Compare commits

..

433 Commits

Author SHA1 Message Date
ebcd14f8e9 docs(changelog): update change log to rc.5
Closes #10599
2016-08-09 10:34:07 -07:00
b65f66feff feat(i18n): switch to sha1 for message fingerprinting 2016-08-09 09:52:11 -07:00
dd68ae3ef1 feat(ExtractorMerger): ignore implicit tags in translatable sections 2016-08-09 09:52:11 -07:00
1b04d70626 feat(ExtractorMerger): allow nested implicit tags 2016-08-09 09:52:11 -07:00
01bca41168 fix: allow users to pass in absolute paths to ngc (#10572) 2016-08-09 09:36:37 -07:00
94e1ab33ce chore(release): update package.jsons 2016-08-09 09:33:17 -07:00
0b08dd8674 chore(animations): make sure host-prop animation deprecation is correctly emitted
Closes #10581
2016-08-08 23:39:22 -07:00
b2b47177cd add brandon suggestions 2016-08-09 03:30:25 +02:00
f08257ff4a docs(cheatsheet): update for rc5 2016-08-09 03:06:01 +02:00
d1f4222c83 docs(cheatsheet): add NgModules docs to the cheatsheet 2016-08-08 17:18:50 -07:00
d21331e902 fix(ngUpgrade): to work with @NgModule
We changed the bootstrap order:
1. create NgZone
2. bootstrap ng1 inside NgZone and upgrade ng1 components to ng2 components.
3. bootstrap ng2 with NgZone

Note: Previous footgun behavior was: bootstrap ng2 first to extract NgZone, so that ng1 bootstrap can happen in NgZone. This meant that if ng2 bootstrap eagerly compiled a component which contained ng1 components, then we did not have complete metadata.
2016-08-08 12:50:08 -07:00
37f138e83d test(ngUpgrade): convert the upgrade example to use NgModules
The example worked even before this change - verifying that the fallback/legacy mode works as well.
2016-08-08 12:20:22 -07:00
5dab0bad3c test(NgUpgrade): add support for loading plaground/upgrade example without bundles 2016-08-08 12:20:22 -07:00
85e70a4cde style(ngUpgrade): small cleanup 2016-08-08 12:20:21 -07:00
6b564ecda5 feat(ngUpgrade): add support for NgModules
BREAKING CHANGE: UpgradeAdapter.addProvider are now deprecated in favor of passing in an NgModule into the adapter's constructor

Before:

```
let upgradeAdapter = new UpgradeAdapter();
upgradeAdapter.addProviders([myProvidersArray);
```

After:

```
@NgModule({
  providers: myProvidersArray
})
class MyModule {}

let upgradeAdapter = new UpgradeAdapter(MyModule);
```
2016-08-08 12:17:35 -07:00
d4cceff0ef chore: remove module aware bootstrap API (#10543)
This API was introduced post RC4, but needs to be removed
before RC5 as we have decided against it.
2016-08-08 09:36:09 -07:00
a415613457 fix(router): update dts files 2016-08-08 09:15:59 -07:00
1a41bd1ca4 feature(router): add route.root returning the root of router state 2016-08-08 09:15:59 -07:00
5a99393355 fix(router): route.parent should work for secondary children 2016-08-08 09:15:59 -07:00
afcb3c0035 fix(router): support outlets in non-absolute positions 2016-08-08 09:15:59 -07:00
d2d36c61f3 fix(router): fix matrix params check to handle 'special' objects 2016-08-08 09:15:59 -07:00
0bd97ecda2 feat(http): add options method to Http (#10540)
Add options method to the Http object, which could be useful when using self-describing RESTful APIs.

This closes #10500, closes #7918
2016-08-08 09:15:13 -07:00
46bbcefb36 fix(linker): prevent pollution of empty embeddedView context (#10548)
Fixes #10045
2016-08-08 09:11:35 -07:00
74b57dfa7d refactor(i18n): remove circular dep 2016-08-05 13:39:54 -07:00
8c9c0986e9 refatcor(digestMessage): takes a i18n.Message 2016-08-05 13:39:54 -07:00
4028fcaa51 refactor(i18n): Drop html.Message and create i18n.Message right away 2016-08-05 13:39:54 -07:00
7a8ef1eae5 feat(i18n): merge translations 2016-08-05 13:39:54 -07:00
e811a5d97f refactor(i18n): misc updates 2016-08-05 13:39:54 -07:00
df44e3e425 fix(i18n extractor): array manipulation 2016-08-05 13:39:54 -07:00
cdb1a237e5 refactor(compiler): html_parser -> ml_parser 2016-08-05 13:39:54 -07:00
fcafdff10b feat(forms): allow both patching and strict setting of values (#10537) 2016-08-05 13:35:17 -07:00
c586656d43 fix(router): fix type definition 2016-08-05 13:12:21 -07:00
3a307c2794 fix(router): absolute redirects should work with lazy loading 2016-08-05 13:12:21 -07:00
4f17dbc721 fix(router): add segmentPath to the link DSL 2016-08-05 13:12:21 -07:00
99989f5d3f chore(facade): remove most facade/async functions 2016-08-05 12:26:28 -07:00
6baf3baedd chore(playground): clang-format 2016-08-05 12:26:28 -07:00
0d1f3c3b07 fix: support trailing slash in basePath (#10533) 2016-08-05 11:11:24 -07:00
83e2d3d1cb refactor(RegExpWrapper): remove the facade (#10512) 2016-08-05 09:50:49 -07:00
b4613ab2d2 fix(ExpressionParser): undefined is undefined (was null) 2016-08-05 09:45:13 -07:00
0ca05eee45 feat(ExpressionParser): add support for this 2016-08-05 09:45:13 -07:00
26c9e1dc70 refactor(NgFor spec): code cleanup 2016-08-05 09:45:13 -07:00
797cb5ae7b refactor(NgStyleSpec): simplify NgStyle tests (#10519) 2016-08-05 09:28:08 -07:00
63b82cd730 feat(router): Allow navigation without updating the URL (#9608) 2016-08-04 11:46:09 -07:00
2b704f0586 fix(linker/compiler): rename const to avoid duplicate declaration (#10457)
Currently in the `linker/compiler.ts` file, the **same identifier** is used in **two declarations**:
```typescript
export type CompilerOptions = { … }
…
export const CompilerOptions = new OpaqueToken('compilerOptions');
```
This breaks the API doc generation. I’m surprised that this was not flagged by the tsc.

The duplicate declaration was introduced in 46b212706b.
2016-08-04 11:31:58 -07:00
ce5ba80792 refactor(NgTemplateOutlet): simplify implementation (#10492) 2016-08-04 11:28:36 -07:00
8b18ef4ba2 feat(NgStyle): add support for the style.unit notation (#10496)
Closes #10326
2016-08-04 11:00:43 -07:00
cd18de7a21 refactor(compiler): use Object.keys instead of Object.getOwnPropertyNames (#10498) 2016-08-04 10:35:41 -07:00
fd19671c07 chore(benchpress): clang-format and lint 2016-08-04 10:08:37 -07:00
3fcd6fd93f chore(benchpress): make benchpress compile
Also adds compiling benchpress to the build scripts to verify that.
2016-08-04 10:08:37 -07:00
c8d53d71a3 fix(ngc): gather metadata for OpaqueToken
Fixes #10482
2016-08-04 10:05:25 -07:00
790362e243 fix: put all ngc files into a single directory (#10486)
Prior to this change `ngc` would place generated files which refer
to components in the node_modules into the node_module. This is an
issue. Now all of the files are forced into a single directory
as specified in `tsconfig.json` by the `genDir` option.

see: https://docs.google.com/document/d/1OgP1RIpZ-lWUc4113J3w13HTDcW-1-0o7TuGz0tGx0g
2016-08-03 21:34:03 -07:00
2eda7a5293 fix(router): provideRouter should use provideRoutes (#10488) 2016-08-03 19:35:12 -07:00
9925aa89dc fix(compiler): Report references to non-exported symbols.
Includes fixes to places now reported as errors.

Part of #8310
2016-08-03 15:42:38 -07:00
6195a45ae2 fix(forms): export AbstractFormGroupDirective
Because
- `Form` is **exported** -- see line 30/31 of
`modules/@angular/forms/src/forms.ts`: i.e., <br>`export {Form} from
'./directives/form_interface'`; and
- Methods of `Form`, which are public, have an
`AbstractFormGroupDirective` parameter;
e.g.,<br>`Form.getFormGroup(dir: AbstractFormGroupDirective):
FormGroup`.

Then it makes sense for `AbstractFormGroupDirective` to be
public/exported too. In any case, if it isn't exported then the **API
docs for `Form` don't get generated properly.**
2016-08-03 15:33:29 -07:00
422d380b3e feat(router): add queryParams and fragment to every activated route 2016-08-03 15:30:03 -07:00
550ab31bd0 feat(router): add parent, children, firstChild to ActivatedRoute 2016-08-03 15:30:03 -07:00
5fceb21549 refactor(router): remove dead code 2016-08-03 15:30:03 -07:00
29caa37943 feat(router): support sibling modules providing routes 2016-08-02 13:31:15 -07:00
8efbcc996a fix(compiler): allow to use pipes inside of *ngIf (#10452)
Fixes #9746
2016-08-02 12:19:34 -07:00
91c64d2b8d fix: missing export for validators 2016-08-02 12:12:15 -07:00
82e7ecd611 fix(compiler): StaticReflect now resolves re-exported symbols (#10453)
Fixes: #10451
2016-08-02 11:45:14 -07:00
3d53b33391 chore: update public api and integrate minor review comments 2016-08-02 11:23:26 -07:00
34624b2db2 refactor(core): deprecate old methods on ApplicationRef
BREAKING CHANGE:
- `ApplicationRef.run` is deprecated. Use `NgZone.run` directly
- `ApplicationRef.injector` is deprecated. Inject an `Injector` or
  use `NgModuleRef.injector` instead
- `ApplicationRef.zone` is deprecated. Inject `NgZone` instead.
2016-08-02 11:23:26 -07:00
1ab5eb0844 refactor(core): don’t use zone.run in ApplicationRef.bootstrap.
`ApplicationRef.bootstrap` is supposed to be run inside of `ngDoBootstrap` method
of the module that is bootstrapped, and that method already runs inside of the
zone.
2016-08-02 11:23:26 -07:00
630028350a refactor(core): Introduce AppInitStatus
This class allows any provider to know and wait for the initialization of the
application. This functionality previously was tied to `ApplicationRef`.

BREAKING CHANGE:
- `ApplicationRef.waitForAsyncInitializers` is deprecated. Use 
  `AppInitStatus.donePromise` / `AppInitStatus.done` instead.
2016-08-02 11:23:26 -07:00
7e4fd7d7da refactor(core): introduce @NgModule.bootstrap and ngDoBootstrap method
If a `@NgModule` has a `bootstrap` property, `PlatformRef.bootstrapModule` /
`PlatformRef.bootstrapModuleFactory` will automatically bootstrap the components
listed in there.
If such a property does not exist, `PlatformRef.bootstrapModule` /
`PlatformRef.bootstrapModuleFactory` will try to call the method `ngDoBootstrap(appRef: ApplicationRef)` on the module class.
Otherwise an error is reported.
2016-08-02 11:23:26 -07:00
af2e80e068 refactor(core): introduce APP_BOOTSTRAP_LISTENER multi provider
Using the `registerBootstrapListener` easily lead to race condition
and needed dependencies on `ApplicationRef`.

BREAKING CHANGE:
- `ApplicationRef.registerBootstrapListener` is deprecated. Provide a multi
  provider for the new token `APP_BOOTSTRAP_LISTENER` instead.
2016-08-02 11:23:26 -07:00
8e6091de6c refactor(core): use ngOnDestroy in providers
Note about the addition of `beforeEach(fakeAsync(inject(…))))` in some tests:
`ApplicationRef` is now using `ngOnDestroy` and there is eager,
including all of its dependencies which contain `NgZone`.
The additional `fakeAsync` in `beforeEach` ensures that `NgZone`
uses the fake async zone as parent, and not the root zone.

BREAKING CHANGE (via deprecations):
- `ApplicationRef.dispose` is deprecated. Destroy the module that was
   created during bootstrap instead by calling `NgModuleRef.destroy`.
- `AplicationRef.registerDisposeListener` is deprecated.
   Use the `ngOnDestroy` lifecycle hook for providers or
   `NgModuleRef.onDestroy` instead.
- `disposePlatform` is deprecated. Use `destroyPlatform` instead.
- `PlatformRef.dipose()` is deprecated. Use `PlatformRef.destroy()`
   instead.
- `PlatformRef.registerDisposeListener` is deprecated. Use
  `PlatformRef.onDestroy` instead.
- `PlaformRef.diposed` is deprecated. Use `PlatformRef.destroyed`
  instead.
2016-08-02 11:23:26 -07:00
ecdaded25f feat(core): introduce NgModuleRef.destroy and call ngOnDestroy on all providers 2016-08-02 11:23:26 -07:00
c161ed415d feat(core): support ngOnDestroy on providers of a directive.
Such providers also become eager as they will be instantiated
anyways on destruction.
2016-08-02 11:23:26 -07:00
ff3b71f7b3 refactor(core): collect lifecycle hooks for all injectable classes 2016-08-02 11:23:26 -07:00
16cc9b46aa fix(fake_async): share zone between beforeEach and it
This is needed for the case if a `beforeEach` instantiates
`NgZone`and the `it` uses
`TestComponentBuilder.createFakeAsync`.

Otherwise the `NgZone` will use the root zone as parent,
and `TestComponentBuilder.createFakeAsync` will always return
undefined as `tick` does not forward promises created
under the zone of `NgZone`.
2016-08-02 11:23:26 -07:00
3ce11ed58c docs(pipes): update I18nSelectPipe API documentation (#10449) 2016-08-02 10:59:07 -07:00
7db75fa361 test: reactivate some of the disabled tests in Edge (#10450) 2016-08-02 10:58:03 -07:00
d6d4568830 fix(forms): allow arrays as parents (#10440)
Closes #10432
2016-08-02 09:40:42 -07:00
a55d796c4b fix: Better error message in case of unknown property binding 2016-08-02 09:28:04 -07:00
73f02c7861 fix: throw useful error on missing platform module. 2016-08-02 09:28:04 -07:00
8c8754e573 chore: add browserNoRouter test running mode 2016-08-02 09:28:04 -07:00
c977a906b3 docs(cheatsheet): add moduleId (#10095) 2016-08-02 07:34:04 -07:00
e0eea6c2f4 feat(forms): add invalid prop to abstract controls (#10439) 2016-08-01 18:41:25 -07:00
3e377f520e fix(router): make an outlet to unregister itself when it is removed from the dom 2016-08-01 16:56:38 -07:00
8dc82a0080 fix(router): fix offline compilation by exporting provideLocationStrategy 2016-08-01 16:23:28 -07:00
4624a35845 docs(router): fixes api docs 2016-08-01 16:23:28 -07:00
8d4499959a feat(forms): add get method for easy access to child controls (#10428) 2016-08-01 14:22:50 -07:00
2dfc9c653b refactor: dart 2016-08-01 11:34:51 -07:00
106db0aba8 refactor: IS_DART === false 2016-08-01 11:34:51 -07:00
28c4852cd6 refactor: remove ts2dart annotations 2016-08-01 11:34:51 -07:00
13c8211065 fix: String.split(str, n) stops after n separator (#10408) 2016-08-01 11:33:35 -07:00
e73d0511cf fix(TemplateParser): report empty expression (#10391)
fixes #3754
2016-08-01 11:24:49 -07:00
e18626b7a2 fix(core): ensure ngFor only inserts/moves/removes elements when necessary (#10287)
Closes #9960
Closes #7239
Closes #9672
Closes #9454
Closes #10287
2016-08-01 11:09:52 -07:00
4df7b1cfbc chore: fixes some issues that happen with closure compiler. (#10392) 2016-08-01 09:47:49 -07:00
f9573ece41 ci(browser providers): update browsers in SL and BS (#10425) 2016-08-01 08:00:12 -07:00
93ade740e2 fix(router): configure DI correctly when using the old provideRouter function 2016-08-01 02:35:41 -07:00
a46437c57d refactor(core): fix bootstrapModule regarding zones and initializers (#10383)
This makes `bootstrapModuleFactory` wait for promises
returned by `APP_INITIALIZER`s, also making `bootstrapModuleFactory` async.
I.e. now `bootstrapModule` and `bootstrapModuleFactory` behave in the
same way.

This ensures that all code from module instantiation, to creating
`ApplicationRef`s as well as calling `APP_INITIALIZERS` is run
in the Angular zone.

This also moves the invocation of the initializers from the `ApplicationRef`
constructor into the `bootstrapModuleFactory` call, allowing initializers
to get a hold of `ApplicationRef` (see #9101).

Fixes #9101
Fixes #10363
Fixes #10205
2016-08-01 02:12:59 -07:00
633c7d1ebe refactor(core): cleanup unused NgZone factory
This factory was only used when using `coreBootstrap` / `coreLoadAndBoostrap`
which is not supported any more.
2016-08-01 02:12:59 -07:00
251953218c fix(http): URLSearchParams.clone propagate the QueryEncoder (#9900) 2016-07-30 19:01:20 -07:00
0d6cc17252 fix(UrlParser): stop setting default value 'true' (#10399) 2016-07-30 14:34:03 -07:00
c8989c900f chore(github): remove reference to Dart in the issue template (#10388) 2016-07-30 00:22:04 -07:00
6134320f16 refactor(http): rewrite for readable & efficient. 2016-07-29 21:30:28 -07:00
7f647822bd fix(http): headers should be case-insensitive.
fixes #9452

spec at https://tools.ietf.org/html/rfc2616
2016-07-29 21:30:15 -07:00
e34a04d2ad feat(xmb/xtb): support dtd 2016-07-29 14:18:34 -07:00
44093905e2 refactor(test): refine types 2016-07-29 13:53:13 -07:00
3e2900f74b refactor(i18n): move code around 2016-07-29 13:40:58 -07:00
11fd2eccec refactor: fix merge glitches 2016-07-29 13:40:58 -07:00
0eee1d5de3 feat(i18n): xtb serializer 2016-07-29 13:40:58 -07:00
1b77604ee2 refactor(compiler): re-arrange files 2016-07-29 13:40:58 -07:00
cc5cfe87c3 feat(i18n): xmb serializer 2016-07-29 13:40:58 -07:00
48f230a951 feat(I18nAst): introduce an intermediate AST 2016-07-29 13:40:58 -07:00
2be50bdbb0 refactor(i18n): message extractor
fixes #8802
2016-07-29 13:40:58 -07:00
f7258ea52a test(HtmlAst): add a serializer 2016-07-29 13:40:58 -07:00
28e8b2faab feat(ICU): extract ICU messages 2016-07-29 13:40:58 -07:00
3c3e9ddb10 feat(router): add a validation to make sure pathMatch is set correctly 2016-07-29 12:27:43 -07:00
5162fb6d52 feat(router): add isActive to router 2016-07-29 12:27:43 -07:00
2fdb39e60a feat(router): activateroute should expose its route config 2016-07-29 12:27:43 -07:00
43c71ae103 fix(platform-browser): IEMobile is badly detected when testing (#10382) 2016-07-29 10:05:12 -07:00
f0bd528d77 test(http): fix Blob creation for Android <= 4.3
Closes #10377
2016-07-29 18:20:09 +02:00
50a024b42f test(http): add Typed Array polyfill for IE9 2016-07-29 18:19:54 +02:00
b48f7bcb8d fix(forms): normalize written value in NumberValueAccessor
Closes #10379
2016-07-29 18:18:30 +02:00
763ca60f5b feat(compiler): Support default parameters in static reflector (#10370)
Closes: #10369
2016-07-29 09:10:45 -07:00
0eca7abdd8 chore: update public api
Closes #10355
2016-07-29 04:47:50 -07:00
d0a95e35af refactor(testing): introduce new testing api to support ng modules
BREAKING CHANGE:
- deprecations:
  * `withProviders`, use `TestBed.withModule` instead
  * `addProviders`, use `TestBed.configureTestingModule` instead
  * `TestComponentBuilder`, use `TestBed.configureTestModule` / `TestBed.override...` / `TestBed.createComponent` instead.

Closes #10354
2016-07-29 04:47:18 -07:00
acc6c8d0b7 feat(compiler): introduce MockDirectiveResolver.setDirective 2016-07-29 04:47:18 -07:00
3dbc66c1ac refactor(core): introduce interfaces for constructor arguments of decorators
For @Directive, @Component, @Pipe, @NgModule
2016-07-29 04:47:18 -07:00
4ad6bcce54 feat(compiler): add MockPipeResolver 2016-07-29 04:47:17 -07:00
0988cc82b0 refactor(core): remove ViewResolver and ViewResolverMock
The methods on `ViewResolverMock` have been merged into `DirectiveResolver`.

BREAKING CHANGE:
- ES5 users can no longer use the `View(…)` function to provide `ViewMetadata`.
  This mirrors the removal of the `@View` decorator a while ago.
2016-07-29 04:47:17 -07:00
20b03bad11 feat(compiler): Added support for conditional expressions. (#10366)
Expression evaluated by the static reflector can now supports
conditional expressions.

Closes: #10365
2016-07-28 17:32:29 -07:00
81d27daf0d fix(router): update dts files 2016-07-28 15:03:19 -07:00
bb8b82b3f5 fix(router): relax type defintion of Route to improve dev ergonomics 2016-07-28 15:03:19 -07:00
915a6666f8 fix(core): fix offline detection in ng_module_factory_loader 2016-07-28 15:03:19 -07:00
72da547d6a fix(router): updates router module to be offline-compilation friendly 2016-07-28 15:03:19 -07:00
7c76a75452 fix(forms): update dirty before emitting value change (#10362)
Closes #5328
2016-07-28 14:25:33 -07:00
a32c4ad2f0 fix(compiler): auto declare entryComponents recursively
Closes #10348
2016-07-28 12:03:34 -07:00
fb3608aa5d fix(compiler): report better error messages for host bindings
Closes #10346
2016-07-28 11:21:50 -07:00
0a46f37444 fix(metadata): fix typechecking with typescript@next 2016-07-28 11:17:53 -07:00
9b39e499ac fix(core): support components without a selector (#10331)
Components without a selector now get the selector `ng-component`.
Directives without a selector will throw an error message.

Closes #3464
Closes #10216
2016-07-28 10:39:10 -07:00
a67cc8229d chore: move injector to being non-internal but private (#10339)
* chore: move injector to being non-internal but private

* Add the new non-internal method to the public API.
2016-07-28 10:38:29 -07:00
b58e9ea775 feat(compiler): Added support for references to static fields. (#10334)
Closes: #10332
2016-07-27 19:26:59 -07:00
422effdd18 refactor(http): use ngModules for http (#10329) 2016-07-27 13:09:05 -07:00
3b690b68a6 fix(testing): Fix error message in test bed
The API name in the error message was wrong
2016-07-27 12:03:27 -07:00
43349dd373 fix(forms): improve ngModel error messages (#10314) 2016-07-27 10:59:40 -07:00
e44e8668ea fix(core): only warn and auto declare undeclared entryComponents.
This is needed to support existing applications.
After final these warnings will become errors.

Closes #10316
2016-07-27 10:56:12 -07:00
69e72c0786 chore: remove browserDynamicTestingPlatform as it is deprecated and was not part of rc.4
Closes #10319
2016-07-27 10:52:47 -07:00
553344739c fix(core): allow module providers to overwrite providers from ModuleWithProviders
Fixes #10313
Closes #10317
2016-07-27 10:51:58 -07:00
367f0fd142 fix(static_reflector): report methods with decorators in propMetadata as well
This was the behavior of our regular reflector as well, although the
method name does not imply this.

Fixes #10308
Closes #10318
2016-07-27 10:50:58 -07:00
58d9e7fc5a feat(facade): add support for all thenables (#10278)
All objects that have a then function will be considered Promises
2016-07-27 10:37:48 -07:00
9d9e9c6ff1 refactor(router): take advantage of the new way of configuring modules 2016-07-27 10:24:29 -07:00
ba88db5141 fix(ngClass): do not deconstruct classes on element removal (#10303)
Prior to this fix [ngClass] would remove all dynamic classes
when destroyed. It's essential that classes are persisted such
that remove-based animations will still be stylistically correct.
This patch fixes this issue.

Closes #10008
Closes #10303
2016-07-26 15:20:27 -07:00
62e7c0f464 feat(router): implement canLoad 2016-07-26 14:39:02 -07:00
fc83bbbe98 fix(compiler): treat custom elements as unknown elements by default
Closes #10300
2016-07-26 12:31:22 -07:00
482c019199 feat(security): only warn when actually sanitizing HTML. (#10272)
Previously, Angular would warn users when simply re-encoding text
outside of the ASCII range. While harmless, the log spam was annoying.

With this change, Angular specifically tracks whether anything was
stripped during sanitization, and only reports a warning if so.

Fixes #10206.
2016-07-26 11:39:09 -07:00
b449467940 feat(compiler): Allow calls to simple static methods (#10289)
Closes: #10266
2016-07-26 10:18:35 -07:00
0aba42ae5b fix(forms): throw error if wrong control container for reactive forms (#10286) 2016-07-26 10:08:46 -07:00
0d1bf8148b fix(animations): ensure animation detection doesn't rely on the body node
Closes #10230
Closes #10191
Closes #10273
2016-07-26 09:33:50 -07:00
b42411ba1f chore: update public api
- `precompile` -> `entryComponents`
- introduce `ModuleWithProviders`
- introduce `@NgModule.schema`
- update to bootstrap

Closes #10268
2016-07-26 07:45:40 -07:00
5a21f168d6 refactor(core): change bootstrap of modules and names of platforms
BREAKING CHANGES:
- `browserPlatform`/`browserDynamicPlatform`/... have been deprecated and renamed into `platformBrowser`/`platformBrowserDynamic`/....
- `bootstrapModule` and `bootstrapModuleFactory` have been moved to be members of `PlaformRef`.
  E.g. `platformBrowserDynamic().bootstrapModule(MyModule)`.
2016-07-26 07:28:55 -07:00
00b726f695 refactor(core): introduce NgModule.schemas
This allows Angular to error on unknown properties,
allowing applications that don’t use custom elements
to get better error reporting.

Part of #10043

BREAKING CHANGE:
- By default, Angular will error during parsing
  on unknown properties,
  even if they are on elements with a `-` in their name
  (aka custom elements). If you application is using
  custom elements, fill the new parameter `@NgModule.schemas`
  with the value `[CUSTOM_ELEMENTS_SCHEMA]`.

  E.g. for bootstrap:
  ```
  bootstrap(MyComponent, {schemas: [CUSTOM_ELEMENTS_SCHEMA]});
  ```
2016-07-26 07:04:36 -07:00
f02da4e91a feat(core): introduce ModuleWithProviders.
Modules can now provider helper functions that allow
to import a module together with an array of providers.

Part of #10043
2016-07-26 07:04:36 -07:00
d6b65db9a7 fix(static_reflector): resolve values of functions in the function context 2016-07-26 07:04:36 -07:00
6f4e49ed53 refactor(core): rename precompile into entryComponents.
Part of #10043

BREAKING CHANGE:
- `@Component.precompile` was renamed to `@Component.entryComponents`
  (old property still works but is deprecated)
- `ANALYZE_FOR_PRECOMPILE` was renamed to `ANALYZE_FOR_ENTRY_COMPONENTS` (no deprecations)
2016-07-26 07:04:36 -07:00
46b212706b refactor(core): change module semantics
This contains major changes to the compiler, bootstrap of the platforms
and test environment initialization.

Main part of #10043
Closes #10164

BREAKING CHANGE:
- Semantics and name of `@AppModule` (now `@NgModule`) changed quite a bit.
  This is actually not breaking as `@AppModules` were not part of rc.4.
  We will have detailed docs on `@NgModule` separately.
- `coreLoadAndBootstrap` and `coreBootstrap` can't be used any more (without migration support).
  Use `bootstrapModule` / `bootstrapModuleFactory` instead.
- All Components listed in routes have to be part of the `declarations` of an NgModule.
  Either directly on the bootstrap module / lazy loaded module, or in an NgModule imported by them.
2016-07-26 07:04:10 -07:00
ca16fc29a6 build: fix and document the symlinks scripts for Windows
Closes #10213
2016-07-26 09:52:11 +02:00
9edea0b139 fix(ng upgrade): do not compile ng2 components until after ng1 bootstrap (#10084)
Closes #9407 and angular/protractor#2944
2016-07-25 21:14:35 -07:00
d15a1d64e1 fix(router): make router provides work with cli and offline compilation 2016-07-25 18:04:22 -07:00
c87847974a chore(forms): separate out tests for reactive forms (#10283) 2016-07-25 15:57:51 -07:00
6f68330fa5 feat(router): rename UrlPathWithParams into UrlSegment
BREAKING CHANGE:

UrlPathWithParams => UrlSegment
UrlSegment => UrlSegmentGroup
2016-07-25 12:15:07 -07:00
2b63330a36 fix(router): handle when both primary and secondary are empty-path and primary has a child 2016-07-22 18:51:35 -07:00
06e4ca4bb3 fix(router): advance query params and fragment after advanced routes 2016-07-22 18:51:35 -07:00
43437c175a fix(router): handle url fragments when no url segments present 2016-07-22 18:51:35 -07:00
8d90a5a4cf fix(router): router link active should take all descendants into account 2016-07-22 18:51:35 -07:00
93a4ca652a refactor(router): renames PRIMARY_OUTLET into primary 2016-07-22 18:51:35 -07:00
41178367d1 feat(HtmlLexer): better hint on unclosed ICU message errors
fixes #10227
2016-07-22 17:27:15 -07:00
54f2edbb90 refactor(Lexer): code cleanup 2016-07-22 16:50:54 -07:00
b652a7fc9f chore: remove obsolete files (#10240) 2016-07-22 16:18:31 -07:00
e34eb4520f fix(testing): ComponentFixture - Avoid extra scheduleMicrotask (#10223)
Don't schedule microtask to check for pending macrotasks when no one is waiting for a whenStable().
2016-07-22 16:07:11 -07:00
190bcc89c1 refactor(EventEmitter): optional emits (#10058)
the Subject#next is optional
2016-07-22 10:19:57 -07:00
64fc4648b7 fix(testing): correctly import NgMatchers (#10077)
Some test cases incorrectly rely on the side effect of other test cases
importing `NgMatchers`. This commit fixes this by making `expect` in
`core/testing_internal` properly typed.
2016-07-22 09:20:51 -07:00
bdb59129d0 feat(http): add content-type override support for http request (#10211) 2016-07-22 08:37:32 -07:00
d455942389 fix(CurrencyPipe): use default Intl formatting options when none provided
fixes #10189
2016-07-22 08:21:31 -07:00
cdb3678fe3 chore(tools): remove unused files 2016-07-22 08:20:46 -07:00
e73ac1e992 chore(Dart): remove obsolete files, update the docs 2016-07-22 08:20:46 -07:00
51f3d22e4f feat(security): trust resource URLs as URLs. (#10220)
Resource URLs are strictly "more" trustworthy than plain URLs, so trusting them maintains the same level of security while avoiding to break people when we downgrade a resource URL context to a plain URL context.
2016-07-21 17:44:59 -07:00
00aa7a76b6 chore(tests): enable lint, make it green. (#10224) 2016-07-21 17:12:00 -07:00
27b87ef535 fix(router): throw when cannot parse a url 2016-07-21 16:14:55 -07:00
44709e0dca fix(router): handle urls with only secondary top-level segments 2016-07-21 16:14:44 -07:00
31a7709ece test: execute router tests on ./test.sh browser (#10053) 2016-07-21 16:12:40 -07:00
a441b5b8fe feat(security): categorize <track src> as a regular URL.
After security review, it turns out we were too paranoid about <track src>. Its content is not actually active or dangerous.

Fixes #10089.
2016-07-21 13:53:35 -07:00
76b8a49bfb feat(http): add support for blob as a response type (#10190) 2016-07-21 13:44:38 -07:00
db54a84d14 fix(router): routerLinkActive should only set classes after the router has successfully navigated 2016-07-20 17:51:21 -07:00
eb6ff65af7 refactor(router): makes an error message clearer 2016-07-20 14:47:51 -07:00
23ee29b6a2 fix(router): navigation should not preserve query params and fragment by default
BREAKING CHANGE

Previously both imperative (router.navigate) and declarative (routerLink) navigations
would preserve the current query params and fragment. This behavior turned out to
be confusing. This commit changes it.

Now, neither is preserved by default. To preserve them, you need to do the following:

router.naviage("newUrl", {preserveQueryParams: true, preserveFragment: true})

<a routerLink="newUrl" preserveQueryParams preserveFragment></a>
2016-07-20 14:30:04 -07:00
73a69895d8 cleanup(router): removes unnecessary files from tsconfig 2016-07-20 11:44:07 -07:00
2799e7a3ca refactor(router): rename RouterTestModule into RouterTestingModule 2016-07-20 11:39:31 -07:00
b43f95435b fix(testing): add an explicit doAsyncPrecompilation step (#10015)
This removes the magic from the `inject` test helper that would inspect
the current zone and would only work with our `async` test helper.
Now, `inject` is always synchronous, and if you are using a module
that requires async precompilation, you're required to call
`doAsyncPrecompilation` in your tests.

This is part of the breaking changes introduced with the swap
to each test having an AppModule.

Closes #9975
Closes #9593

BREAKING CHANGE:

`TestInjector` is now renamed to `TestBed`

Before:

```js
import {TestInjector, getTestInjector} from '@angular/core/testing';
```

After:

```js
import {TestBed, getTestBed} from '@angular/core/testing';
```
2016-07-20 10:51:21 -07:00
450f61d384 docs(router): fix provider token (#10177) 2016-07-20 07:27:09 -07:00
f3dd91e1d7 feat(NumberPipe): add string support (#10163)
fixes #10159
2016-07-19 11:27:06 -07:00
979946c062 fix(testing): Add platform directives to the shim that keeps setBaseTestProviders running (#10154)
Due to daa9da4047,
tests using the setBaseTestProviders stopped working with ambient directives such as
`ngIf`. Add them back in to keep the shim working.
2016-07-19 08:59:14 -07:00
51e661eb74 fix(router): export navigation extras 2016-07-18 17:42:04 -07:00
921a17960c fix(router): lazy loaded components should use loaded injector 2016-07-18 17:42:04 -07:00
7a4f6621ed fix(router): handle lastPathIndex of empty-path routes 2016-07-18 17:42:04 -07:00
83bc5c97ef fix(http): convert objects passed to requests into a string (#10124)
This remove a breaking change introduced with commit #e7a8e2757b06d572f614f53b648d2fd75df370d2 where json objects passed to  requests were not converted into string.

BREAKING CHANGE:

The behavior in this commit is the same as before PR 7260 : the objects sent with the request are converted to a string, therefore there is no need for the user to take care of the serialization.

Fixes #10073
2016-07-18 14:20:03 -07:00
3f08efa35d fix(KeyValueDiffer): check for changes
fixes #9115
2016-07-18 11:30:07 -07:00
0914dc35e8 refactor(Differ): cleanup 2016-07-18 11:30:07 -07:00
b6746cce9c refactor(decorators): cleanup 2016-07-18 10:38:59 -07:00
8cd97c2054 refactor(NgFor): cleanup 2016-07-18 10:38:59 -07:00
32d8cde9c6 docs(NgSwitch): fix typo ngSwitch to NgSwitch (#10143) 2016-07-18 10:24:55 -07:00
1803ed2512 fix(router): fix rollup config to properly set up rxjs 2016-07-15 16:27:54 -07:00
f08060b0b0 fix(router): back button does not work in IE11 and Safari 2016-07-15 14:59:59 -07:00
b77a4a40a4 fix(router): expose initalNavigation and dispose so they can be used with webworkers 2016-07-14 17:29:01 -07:00
e1109d52e1 docs(router): update the docs of LocationPathStrategy 2016-07-14 15:00:50 -07:00
0668ba50e8 fix(router): freeze params and queryParams to prevent common source of bugs 2016-07-14 13:33:05 -07:00
44ff005ce3 doc(developer): updates (#10075) 2016-07-14 08:51:05 -07:00
aa88438b54 feat(Router): add extra validation for when route was passed as Array (#9942) 2016-07-14 08:28:31 -07:00
85be729c70 fix(router): lazily-loaded modules should use loaded injectors instead of the root one 2016-07-13 18:25:30 -07:00
a5dc5705a3 feat(router): guards and data resolvers can now return promises 2016-07-13 18:25:30 -07:00
9e3d13f61f feat(router): add support for canActivateChild 2016-07-13 18:25:30 -07:00
961c9d48ae fix(compiler): Query expression lambdas should have dynamic type
Fixes: #9875
2016-07-13 15:41:30 -07:00
9229bbbc80 Revert "fix(compiler): Generates function expressions as returning any (#9980)"
This reverts commit eb5763c23f.
2016-07-13 15:41:30 -07:00
34feecf60e fix(forms): improve no value accessor error message (#10051) 2016-07-13 14:13:02 -07:00
4c762a6be3 chore(lint): enable lint check for duplicate vars 2016-07-13 12:33:39 -07:00
0426325ef7 fix(router): merge SystemJsAppModuleFactoryLoader and SystemJsAllModuleLoader 2016-07-13 11:16:46 -07:00
0b54e3cf0a fix(router): do not fire events on 'duplicate' location events 2016-07-13 11:16:46 -07:00
5cf58971f1 fix(router): update current state and url before activating components 2016-07-13 11:16:46 -07:00
6518ff88b2 fix(compiler): No longer writes 0 length files outside of genDir (#10023)
Fixes: #9984
2016-07-13 11:15:23 -07:00
42b0c1d8a2 refactor: misc cleanup (#10046) 2016-07-13 11:01:32 -07:00
4a965052f9 fix(platform-browser): remove testing_e2e target (#10029)
The testing_e2e util does not belong in platform-browser and was never
intended to be a public API. Move it out of that whole tree.

BREAKING CHANGE:

The following API was never intended to be public and is removed:

```js
import {verifyNoBrowserErrors} from '@angular/platform-browser/testing_e2e';
```

Consider using Protractor's console plugin: https://github.com/angular/protractor-console-plugin
2016-07-13 10:10:02 -07:00
5725c5925c docs(ExceptionHandler): Update code example in comment block to correct syntax error. (#10032) 2016-07-13 07:28:08 -07:00
a46291b67c docs(router) Added @Injectable decorators to Router API examples (#10033) 2016-07-13 07:27:32 -07:00
4ac76ca281 docs(router): fix syntax in code example of comment block (#10026) 2016-07-13 07:26:26 -07:00
e7a8e2757b refactor(http): share 'body' logic between Request and Response 2016-07-12 18:01:06 -07:00
1266460386 feat(http): add support for ArrayBuffer
Add the buffer option to store response in ArrayBuffer
Improve the interface to get back response independently of the buffer type
2016-07-12 18:01:06 -07:00
0ccb6e0dfc refactor: code cleanup 2016-07-12 16:57:39 -07:00
3050ae155c feat(ICU): enable ICU extraction even when when in is not used
BREAKING CHANGES:

"{" is used a a delimiter for ICU messages then it could not be used in text nodes.
"{" should be escaped as "{{ '{' }}"

Before:

    <span>some { valid } text</span>

After:

    <span>some { invalid } text<span> <!-- throw parse error -->
    <span>some {{ '{' }} valid } text</span>
2016-07-12 16:57:39 -07:00
402fd934d0 refactor: code cleanup 2016-07-12 15:26:03 -07:00
6c86e8d80a test(HtmlLexer): Add test for "{" and "{{" escaping 2016-07-12 15:26:03 -07:00
60e6f91a53 refactor(HmtlLexer): cleanup 2016-07-12 15:26:03 -07:00
e676fded21 refactor(Lexer): add types
relates to #9100
2016-07-12 15:26:03 -07:00
25e070dd65 fix(HtmlParser): correctly propagate the interpolation config across layers 2016-07-12 15:26:03 -07:00
da8eb9f8b8 feat(forms): add ability to reset forms (#9974)
Closes #4914
Closes #4933
2016-07-12 15:02:25 -07:00
806a25413c feat(animations): allow animation integration support into host params
Closes #9044
Closes #9933
2016-07-12 14:55:36 -07:00
5af1e891cd fix(animations): throw errors when duplicate component trigger names are registered 2016-07-12 14:55:31 -07:00
79eda30f0f refactor(animations): collect parser / lookup errors in the same place 2016-07-12 14:55:27 -07:00
6d02d2f107 fix(SyncAsyncResult): fix default async value (#10013) 2016-07-12 13:55:06 -07:00
ded518d47f feat(router): update routerLink DSL to handle aux routes 2016-07-12 11:44:55 -07:00
27436270fd fix(Compiler): Catch exceptions in the logging of binding update
fixes #9994
2016-07-12 11:21:32 -07:00
b4ea0b1601 test(datePipe): remove hardcoded timezone (#10007)
Closes #9964
2016-07-12 11:13:26 -07:00
7b31178546 fix(platform-browser-dynamic): Add @Injectable() annotation to XHRImpl.
Otherwise Closure compiled code will complain that the class is missing the annootation.
2016-07-11 23:27:35 -07:00
2ff83324af fix(core): Don't use ES6 spread operator when undefined is allowed.
Workaround a closure bug where it doesn't produce the right code ES6 operator when the array value can be undefined.
2016-07-11 23:14:25 -07:00
4ef86891a3 fix(compiler): Ignore references to declared modules and unneeded types (#9776)
Fixes: #9670
2016-07-11 17:26:35 -07:00
eb5763c23f fix(compiler): Generates function expressions as returning any (#9980)
Function expressions are used in an expression context so untyped
function expressions should have any as the result type.

Fixes: #9877
2016-07-11 17:19:38 -07:00
d1a3e3aff1 fix(DirectiveResolver): throw on duplicate Input & Output names 2016-07-11 16:38:06 -07:00
93d0a01d3d refactor: code cleanup 2016-07-11 16:22:23 -07:00
9af2d8b810 fix(testing): remove deprecated testing APIs (#9923)
See https://github.com/angular/angular/blob/master/CHANGELOG.md for
prior deprecation and how to update.
2016-07-11 16:04:32 -07:00
94dc632a6d fix(NgStyle): remove duplicate input declaration (#9978)
fixes #9977
2016-07-11 15:09:04 -07:00
29231877e6 fix(testing): reintroduce and deprecate setBaseTestProviders (#9905)
This change reverts the removal of setBaseTestProviders that was
introduced in 8d746e3f67.

Instead, setBaseTestProviders and the providers provided from
`@angular/platform-browser-dynamic/testing` and `@angular/server/testing`
will still work for the next release, but are deprecated.

See 8d746e3f67 for how to upgrade.
2016-07-11 14:01:11 -07:00
e68252a79b fix(forms): re-enable form provider functions for easier migration (#9972) 2016-07-11 13:23:38 -07:00
4ec2a30942 fix(compiler): Fixed ?. operator to short-circut execution (#9965)
Fixes: #9850
2016-07-11 12:58:56 -07:00
e6b24437a9 fix(compiler): Collector collects enum values. (#9967)
Fixes: #9928
2016-07-11 11:50:33 -07:00
a05f7b2d76 refactor(animations): move MockAnimationPlayer back into core (#9966)
Closes #9966
2016-07-11 10:55:47 -07:00
61e18434d3 refactor(router): not use reserved words as variable (#9941) 2016-07-11 10:53:29 -07:00
57473e72ec refactor: code cleanup (#9931) 2016-07-09 10:12:39 -07:00
c3bdd504d0 fix(animations): ensure all child elements are rendered before running animations
Closes #9402
Closes #9775
Closes #9887
2016-07-08 18:18:46 -07:00
daa9da4047 refactor(core): deprecate coreBootstrap, PLATFORM_PIPES/DIRECTIVES providers and ComponentResolver
BREAKING CHANGE (deprecations)

- Instead of `coreBootstrap`, create an `@AppModule` and use `bootstrapModule`.
- Instead of `coreLoadAndBootstarp`, create an `@AppModule` and use `bootstrapModuleFactory`.
- Instead of `bootstrapWorkerApp`, create an `@AppModule` that includes the `WorkerAppModule` and use `bootstrapModule` with the `workerAppPlatform()`.
- Instead of `bootstrapWorkerUi`, create an @AppModule that includes the `WorkerUiModule` and use `bootstrapModule` with the `workerUiPlatform()` instead.
- Instead of `serverBootstrap`, create an @AppModule and use `bootstrapModule` with the `serverDynamicPlatform()` instead.
- Instead of `PLATFORM_PIPES` and `PLATFORM_DIRECTIVES`, provide platform directives/pipes via an `@AppModule`.
- Instead of `ComponentResolver`:
  - use `ComponentFactoryResolver` together with `@AppModule.precompile`/`@Component.precompile` or `ANALYZE_FOR_PRECOMPILE` provider for dynamic component creation.
  - use `AppModuleFactoryLoader` for lazy loading.
- Instead of `SystemJsComponentResolver`, create an `@AppModule` and use `SystemJsAppModuleLoader`.
- Instead of `SystemJsCmpFactoryResolver`, create an `@AppModule` and use `SystemJsAppModuleFactoryLoader`

Closes #9726
2016-07-08 15:31:50 -07:00
245b0910ed feat(router): add activate and deactivate events to RouterOutlet 2016-07-08 15:01:52 -07:00
a77db44129 feat(router): empty-path routes should inherit matrix params 2016-07-08 14:48:59 -07:00
34b3c534e7 fix(router): disallow root segments with matrix params 2016-07-08 14:47:55 -07:00
fa47890032 refactor(core): clean up platform bootstrap and initTestEnvironment
- Introduces `CompilerFactory` which can be part of a `PlatformRef`.
- Introduces `WorkerAppModule`, `WorkerUiModule`, `ServerModule`
- Introduces `serverDynamicPlatform` for applications using runtime compilation
  on the server.
- Changes browser bootstrap for runtime and offline compilation (see below for an example).
  * introduces `bootstrapModule` and `bootstrapModuleFactory` in `@angular/core`
  * introduces new `browserDynamicPlatform` in `@angular/platform-browser-dynamic
- Changes `initTestEnvironment` (which used to be `setBaseTestProviders`) to not take a compiler factory any more (see below for an example).

BREAKING CHANGE:

## Migration from `setBaseTestProviders` to `initTestEnvironment`:

- For the browser platform:
  BEFORE:
  ```
  import {setBaseTestProviders} from ‘@angular/core/testing’;
  import {TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
      TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS} from ‘@angular/platform-browser-dynamic/testing’;

  setBaseTestProviders(TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
      TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS);
  ```

  AFTER:
  ```
  import {initTestEnvironment} from ‘@angular/core/testing’;
  import {browserDynamicTestPlatform,
      BrowserDynamicTestModule} from ‘@angular/platform-browser-dynamic/testing’;

  initTestEnvironment(
      BrowserDynamicTestModule,
      browserDynamicTestPlatform());

  ```
- For the server platform:
  BEFORE:
  ```
  import {setBaseTestProviders} from ‘@angular/core/testing’;
  import {TEST_SERVER_PLATFORM_PROVIDERS,
      TEST_SERVER_APPLICATION_PROVIDERS} from ‘@angular/platform-server/testing/server’;

  setBaseTestProviders(TEST_SERVER_PLATFORM_PROVIDERS,
      TEST_SERVER_APPLICATION_PROVIDERS);
  ```

  AFTER:
  ```
  import {initTestEnvironment} from ‘@angular/core/testing’;
  import {serverTestPlatform,
      ServerTestModule} from ‘@angular/platform-browser-dynamic/testing’;

  initTestEnvironment(
      ServerTestModule,
      serverTestPlatform());

  ```

## Bootstrap changes
```
@AppModule({
  modules: [BrowserModule],
  precompile: [MainComponent],
  providers: […], // additional providers
  directives: […], // additional platform directives
  pipes: […] // additional platform pipes
})
class MyModule {
  constructor(appRef: ApplicationRef) {
    appRef.bootstrap(MainComponent);
  }
}

// offline compile
import {browserPlatform} from ‘@angular/platform-browser’;
import {bootstrapModuleFactory} from ‘@angular/core’;

bootstrapModuleFactory(MyModuleNgFactory, browserPlatform());

// runtime compile long form
import {browserDynamicPlatform} from ‘@angular/platform-browser-dynamic’;
import {bootstrapModule} from ‘@angular/core’;

bootstrapModule(MyModule, browserDynamicPlatform());
```

Closes #9922
Part of #9726
2016-07-08 13:41:38 -07:00
d84a43c828 fix(TemplateParser): add support for data-template attribute
fixes #9904
2016-07-08 13:07:01 -07:00
9a1babb30c refactor(TemplateParser): cleanup 2016-07-08 13:07:01 -07:00
30a332ee36 feat(forms): updateValue() for form groups and form arrays (#9901)
Closes #9553
2016-07-08 13:04:25 -07:00
426b002897 docs(developer): update building and testing instructions (#9903)
fixes #9683
2016-07-08 12:00:27 -07:00
2de8364de2 feat(ExpressionChangedAfterItHasBeenCheckedException): more meaningful error message
fixes #9882
2016-07-08 10:34:22 -07:00
eacc9e6541 refactor: misc cleanup 2016-07-08 10:34:22 -07:00
749dec7dfb doc(api): fix invalid doc links (#9873)
Errors were reported during API doc generation.
2016-07-07 23:02:35 -07:00
96a9e66616 feat(router): add the ANALYZE_FOR_PRECOMPILE provider to make dev ergonomics better 2016-07-07 18:07:10 -07:00
46e105f3ab fix(router): encode/decode params and path segments 2016-07-07 17:33:42 -07:00
f7a0e9ecb6 fix(router): fix RouterLinKActive to work with RouterLink 2016-07-07 17:33:42 -07:00
93025d1bc6 fix(forms): export form directive arrays for offline compile (#9893) 2016-07-07 17:29:20 -07:00
98d49d4ce3 refactor(core): make lockRunMode a noop and deprecate it.
BREAKING CHANGE:
- `lockRunMode` is deprecated and no more needed.

Closes #9878
2016-07-07 16:16:55 -07:00
1426f680f5 refactor(core): add a deprecation message for using PLATFORM_DIRECTIVES / PLATFORM_PIPES / CompilerConfig / XHR as regular providers in bootstrap.
We still support this via a hack, but should remove this soon.

This also fixes tests for module directives / pipes
as they used directives / pipes that were
already present in the underlying platform.
2016-07-07 16:16:55 -07:00
c7fc51a185 chore(public api): run build.sh before generating the api doc (#9889) 2016-07-07 15:39:53 -07:00
b7e69bc1a1 fix(NgPlural): expression inside cases (#9883)
fixes #9868
2016-07-07 14:47:06 -07:00
72544ba551 feat(router): add RouterTestModule 2016-07-07 14:28:01 -07:00
c43dd5a655 refactor(router): renamed RouterAppModule into RouterModule 2016-07-07 14:28:01 -07:00
7f4954bed6 fix(animations): change trigger binding syntax to function as a property binding []
Animation triggers can now be set via template bindings `[]`

BREAKING CHANGE:

animation trigger expressions within the template that are assigned as
an element attribute (e.g. `@prop`) are deprecated. Please use the
Angular2 property binding syntax (e.g. `[@prop]`) when assigning
properties.

```ts
// this is now deprecated
<div @trigger="expression"></div>

// do this instead
<div [@trigger]="expression"></div>
```
2016-07-07 14:13:06 -07:00
f1fc1dc669 revert: fix(animations): ensure all child elements are rendered before running animations
This reverts commit cbe85a0893.
2016-07-07 14:12:17 -07:00
cbe85a0893 fix(animations): ensure all child elements are rendered before running animations
Closes #9402
Closes #9775
2016-07-07 14:10:04 -07:00
7073cf74fe feat(core): allow to add precompiled tokens via a provider
Introduces the new `ANALYZE_FOR_PRECOMPILE` token. This token can be used to
create a virtual provider that will populate the `precompile` fields of
components and app modules based on its
`useValue`. All components that are referenced in the `useValue`
value (either directly or in a nested array or map) will be added
to the `precompile` property.

closes #9874
related to #9726
2016-07-07 12:16:48 -07:00
9d265b6f61 feat(forms): add modules for forms and deprecatedForms (#9859)
Closes #9732

BREAKING CHANGE:

We have removed the deprecated form directives from the built-in platform directive list, so apps are not required to package forms with their app. This also makes forms friendly to offline compilation.

Instead, we have exposed three modules:

OLD API:
- `DeprecatedFormsModule`

NEW API:
- `FormsModule`
- `ReactiveFormsModule`

If you provide one of these modules, the default forms directives and providers from that module will be available to you app-wide.  Note: You can provide both the `FormsModule` and the `ReactiveFormsModule` together if you like, but they are fully-functional separately.

**Before:**
```ts
import {disableDeprecatedForms, provideForms} from @angular/forms;

bootstrap(App, [
   disableDeprecatedForms(),
   provideForms()
]);
```

**After:**

```ts
import {DeprecatedFormsModule} from @angular/common;

bootstrap(App, {modules: [DeprecatedFormsModule] });
```

-OR-

```ts
import {FormsModule} from @angular/forms;

bootstrap(App, {modules: [FormsModule] });
```

-OR-

```ts
import {ReactiveFormsModule} from @angular/forms;

bootstrap(App, {modules: [ReactiveFormsModule] });
```

You can also choose not to provide any forms module and run your app without forms.

Or you can choose not to provide any forms module *and* provide form directives at will.  This will allow you to use the deprecatedForms API for some components and not others.

```
import {FORM_DIRECTIVES, FORM_PROVIDERS} from @angular/forms;

@Component({
   selector: some-comp,
   directives: [FORM_DIRECTIVES],
   providers: [FORM_PROVIDERS]
})
class SomeComp
```
2016-07-07 11:32:51 -07:00
776a83f9da doc(i18nPluralPipe): update API doc example (#9862) 2016-07-07 08:48:37 -07:00
f29457f3f0 fix(datePipe): short timezone not displayed, closes #9812 (#9816) 2016-07-07 08:47:30 -07:00
a005d1595e chore(compiler-cli): correct homepage URL in package.json (#9869) 2016-07-07 08:43:53 -07:00
8d746e3f67 feat(testing): add implicit test module
Every test now has an implicit module. It can be configured via `configureModule` (from @angular/core/testing)
to add providers, directives, pipes, ...

The compiler now has to be configured separately via `configureCompiler` (from @angular/core/testing)
to add providers or define whether to use jit.

BREAKING CHANGE:
- Application providers can no longer inject compiler internals (i.e. everything
  from `@angular/compiler). Inject `Compiler` instead. This reflects the
  changes to `bootstrap` for module support (3f55aa609f).
- Compiler providers can no longer be added via `addProviders` / `withProviders`.
  Use the new method `configureCompiler` instead.
- Platform directives / pipes need to be provided via
  `configureModule` and can no longer be provided via the
  `PLATFORM_PIPES` / `PLATFORM_DIRECTIVES` tokens.
- `setBaseTestProviders()` was renamed into `initTestEnvironment` and 
  now takes a `PlatformRef` and a factory for a
  `Compiler`.
- E.g. for the browser platform:
  
  BEFORE:
  ```
  import {setBaseTestProviders} from ‘@angular/core/testing’;
  import {TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
      TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS} from ‘@angular/platform-browser-dynamic/testing’;
  
  setBaseTestProviders(TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
      TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS);   
  ```

  AFTER:
  ```
  import {setBaseTestProviders} from ‘@angular/core/testing’;
  import {browserTestCompiler, browserDynamicTestPlatform,
      BrowserDynamicTestModule} from ‘@angular/platform-browser-dynamic/testing’;
  
  initTestEnvironment(
      browserTestCompiler,
      browserDynamicTestPlatform(),
      BrowserDynamicTestModule);

  ```
- E.g. for the server platform:
  
  BEFORE:
  ```
  import {setBaseTestProviders} from ‘@angular/core/testing’;
  import {TEST_SERVER_PLATFORM_PROVIDERS,
      TEST_SERVER_APPLICATION_PROVIDERS} from ‘@angular/platform-server/testing/server’;
  
  setBaseTestProviders(TEST_SERVER_PLATFORM_PROVIDERS,
      TEST_SERVER_APPLICATION_PROVIDERS);   
  ```

  AFTER:
  ```
  import {setBaseTestProviders} from ‘@angular/core/testing’;
  import {serverTestCompiler, serverTestPlatform,
      ServerTestModule} from ‘@angular/platform-browser-dynamic/testing’;
  
  initTestEnvironment(
      serverTestCompiler,
      serverTestPlatform(),
      ServerTestModule);

  ```

Related to #9726
Closes #9846
2016-07-06 18:04:19 -07:00
37e6da6dfb refactor(router): clean up naming 2016-07-06 16:19:52 -07:00
8aa2a0c1b2 feat(router): add RouterAppModule 2016-07-06 16:00:40 -07:00
6bfd514caf fix(router): remove a circular dep 2016-07-06 14:38:05 -07:00
ad3f18c0dd chore(build): update build script to increase node's heap size 2016-07-06 14:38:05 -07:00
39d04b4a15 chore(public_api): update public api 2016-07-06 14:38:05 -07:00
6fbe56dbf2 feat(router): update the example app to use lazily-loaded modules 2016-07-06 14:38:05 -07:00
8ebb8e44c8 feat(router): add support for lazily loaded modules 2016-07-06 14:38:05 -07:00
6fcf962fb5 feat(core): add AddModuleFactoryLoader 2016-07-06 14:38:05 -07:00
2708ce6a17 docs(api): fix links (#9852) 2016-07-06 14:34:27 -07:00
30bec78da3 fix(compiler): Missing metadata files should result in undefined (#9704)
RelectorHost threw an exception when metadata was requested for a
.d.ts file that didn't have a .metadata.json file.  Changed it to
return undefined.

Fixes #9678
2016-07-06 14:26:31 -07:00
9a04fcd061 feat(compiler): Expression span information and error correction (#9772)
Added error correction so the parser always returns an AST
Added span information to the expression parser
Refactored the test to account for the difference in error reporting
Added tests for error corretion
Modified tests to validate the span information
2016-07-06 14:06:47 -07:00
ae62f082fd docs(api): fix broken example urls (#9828) 2016-07-06 13:57:38 -07:00
9cc3b2ca9e fix(animations): ensure a null easing value is never used with web-animations
Closes #9780
Closes #9752
2016-07-06 11:25:54 -07:00
3fe1cb0253 refactor(core): ensure CSS parser uses ParseSourceSpan to track ast locations
This commit also fixes up any remaining TODO comments.

Closes #9778
2016-07-06 11:22:45 -07:00
0ed7773223 build(gulp): Fix paths for public-api tasks on Windows (#9794) 2016-07-05 20:52:35 -07:00
3f55aa609f feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form
bootstrap and offline compile bootstrap:

```
@AppModule({
  modules: [BrowserModule],
  precompile: [MainComponent],
  providers: […], // additional providers
  directives: […], // additional platform directives
  pipes: […] // additional platform pipes
})
class MyModule {
  constructor(appRef: ApplicationRef) {
    appRef.bootstrap(MainComponent);
  }
}

// offline compile
import {bootstrapModuleFactory} from ‘@angular/platform-browser’;
bootstrapModuleFactory(MyModuleNgFactory);

// runtime compile long form
import {bootstrapModule} from ‘@angular/platform-browser-dynamic’;
bootstrapModule(MyModule);
```

The short form, `bootstrap(...)`, can now creates a module on the fly,
given `directives`, `pipes, `providers`, `precompile` and `modules`
properties.

Related changes:
- make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token
- move `AnimationDriver` to `platform-browser` and make it
  public so that the offline compiler can resolve the token

BREAKING CHANGES:
- short form bootstrap does no longer allow
  to inject compiler internals (i.e. everything 
  from `@angular/compiler). Inject `Compiler` instead.
  To provide custom providers for the compiler,
  create a custom compiler via `browserCompiler({providers: [...]})`
  and pass that into the `bootstrap` method.
2016-07-02 20:35:09 -07:00
74b45dfbf8 Revert "refactor(core): ensure CSS parser uses ParseSourceSpan to track ast locations"
This reverts commit 5c9f871b21.
2016-07-01 21:21:56 -07:00
5c9f871b21 refactor(core): ensure CSS parser uses ParseSourceSpan to track ast locations
This commit also fixes up any remaining TODO comments.

Closes #9285
2016-07-01 17:18:14 -07:00
77dc6ef411 fix(forms): mark control containers as touched when child controls are touched (#9735) 2016-07-01 15:36:04 -07:00
5eca6e4e40 bug(datePipe): passing "hh" to the datepipe (#9774)
closes #9759
2016-07-01 15:34:57 -07:00
0c65d5cf2b fix(router): handle router outlets in ngIf 2016-06-30 22:14:42 -07:00
f65ebec3ed fix(router): update links when query params change 2016-06-30 22:14:42 -07:00
81bf3f66ca docs(router): rename global redirects into absolute redirects 2016-06-30 22:14:42 -07:00
3cbded6694 fix(forms): use change event for select multiple (#9713) 2016-06-30 20:24:39 -07:00
137fff9632 fix(router): remove private and internal annotations (#9753) 2016-06-30 19:39:13 -07:00
695c08b9dd test(forms): add test for multi-select and custom accessors (#9624) 2016-06-30 18:04:00 -07:00
119794249b doc(changelog): cleans up markdown for breaking changes (#9739) 2016-06-30 17:31:39 -07:00
afb72164e4 fix(docs): typo in comments (#9743)
correct a typo in comments
2016-06-30 15:18:41 -07:00
9fee5630fd chore: fix package on changelog (#9736) 2016-06-30 15:17:00 -07:00
01de58d650 chore(router): bump up version number 2016-06-30 14:58:59 -07:00
dabf214f17 fix(router): remove private and internal annotations (#9745) 2016-06-30 14:47:55 -07:00
fb2539e1d5 fix(router): remove the precompile warning 2016-06-30 14:33:04 -07:00
ad9f02a73e chore: enable cyclic dependency check
Closes #9742
2016-06-30 14:28:22 -07:00
2d73583253 chore(compiler): fix cyclic dependency 2016-06-30 14:28:22 -07:00
73f017bad9 fix(typescript): make router compile with typescript@next
fixes #9731
2016-06-30 11:51:52 -07:00
055282f156 chore(router): bump up version number 2016-06-30 11:45:31 -07:00
fe7de53b89 chore(router): update router change log 2016-06-30 11:45:31 -07:00
17e4cfc748 feat(core): introduce @AppModule
Main part for #9726
Closes #9730
2016-06-30 11:34:40 -07:00
1608d91728 docs(changelog): change log and package.json to rc4
Closes #9727
2016-06-30 10:16:32 -07:00
a3b90411aa fix(router): fix RouterLinkActive to handle the case when the link has extra paths 2016-06-30 09:26:57 -07:00
5781b96490 fix(router): redirect should not add unnecessary brackets 2016-06-30 09:26:57 -07:00
f208ee0d57 fix(router): reexport router directives 2016-06-30 09:26:57 -07:00
8aa388de6c doc(directive): fixes incorrect example code (#9635) 2016-06-29 22:16:43 -07:00
51d4c9dcbd fix(compiler): make code easier to type check
These changes are needed for the G3 sync as we use a different version/settings of Typescript than on Github.

closes #9701
2016-06-29 10:43:58 -07:00
e81dea695c fix(compiler): report not existing files as errors
Closes #9690
2016-06-29 07:35:34 -07:00
3fec27961e fix: support *directive on <template> (#9691)
fixes #7315
2016-06-28 21:53:41 -07:00
3784696b9e fix(router): make the contstructor of the router service public 2016-06-28 18:39:37 -07:00
8c45aebc18 fix(router): make router links work on non-a tags 2016-06-28 18:39:37 -07:00
810c722413 docs(security): point users to docs when sanitization fails. (#9680) 2016-06-28 18:13:46 -07:00
e2116c53f3 fix(upgrade): add peerDependency on platform-browser-dynamic (#9674)
Closes #9623
2016-06-28 17:27:28 -07:00
296a447e3c docs(router): add api docs 2016-06-28 14:49:29 -07:00
0961bd1eff feat(forms): use formControlName on radio buttons when name is absent (#9681) 2016-06-28 15:21:53 -06:00
9340e1b065 docs(security): security api doc update and fix stability marker for Type 2016-06-28 14:01:48 -07:00
ae4fa56ee9 fix(public API): update golden files
broken by #9606
2016-06-28 12:21:50 -07:00
2d9d7f1310 fix(security): allow empty CSS values. (#9675) 2016-06-28 11:45:02 -07:00
5ee84fe0f6 refactor: add types (#9606)
relates to #9100
2016-06-28 11:35:59 -07:00
1620426393 fix(http): don't encode values that are allowed in query (#9651)
This implements a new class, QueryEncoder, that provides
methods for encoding keys and values of query parameter.
The encoder encodes with encodeURIComponent, and then
decodes a whitelist of allowed characters back to their
unencoded form.

BREAKING CHANGE:

The changes to Http's URLSearchParams serialization now 
prevent encoding of these characters inside query parameters
which were previously converted to percent-encoded values:

@ : $ , ; + ; ? /

The default encoding behavior can be overridden by extending
QueryEncoder, as documented in the URLSearchParams service.

Fixes #9348
2016-06-28 11:31:35 -07:00
bf598d6b8b feat(compiler): support sync runtime compile
Adds new abstraction `Compiler` with methods
`compileComponentAsync` and `compileComponentSync`.
This is in preparation of deprecating `ComponentResolver`.

`compileComponentSync` is able to compile components
synchronously given all components either have an inline
template or they have been compiled before.

Also changes `TestComponentBuilder.createSync` to
take a `Type` and use the new `compileComponentSync` method.

Also supports overriding the component metadata even if
the component has already been compiled.

Also fixes #7084 in a better way.

BREAKING CHANGE:
`TestComponentBuilder.createSync` now takes a component type
and throws if not all templates are either inlined
are compiled before via `createAsync`.

Closes #9594
2016-06-28 10:26:16 -07:00
24eb8389d2 fix: public api surface fixes + stability markers
- ts-api-guardian will now error if a new public symbol is added with a stability marker (`@stable`, `@experimental`, `@deprecated`)
- DomEventsPlugin and KeyEventsPlugin were removed from public api surface - these classes is an implementation detail
- deprecated BROWSER_PROVIDERS was removed completely
- `@angular/compiler` was removed from the ts-api-guardian check since this package shouldn't contain anything that users need to directly import
- the rest of the api surface was conservatively marked as stable or experimental

BREAKING CHANGES: DomEventsPlugin and KeyEventsPlugin previously exported from core are no longer public - these classes are implementation detail.

Previously deprecated BROWSER_PROVIDERS was completely removed from platform-browser.

Closes #9236
Closes #9235
Ref #9234
2016-06-28 07:39:40 -07:00
fcfddbf79c feat(router): add pathMatch property to replace terminal 2016-06-27 20:21:30 -07:00
dc64e90ab9 feat(router): use componentFactoryResolver 2016-06-27 20:21:30 -07:00
e12b1277df feat(core): split ChangeDetectorStrategy into ChangeDetectionStrategy and ChangeDetectorStatus 2016-06-27 20:19:20 -07:00
797914e948 fix(forms): emit statusChange when child controls have async validator (#9652) 2016-06-27 21:01:24 -06:00
e0b0a594bb fix(animations): ensure void => * animations are triggered when an expression is omitted
Closes #9327
Closes #9381
2016-06-27 18:55:10 -07:00
ed0ade6f34 fix(forms): make radio button selection logic more flexible (#9646)
Closes #9558
2016-06-27 15:29:33 -06:00
5cc7b41f39 Revert "fix(Compiler): relax childIsRecursive check (#8705)"
This fix prevented waiting for child components even if the cycle was only introduced via the `directives` array, i.e. without actually having a cycle. This easily causes issues for applications that have one shared list of directives for all components.

This reverts commit 3d5bb23184.

Closes #9647
2016-06-27 14:27:03 -07:00
f2f1ec0117 feat(router): implement data and resolve 2016-06-27 14:25:56 -07:00
e913d9954d chore(typings): restrict Angular to es5+collections+promise 2016-06-27 13:58:59 -07:00
d20488752b fix(router): top-levels do not work in ngIf 2016-06-27 13:34:54 -07:00
855f3afb28 fix(router): canceled navigations should return a promise that is resolved with false 2016-06-27 13:34:54 -07:00
3f44377f2f fix(router): handle empty path with query params 2016-06-27 13:34:54 -07:00
90295e3252 fix(router): preserve fragment on initial load 2016-06-27 13:34:54 -07:00
a620f95891 build(npm): upgrade ts-api-guardian to v0.1.4
Closes #9642
2016-06-27 12:27:59 -07:00
db66509e66 test(security): tests for HTML5 elements, srcset.
Part of #9572.
2016-06-27 12:19:03 -07:00
6605eb30e9 feat(security): allow more HTML5 elements and attributes in sanitizers
Allow more elements and attributes from the HTML5 spec which were stripped by the htmlSanitizer.

fixes #9438

feat(security): allow audio data URLs in urlSanitizer

test(security) : add test for valid audio data URL

feat(security): allow and sanitize srcset attributes

test(security): test for srcset sanitization
2016-06-27 12:19:03 -07:00
3644eef860 feat(DomRenderer): Adding support for document fragments in SVG foreign objects (#9458) 2016-06-27 08:26:45 -07:00
fb2509675d doc(changelog): add backticks around html elements so they actually render (#9637) 2016-06-27 08:21:34 -07:00
eef9512ce6 fix(forms): async validator-directives process Observables correctly (#8186)
Closes #/8022
2016-06-26 16:52:50 -06:00
9f00a1b902 fix(forms): add select multiple accessor as built-in accessor 2016-06-26 16:24:27 -06:00
c369bc747d docs: update cheatsheet import lines (#9614) 2016-06-26 07:31:35 -07:00
c03e1f2f59 feat(forms): add support for formArrayName
Closes #9251
2016-06-25 13:30:53 -07:00
17dcbf66b9 feat(forms): expose ValidatorFn and AsyncValidatorFn
Closes #8834
2016-06-24 18:24:11 -07:00
40b907a657 refactor(testing): remove wrapping of Jasmine functions (#9564)
Instead, the async function now determines whether it should return a promise
or instead call a done function parameter. Importing Jasmine functions
from `@angular/core/testing` is no longer necessary and is now deprecated.

Additionally, beforeEachProviders is also deprecated, as it is specific
to the testing framework. Instead, use the new addProviders method directly.

Before:
```js
import {beforeEachProviders, it, describe, inject} from 'angular2/testing/core';

describe('my code', () => {
  beforeEachProviders(() => [MyService]);

  it('does stuff', inject([MyService], (service) => {
    // actual test
  });
});
```

After:
```js
import {addProviders, inject} from 'angular2/testing/core';

describe('my code', () => {
  beforeEach(() => {
    addProviders([MyService]);
  });

  it('does stuff', inject([MyService], (service) => {
    // actual test
  });
});
```
2016-06-24 17:48:35 -07:00
a33195dcf3 fix(core/testing compiler/testing): move TestComponentBuilder to core/testing (#9590)
TestComponentBuilder now lives in core/testing. compiler/testing contains a private
OverridingTestComponentBuilder implementation which handles the private behavior
we need to override templates. This is part of the effort to simplify the testing
imports and hide compiler APIs.

Closes #9585

BREAKING CHANGE:

`TestComponentBuilder` is now imported from `@angular/core/testing`. Imports
from `@angular/compiler/testing` are deprecated.

Before:

```
import {TestComponentBuilder, TestComponentRenderer, ComponentFixtureAutoDetect} from '@angular/compiler/testing';
```

After:
```
import {TestComponentBuilder, TestComponentRenderer, ComponentFixtureAutoDetect} from '@angular/core/testing';
```
2016-06-24 17:35:01 -07:00
c693c03f1d test(node): enable source maps in test.sh node (#9589) 2016-06-24 16:52:41 -07:00
de127109f9 feat(forms): make valueChanges and statusChanges available on abstract control directives 2016-06-24 14:37:19 -07:00
83208983b3 chore(router): bump up version number 2016-06-24 13:07:42 -07:00
327d04c9c6 chore(router): clang-format 2016-06-24 12:44:32 -07:00
54edce2bab fix(router): wildcard don't get notified on url changes 2016-06-24 12:44:32 -07:00
1a145ac500 fix(router): default exact to false in routerLinkActiveOptions 2016-06-24 12:44:32 -07:00
9f978cf49d test(router): add a test checking that you can use a slash in query params 2016-06-24 12:44:32 -07:00
41b781107b fix(router): doen't throw on canDeactive when route hasn't advanced 2016-06-24 12:44:32 -07:00
dcf75126bf fix(common/testing): remove internal MockLocationStrategy from common/testing (#9562)
BREAKING CHANGE:

MockLocationStrategy was intended to be internal only and is now removed
from the `@angular/common/testing` public api.

Use `SpyLocation` from `@angular/common/testing` for location testing.
2016-06-24 12:41:57 -07:00
1143b0389a fix(core/testing): move ComponentFixture to core (#9386)
BREAKING CHANGE:

`ComponentFixture` will be moving out of `@angular/compiler/testing` to `@angular/core/testing` in
this release. For now, it is deprecated from `@angular/compiler/testing`.
2016-06-24 12:41:49 -07:00
97a2119596 fix(forms): ngModel should emit valueChanges and statusChanges asynchronously 2016-06-24 12:37:46 -07:00
fbd2dd9ca2 fix(router): handle path:'' redirects and matches 2016-06-24 11:39:41 -07:00
f463e09b9f fix(ngc): work with typescript@next
This is required due to breaking change in TS, see
https://github.com/Microsoft/TypeScript/pull/8841#issuecomment-227300348
2016-06-24 10:27:31 -07:00
42a5b6cbda chore(testing): upgrade ts-api-guardian to 0.1.3 2016-06-23 18:19:32 -07:00
0ad1215a92 build(changelog): remove old changelog script and add gulp task 2016-06-23 17:35:57 -07:00
7733c97df3 build(npm): update conventional-changelog dependency
Fixes #5672
2016-06-23 17:35:57 -07:00
8a9e9c7bd3 fix(core/testing): clean up the core testing public API (#9466)
Previously, we were exporting internal mocks and helpers. Move these
to core/testing/testing_internal or remove them if they were
never used.

Remove deprecated items - injectAsync, clearPendingTimers.

BREAKING CHANGE:

Remove the following APIs from `@angular/core/testing`, which have been deprecated or were
never intended to be publicly exported:

```
injectAsync
clearPendingTimers
Log
MockAppliacationHref
MockNgZone
clearPendingTimers
getTypeOf
instantiateType
```

Instead of `injectAsync`, use `async(inject())`.

`clearPendingTimers` is no longer required.
2016-06-23 17:10:22 -07:00
3d8eb8cbca fix(platform-browser/testing): clean up public api for platform-browser/testing (#9519)
Mostly, removing things that were never intended to be exported publicy.

BREAKING CHANGE:

The following are no longer publicly exported APIs. They were intended as internal
utilities and you should use your own util:

```
browserDetection,
dispatchEvent,
el,
normalizeCSS,
stringifyElement,
expect (and custom matchers for Jasmine)
```
2016-06-23 16:42:25 -07:00
894747c34c fix(platform-browser/testing-e2e): clean up unused exports from e2e testing helpers (#9387) 2016-06-23 16:14:31 -07:00
8d5a312585 chore(api): clean up compiler/testing api (#9520)
Do not export MockXHR, which is a private helper.
2016-06-23 15:52:18 -07:00
8eb81b3741 ci: add updated ts-api-guardian check 2016-06-23 14:26:40 -07:00
22d8f73bc9 test: add public api golden files
Includes a few style fixes on "* as foo" imports.
2016-06-23 14:26:40 -07:00
249a6bdd98 test: upgrade ts-api-guardian to v0.1.2 2016-06-23 14:26:40 -07:00
3ad81b1beb test(security): simplify integration test. 2016-06-23 13:57:51 -07:00
5ab0534164 test(security): Ensure xlink:href is not bindable.
The DOM schema does not allow binding any properties to dangerous SVG
attributes/properties. This change adds a smoke test to verify that
behaviour, by testing that `xlink:href` (a sample dangerous property)
is not bindable.

Fixes #9510.
2016-06-23 13:57:51 -07:00
5150344213 fix(common): add license header to localization.ts 2016-06-23 13:27:43 -07:00
98cef76931 fix(security): no warning when sanitizing escaped html (#9392) (#9413) 2016-06-23 13:06:19 -07:00
6c5b653593 feat(core): add @Component.precompile and ComponentFactoryResolver
Part to #9467
Closes #9543
2016-06-23 12:10:04 -07:00
9ed8f2d26e fix(compiler): don't inject viewProviders into content child elements
E.g. in the following scenario,
`some-directive` should not be able to inject
any view provider that `my-comp-with-view-providers`
declares.

```
<my-comp-with-view-providers>
  <div some-directive></div>
</my-comp-with-view-providers>
```
2016-06-23 12:10:04 -07:00
33a2f86b28 chore: remove stale tsconfig.json
This tsconfig.json prevents fast round trip cycles in VsCode
as it relies on the package-dist folders to be filled.
2016-06-23 12:10:04 -07:00
fed1672a43 refactor(i18n): I18nPipe uses NgLocalization (#9313)
and some refactoring
2016-06-23 11:44:05 -07:00
54dbed4f48 fix(typings): don't test compiler-cli typings on TS 1.8 2016-06-23 10:57:03 -07:00
df759b8d4b fix(core): improve error message for broken bindings
Fixes #6820

Closes #9536
2016-06-23 19:28:56 +02:00
6edf0474cc feat(forms): add support for standalone ngModel dirs inside forms
Closes #9230
2016-06-23 10:16:47 -07:00
826f89f862 fix(ngc): correct dependencies for compiler-cli
Update compiler-cli dependencies to include minimist and also increment tsc-wrapped to 0.2.0.  There is signature mismatch between tsc-wrapped (v0.1.0) collector.js#getMetadata and compiler-cli reflector_host.js#getMetadataFor that caused an error anytime ngc was executed. The error received was as follows.

`TypeError: Cannot read property 'getSymbolsInScope' of undefined`

After forcing NPM to install @angular/tsc-wrapped@latest the error was resolved.

Fixes #9540
2016-06-23 10:16:04 -07:00
c43aec2182 fix(animations): make sure the easing value is passed into the web-animations player
Closes #9517
Closes #9523
2016-06-23 10:14:18 -07:00
ae75e3640a chore(lint): Added license headers to most TypeScript files
Relates to #9380
2016-06-23 09:47:54 -07:00
a5f2cc73f6 chore(lint): Add lint check for license headers
Added a tslint check to make sure all source files begin with a license
header (at the very beginning or after a `#!`).

Relates to #9380
2016-06-23 09:46:32 -07:00
e1e5c40ef7 fix(testing): remove the toThrowErrorWith matcher (jasmine has toThrowError)
BREAKING CHANGE:

Before:

    expect(...).toThrowErrorWith(msg);

After:

    expect(...).toThrowError(msg);
2016-06-23 08:58:52 -07:00
6420f75320 fix(testing): remove the toMatchPattern matcher (jasmine has toMatch)
BREAKING CHANGE:

Before:

    expect(...).toMatchPattern(pattern);

After:

    expect(...).toMatch(pattern);
2016-06-23 08:58:28 -07:00
5face35ae5 refactor: misc cleanup 2016-06-23 08:56:10 -07:00
398060d5ff fix(NgSwitch): display deprecation message only once 2016-06-23 08:56:10 -07:00
638fd744aa feat(forms): support updating of validators on exiting controls (#9516)
lint

fix

async

d

test

test
2016-06-23 08:18:07 -07:00
098b461b69 fix(core): report duplicate template bindings in templates
Fixes #7315

BREAKING CHANGES:

Previously multiple template bindings on one element
(ex. `<div *ngIf='..' *ngFor='...'>`) were allowed but most of the time
were leading to undesired result. It is possible that a small number
of applications will see template parse errors that shuld be fixed by
nesting elements or using `<template>` tags explicitly.

Closes #9462
2016-06-23 15:59:07 +02:00
9decc3d823 build: fix some issues on Windows platforms
Closes #9450
2016-06-23 10:46:01 +02:00
a5f2e205ef fix(http): add search param escaping for keys (#9166) 2016-06-22 18:23:15 -07:00
8899b83927 chore(typescript): Enabled noFallthroughCasesInSwitch
Turned on the noFallthroughCasesInSwitch flag in tsconfig and fixed
a few cases where there were fallthroughs.
2016-06-22 16:08:55 -07:00
f6a410a4a8 feat(QueryList): implement some() (#9464)
closes #9443
2016-06-22 13:13:31 -07:00
3d5bb23184 fix(Compiler): relax childIsRecursive check (#8705)
Fix how the compiler checks for recursive components by also considering
component descendants. Previously, it only checked if the current
component was evaluated previously. This failed in certain cases of
mutually recursive components, causing `createAsync` in tests to not
resolve.

closes [7084](https://github.com/angular/angular/issues/7084)
2016-06-22 07:02:11 -07:00
ef37d2ae0b example(router): add an example app for the new router 2016-06-21 23:19:26 -07:00
2eb234bc63 chore(router): enable bundling 2016-06-21 23:19:26 -07:00
758ee95880 fix(router): fix tsconfig to use es2015 modules 2016-06-21 23:19:26 -07:00
40e1112a8e chore(router): test karma config to rerun tests on change 2016-06-21 23:19:26 -07:00
397f5e2390 refactor(HtmlLexer): simplify the code 2016-06-21 18:03:22 -07:00
1a212259af refactor: cleanup lexers & parsers 2016-06-21 18:03:22 -07:00
f114dd300b fix(core): properly report missing providers and viewProviders (#9411)
Fixes #8237
2016-06-21 17:27:27 -07:00
5954a26bce docs: add latest changelog updates (#9415) 2016-06-21 17:16:22 -07:00
1512 changed files with 54363 additions and 56985 deletions

3
.gitattributes vendored
View File

@ -3,3 +3,6 @@
# JS files must always use LF for tools to work
*.js eol=lf
# Must keep Windows line ending to be parsed correctly
scripts/windows/packages.txt eol=crlf

View File

@ -30,4 +30,4 @@ If the current behavior is a bug or you can illustrate your feature request bett
* **Browser:** [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
* **Language:** [all | TypeScript X.X | ES6/7 | ES5 | Dart]
* **Language:** [all | TypeScript X.X | ES6/7 | ES5]

View File

@ -1,3 +1,729 @@
<a name="2.0.0-rc.5"></a>
# [2.0.0-rc.5](https://github.com/angular/angular/compare/2.0.0-rc.4...2.0.0-rc.5) (2016-08-09)
### Bug Fixes
* **animations:** change trigger binding syntax to function as a property binding [] ([7f4954b](https://github.com/angular/angular/commit/7f4954b))
* **animations:** ensure a null easing value is never used with web-animations ([9cc3b2c](https://github.com/angular/angular/commit/9cc3b2c)), closes [#9780](https://github.com/angular/angular/issues/9780) [#9752](https://github.com/angular/angular/issues/9752)
* **animations:** ensure all child elements are rendered before running animations ([c3bdd50](https://github.com/angular/angular/commit/c3bdd50)), closes [#9402](https://github.com/angular/angular/issues/9402) [#9775](https://github.com/angular/angular/issues/9775) [#9887](https://github.com/angular/angular/issues/9887)
* **animations:** ensure animation detection doesn't rely on the body node ([0d1bf81](https://github.com/angular/angular/commit/0d1bf81)), closes [#10230](https://github.com/angular/angular/issues/10230) [#10191](https://github.com/angular/angular/issues/10191) [#10273](https://github.com/angular/angular/issues/10273)
* **animations:** throw errors when duplicate component trigger names are registered ([5af1e89](https://github.com/angular/angular/commit/5af1e89))
* **compiler:** allow to use pipes inside of `*ngIf` ([#10452](https://github.com/angular/angular/issues/10452)) ([8efbcc9](https://github.com/angular/angular/commit/8efbcc9)), closes [#9746](https://github.com/angular/angular/issues/9746)
* **compiler:** auto declare `entryComponents` recursively ([a32c4ad](https://github.com/angular/angular/commit/a32c4ad)), closes [#10348](https://github.com/angular/angular/issues/10348)
* **compiler:** Collector collects enum values. ([#9967](https://github.com/angular/angular/issues/9967)) ([e6b2443](https://github.com/angular/angular/commit/e6b2443))
* **compiler:** Fixed ?. operator to short-circut execution ([#9965](https://github.com/angular/angular/issues/9965)) ([4ec2a30](https://github.com/angular/angular/commit/4ec2a30)), closes [#9965](https://github.com/angular/angular/issues/9965)
* **compiler:** Generates function expressions as returning any ([#9980](https://github.com/angular/angular/issues/9980)) ([eb5763c](https://github.com/angular/angular/commit/eb5763c))
* **compiler:** Ignore references to declared modules and unneeded types ([#9776](https://github.com/angular/angular/issues/9776)) ([4ef8689](https://github.com/angular/angular/commit/4ef8689))
* **compiler:** Missing metadata files should result in undefined ([#9704](https://github.com/angular/angular/issues/9704)) ([30bec78](https://github.com/angular/angular/commit/30bec78)), closes [#9678](https://github.com/angular/angular/issues/9678)
* **compiler:** No longer writes 0 length files outside of genDir ([#10023](https://github.com/angular/angular/issues/10023)) ([6518ff8](https://github.com/angular/angular/commit/6518ff8))
* **compiler:** Query expression lambdas should have dynamic type ([961c9d4](https://github.com/angular/angular/commit/961c9d4))
* **compiler:** report better error messages for `host` bindings ([fb3608a](https://github.com/angular/angular/commit/fb3608a)), closes [#10346](https://github.com/angular/angular/issues/10346)
* **compiler:** Report references to non-exported symbols. ([9925aa8](https://github.com/angular/angular/commit/9925aa8))
* **compiler:** StaticReflect now resolves re-exported symbols ([#10453](https://github.com/angular/angular/issues/10453)) ([82e7ecd](https://github.com/angular/angular/commit/82e7ecd)), closes [#10453](https://github.com/angular/angular/issues/10453)
* **compiler:** treat custom elements as unknown elements by default ([fc83bbb](https://github.com/angular/angular/commit/fc83bbb)), closes [#10300](https://github.com/angular/angular/issues/10300)
* **compiler:** Catch exceptions in the logging of binding update ([2743627](https://github.com/angular/angular/commit/2743627)), closes [#9994](https://github.com/angular/angular/issues/9994)
* **compiler:** Better error message in case of unknown property binding ([a55d796](https://github.com/angular/angular/commit/a55d796))
* **compiler:** String.split(str, n) stops after n separator ([#10408](https://github.com/angular/angular/issues/10408)) ([13c8211](https://github.com/angular/angular/commit/13c8211))
* **compiler-cli:** put all `ngc` files into a single directory ([#10486](https://github.com/angular/angular/issues/10486)) ([790362e](https://github.com/angular/angular/commit/790362e))
* **compiler-cli:** support trailing slash in basePath ([#10533](https://github.com/angular/angular/issues/10533)) ([0d1f3c3](https://github.com/angular/angular/commit/0d1f3c3))
* **core:** allow module providers to overwrite providers from `ModuleWithProviders` ([5533447](https://github.com/angular/angular/commit/5533447)), closes [#10313](https://github.com/angular/angular/issues/10313) [#10317](https://github.com/angular/angular/issues/10317)
* **core:** Don't use ES6 spread operator when undefined is allowed. ([2ff8332](https://github.com/angular/angular/commit/2ff8332))
* **core:** ensure ngFor only inserts/moves/removes elements when necessary ([#10287](https://github.com/angular/angular/issues/10287)) ([e18626b](https://github.com/angular/angular/commit/e18626b)), closes [#9960](https://github.com/angular/angular/issues/9960) [#7239](https://github.com/angular/angular/issues/7239) [#9672](https://github.com/angular/angular/issues/9672) [#9454](https://github.com/angular/angular/issues/9454) [#10287](https://github.com/angular/angular/issues/10287)
* **core:** fix offline detection in ng_module_factory_loader ([915a666](https://github.com/angular/angular/commit/915a666))
* **core:** only warn and auto declare undeclared `entryComponents`. ([e44e866](https://github.com/angular/angular/commit/e44e866)), closes [#10316](https://github.com/angular/angular/issues/10316)
* **core:** support components without a selector ([#10331](https://github.com/angular/angular/issues/10331)) ([9b39e49](https://github.com/angular/angular/commit/9b39e49)), closes [#3464](https://github.com/angular/angular/issues/3464) [#10216](https://github.com/angular/angular/issues/10216)
* **CurrencyPipe:** use default Intl formatting options when none provided ([d455942](https://github.com/angular/angular/commit/d455942)), closes [#10189](https://github.com/angular/angular/issues/10189)
* **datePipe:** short timezone not displayed, closes [#9812](https://github.com/angular/angular/issues/9812) ([#9816](https://github.com/angular/angular/issues/9816)) ([f29457f](https://github.com/angular/angular/commit/f29457f)), closes [#9812](https://github.com/angular/angular/issues/9812) [#9816](https://github.com/angular/angular/issues/9816)
* **DirectiveResolver:** throw on duplicate Input & Output names ([d1a3e3a](https://github.com/angular/angular/commit/d1a3e3a))
* **docs:** typo in comments ([#9743](https://github.com/angular/angular/issues/9743)) ([afb7216](https://github.com/angular/angular/commit/afb7216))
* **ExpressionParser:** undefined is undefined (was null) ([b4613ab](https://github.com/angular/angular/commit/b4613ab))
* **fake_async:** share zone between `beforeEach` and `it` ([16cc9b4](https://github.com/angular/angular/commit/16cc9b4))
* **forms:** allow arrays as parents ([#10440](https://github.com/angular/angular/issues/10440)) ([d6d4568](https://github.com/angular/angular/commit/d6d4568)), closes [#10432](https://github.com/angular/angular/issues/10432)
* **forms:** export AbstractFormGroupDirective ([6195a45](https://github.com/angular/angular/commit/6195a45))
* **forms:** export form directive arrays for offline compile ([#9893](https://github.com/angular/angular/issues/9893)) ([93025d1](https://github.com/angular/angular/commit/93025d1))
* **forms:** improve ngModel error messages ([#10314](https://github.com/angular/angular/issues/10314)) ([43349dd](https://github.com/angular/angular/commit/43349dd))
* **forms:** improve no value accessor error message ([#10051](https://github.com/angular/angular/issues/10051)) ([34feecf](https://github.com/angular/angular/commit/34feecf))
* **forms:** mark control containers as touched when child controls are touched ([#9735](https://github.com/angular/angular/issues/9735)) ([77dc6ef](https://github.com/angular/angular/commit/77dc6ef))
* **forms:** normalize written value in NumberValueAccessor ([b48f7bc](https://github.com/angular/angular/commit/b48f7bc)), closes [#10379](https://github.com/angular/angular/issues/10379)
* **forms:** re-enable form provider functions for easier migration ([#9972](https://github.com/angular/angular/issues/9972)) ([e68252a](https://github.com/angular/angular/commit/e68252a))
* **forms:** throw error if wrong control container for reactive forms ([#10286](https://github.com/angular/angular/issues/10286)) ([0aba42a](https://github.com/angular/angular/commit/0aba42a))
* **forms:** update dirty before emitting value change ([#10362](https://github.com/angular/angular/issues/10362)) ([7c76a75](https://github.com/angular/angular/commit/7c76a75)), closes [#5328](https://github.com/angular/angular/issues/5328)
* **forms:** missing export for validators ([91c64d2](https://github.com/angular/angular/commit/91c64d2))
* **forms:** use change event for select multiple ([#9713](https://github.com/angular/angular/issues/9713)) ([3cbded6](https://github.com/angular/angular/commit/3cbded6))
* **HtmlParser:** correctly propagate the interpolation config across layers ([25e070d](https://github.com/angular/angular/commit/25e070d))
* **http:** convert objects passed to requests into a string ([#10124](https://github.com/angular/angular/issues/10124)) ([83bc5c9](https://github.com/angular/angular/commit/83bc5c9)), closes [#10073](https://github.com/angular/angular/issues/10073)
* **http:** headers should be case-insensitive. ([7f64782](https://github.com/angular/angular/commit/7f64782)), closes [#9452](https://github.com/angular/angular/issues/9452)
* **http:** URLSearchParams.clone propagate the QueryEncoder ([#9900](https://github.com/angular/angular/issues/9900)) ([2519532](https://github.com/angular/angular/commit/2519532))
* **i18n extractor:** array manipulation ([df44e3e](https://github.com/angular/angular/commit/df44e3e))
* **KeyValueDiffer:** check for changes ([3f08efa](https://github.com/angular/angular/commit/3f08efa)), closes [#9115](https://github.com/angular/angular/issues/9115)
* **linker:** prevent pollution of empty embeddedView context ([#10548](https://github.com/angular/angular/issues/10548)) ([46bbcef](https://github.com/angular/angular/commit/46bbcef)), closes [#10045](https://github.com/angular/angular/issues/10045)
* **linker/compiler:** rename const to avoid duplicate declaration ([#10457](https://github.com/angular/angular/issues/10457)) ([2b704f0](https://github.com/angular/angular/commit/2b704f0))
* **metadata:** fix typechecking with typescript[@next](https://github.com/next) ([0a46f37](https://github.com/angular/angular/commit/0a46f37))
* **ng upgrade:** do not compile ng2 components until after ng1 bootstrap ([#10084](https://github.com/angular/angular/issues/10084)) ([9edea0b](https://github.com/angular/angular/commit/9edea0b)), closes [#9407](https://github.com/angular/angular/issues/9407) [angular/protractor#2944](https://github.com/angular/protractor/issues/2944)
* **ngc:** gather metadata for OpaqueToken ([c8d53d7](https://github.com/angular/angular/commit/c8d53d7)), closes [#10482](https://github.com/angular/angular/issues/10482)
* **ngClass:** do not deconstruct classes on element removal ([#10303](https://github.com/angular/angular/issues/10303)) ([ba88db5](https://github.com/angular/angular/commit/ba88db5)), closes [#10008](https://github.com/angular/angular/issues/10008) [#10303](https://github.com/angular/angular/issues/10303)
* **NgPlural:** expression inside cases ([#9883](https://github.com/angular/angular/issues/9883)) ([b7e69bc](https://github.com/angular/angular/commit/b7e69bc)), closes [#9868](https://github.com/angular/angular/issues/9868)
* **NgStyle:** remove duplicate input declaration ([#9978](https://github.com/angular/angular/issues/9978)) ([94dc632](https://github.com/angular/angular/commit/94dc632)), closes [#9977](https://github.com/angular/angular/issues/9977)
* **ngUpgrade:** to work with [@NgModule](https://github.com/NgModule) ([d21331e](https://github.com/angular/angular/commit/d21331e))
* **platform-browser:** IEMobile is badly detected when testing ([#10382](https://github.com/angular/angular/issues/10382)) ([43c71ae](https://github.com/angular/angular/commit/43c71ae))
* **platform-browser:** remove testing_e2e target ([#10029](https://github.com/angular/angular/issues/10029)) ([4a96505](https://github.com/angular/angular/commit/4a96505))
* **platform-browser:** throw useful error on missing platform module. ([73f02c7](https://github.com/angular/angular/commit/73f02c7))
* **platform-browser-dynamic:** Add [@Injectable](https://github.com/Injectable)() annotation to XHRImpl. ([7b31178](https://github.com/angular/angular/commit/7b31178))
* **router:** absolute redirects should work with lazy loading ([3a307c2](https://github.com/angular/angular/commit/3a307c2))
* **router:** add segmentPath to the link DSL ([4f17dbc](https://github.com/angular/angular/commit/4f17dbc))
* **router:** advance query params and fragment after advanced routes ([06e4ca4](https://github.com/angular/angular/commit/06e4ca4))
* **router:** back button does not work in IE11 and Safari ([f08060b](https://github.com/angular/angular/commit/f08060b))
* **router:** configure DI correctly when using the old `provideRouter` function ([93ade74](https://github.com/angular/angular/commit/93ade74))
* **router:** disallow root segments with matrix params ([34b3c53](https://github.com/angular/angular/commit/34b3c53))
* **router:** do not fire events on 'duplicate' location events ([0b54e3c](https://github.com/angular/angular/commit/0b54e3c))
* **router:** encode/decode params and path segments ([46e105f](https://github.com/angular/angular/commit/46e105f))
* **router:** export navigation extras ([51e661e](https://github.com/angular/angular/commit/51e661e))
* **router:** expose initalNavigation and dispose so they can be used with webworkers ([b77a4a4](https://github.com/angular/angular/commit/b77a4a4))
* **router:** fix matrix params check to handle 'special' objects ([d2d36c6](https://github.com/angular/angular/commit/d2d36c6))
* **router:** fix offline compilation by exporting provideLocationStrategy ([8dc82a0](https://github.com/angular/angular/commit/8dc82a0))
* **router:** fix rollup config to properly set up rxjs ([1803ed2](https://github.com/angular/angular/commit/1803ed2))
* **router:** fix RouterLinKActive to work with RouterLink ([f7a0e9e](https://github.com/angular/angular/commit/f7a0e9e))
* **router:** fix type definition ([c586656](https://github.com/angular/angular/commit/c586656))
* **router:** freeze params and queryParams to prevent common source of bugs ([0668ba5](https://github.com/angular/angular/commit/0668ba5))
* **router:** handle lastPathIndex of empty-path routes ([7a4f662](https://github.com/angular/angular/commit/7a4f662))
* **router:** handle router outlets in ngIf ([0c65d5c](https://github.com/angular/angular/commit/0c65d5c))
* **router:** handle url fragments when no url segments present ([43437c1](https://github.com/angular/angular/commit/43437c1))
* **router:** handle urls with only secondary top-level segments ([44709e0](https://github.com/angular/angular/commit/44709e0))
* **router:** handle when both primary and secondary are empty-path and primary has a child ([2b63330](https://github.com/angular/angular/commit/2b63330))
* **router:** lazily-loaded modules should use loaded injectors instead of the root one ([85be729](https://github.com/angular/angular/commit/85be729))
* **router:** lazy loaded components should use loaded injector ([921a179](https://github.com/angular/angular/commit/921a179))
* **router:** make an outlet to unregister itself when it is removed from the dom ([3e377f5](https://github.com/angular/angular/commit/3e377f5))
* **router:** make router provides work with cli and offline compilation ([d15a1d6](https://github.com/angular/angular/commit/d15a1d6))
* **router:** merge SystemJsAppModuleFactoryLoader and SystemJsAllModuleLoader ([0426325](https://github.com/angular/angular/commit/0426325))
* **router:** navigation should not preserve query params and fragment by default ([23ee29b](https://github.com/angular/angular/commit/23ee29b))
* **router:** provideRouter should use provideRoutes ([#10488](https://github.com/angular/angular/issues/10488)) ([2eda7a5](https://github.com/angular/angular/commit/2eda7a5))
* **router:** relax type defintion of Route to improve dev ergonomics ([bb8b82b](https://github.com/angular/angular/commit/bb8b82b))
* **router:** remove a circular dep ([6bfd514](https://github.com/angular/angular/commit/6bfd514))
* **router:** remove private and internal annotations ([#9745](https://github.com/angular/angular/issues/9745)) ([dabf214](https://github.com/angular/angular/commit/dabf214))
* **router:** remove private and internal annotations ([#9753](https://github.com/angular/angular/issues/9753)) ([137fff9](https://github.com/angular/angular/commit/137fff9))
* **router:** remove the precompile warning ([fb2539e](https://github.com/angular/angular/commit/fb2539e))
* **router:** route.parent should work for secondary children ([5a99393](https://github.com/angular/angular/commit/5a99393))
* **router:** router link active should take all descendants into account ([8d90a5a](https://github.com/angular/angular/commit/8d90a5a))
* **router:** routerLinkActive should only set classes after the router has successfully navigated ([db54a84](https://github.com/angular/angular/commit/db54a84))
* **router:** support outlets in non-absolute positions ([afcb3c0](https://github.com/angular/angular/commit/afcb3c0))
* **router:** throw when cannot parse a url ([27b87ef](https://github.com/angular/angular/commit/27b87ef))
* **router:** update current state and url before activating components ([5cf5897](https://github.com/angular/angular/commit/5cf5897))
* **router:** update dts files ([81d27da](https://github.com/angular/angular/commit/81d27da))
* **router:** update dts files ([a415613](https://github.com/angular/angular/commit/a415613))
* **router:** update links when query params change ([f65ebec](https://github.com/angular/angular/commit/f65ebec))
* **router:** updates router module to be offline-compilation friendly ([72da547](https://github.com/angular/angular/commit/72da547))
* **static_reflector:** report methods with decorators in `propMetadata` as well ([367f0fd](https://github.com/angular/angular/commit/367f0fd)), closes [#10308](https://github.com/angular/angular/issues/10308) [#10318](https://github.com/angular/angular/issues/10318)
* **static_reflector:** resolve values of functions in the function context ([d6b65db](https://github.com/angular/angular/commit/d6b65db))
* **SyncAsyncResult:** fix default async value ([#10013](https://github.com/angular/angular/issues/10013)) ([6d02d2f](https://github.com/angular/angular/commit/6d02d2f)), closes [#10013](https://github.com/angular/angular/issues/10013)
* **TemplateParser:** add support for data-template attribute ([d84a43c](https://github.com/angular/angular/commit/d84a43c)), closes [#9904](https://github.com/angular/angular/issues/9904)
* **TemplateParser:** report empty expression ([#10391](https://github.com/angular/angular/issues/10391)) ([e73d051](https://github.com/angular/angular/commit/e73d051)), closes [#3754](https://github.com/angular/angular/issues/3754)
* **testing:** add an explicit doAsyncPrecompilation step ([#10015](https://github.com/angular/angular/issues/10015)) ([b43f954](https://github.com/angular/angular/commit/b43f954)), closes [#9975](https://github.com/angular/angular/issues/9975) [#9593](https://github.com/angular/angular/issues/9593)
* **testing:** Add platform directives to the shim that keeps setBaseTestProviders running ([#10154](https://github.com/angular/angular/issues/10154)) ([979946c](https://github.com/angular/angular/commit/979946c))
* **testing:** ComponentFixture - Avoid extra scheduleMicrotask ([#10223](https://github.com/angular/angular/issues/10223)) ([e34eb45](https://github.com/angular/angular/commit/e34eb45))
* **testing:** correctly import NgMatchers ([#10077](https://github.com/angular/angular/issues/10077)) ([64fc464](https://github.com/angular/angular/commit/64fc464))
* **testing:** Fix error message in test bed ([3b690b6](https://github.com/angular/angular/commit/3b690b6))
* **testing:** reintroduce and deprecate setBaseTestProviders ([#9905](https://github.com/angular/angular/issues/9905)) ([2923187](https://github.com/angular/angular/commit/2923187))
* **testing:** remove deprecated testing APIs ([#9923](https://github.com/angular/angular/issues/9923)) ([9af2d8b](https://github.com/angular/angular/commit/9af2d8b))
* **typescript:** make router compile with typescript[@next](https://github.com/next) ([73f017b](https://github.com/angular/angular/commit/73f017b)), closes [#9731](https://github.com/angular/angular/issues/9731)
* **UrlParser:** stop setting default value 'true' ([#10399](https://github.com/angular/angular/issues/10399)) ([0d6cc17](https://github.com/angular/angular/commit/0d6cc17))
### Code Refactoring
* **core:** change bootstrap of modules and names of platforms ([5a21f16](https://github.com/angular/angular/commit/5a21f16))
* **core:** change module semantics ([46b2127](https://github.com/angular/angular/commit/46b2127)), closes [#10164](https://github.com/angular/angular/issues/10164)
* **core:** clean up platform bootstrap and initTestEnvironment ([fa47890](https://github.com/angular/angular/commit/fa47890)), closes [#9922](https://github.com/angular/angular/issues/9922)
* **core:** deprecate `coreBootstrap`, `PLATFORM_PIPES/DIRECTIVES` providers and `ComponentResolver` ([daa9da4](https://github.com/angular/angular/commit/daa9da4)), closes [#9726](https://github.com/angular/angular/issues/9726)
* **core:** deprecate old methods on `ApplicationRef` ([34624b2](https://github.com/angular/angular/commit/34624b2))
* **core:** introduce `APP_BOOTSTRAP_LISTENER` multi provider ([af2e80e](https://github.com/angular/angular/commit/af2e80e))
* **core:** Introduce `AppInitStatus` ([6300283](https://github.com/angular/angular/commit/6300283))
* **core:** introduce `NgModule.schemas` ([00b726f](https://github.com/angular/angular/commit/00b726f))
* **core:** make `lockRunMode` a noop and deprecate it. ([98d49d4](https://github.com/angular/angular/commit/98d49d4)), closes [#9878](https://github.com/angular/angular/issues/9878)
* **core:** remove `ViewResolver` and `ViewResolverMock` ([0988cc8](https://github.com/angular/angular/commit/0988cc8))
* **core:** rename `precompile` into `entryComponents`. ([6f4e49e](https://github.com/angular/angular/commit/6f4e49e))
* **core:** use `ngOnDestroy` in providers ([8e6091d](https://github.com/angular/angular/commit/8e6091d))
* **testing:** introduce new testing api to support ng modules ([d0a95e3](https://github.com/angular/angular/commit/d0a95e3)), closes [#10354](https://github.com/angular/angular/issues/10354)
### Features
* **animations:** allow animation integration support into host params ([806a254](https://github.com/angular/angular/commit/806a254)), closes [#9044](https://github.com/angular/angular/issues/9044) [#9933](https://github.com/angular/angular/issues/9933)
* **browser:** use AppModules for bootstrap in the browser ([3f55aa6](https://github.com/angular/angular/commit/3f55aa6))
* **compiler:** add `MockPipeResolver` ([4ad6bcc](https://github.com/angular/angular/commit/4ad6bcc))
* **compiler:** Added support for conditional expressions. ([#10366](https://github.com/angular/angular/issues/10366)) ([20b03ba](https://github.com/angular/angular/commit/20b03ba))
* **compiler:** Added support for references to static fields. ([#10334](https://github.com/angular/angular/issues/10334)) ([b58e9ea](https://github.com/angular/angular/commit/b58e9ea))
* **compiler:** Allow calls to simple static methods ([#10289](https://github.com/angular/angular/issues/10289)) ([b449467](https://github.com/angular/angular/commit/b449467))
* **compiler:** Expression span information and error correction ([#9772](https://github.com/angular/angular/issues/9772)) ([9a04fcd](https://github.com/angular/angular/commit/9a04fcd))
* **compiler:** introduce `MockDirectiveResolver.setDirective` ([acc6c8d](https://github.com/angular/angular/commit/acc6c8d))
* **compiler:** Support default parameters in static reflector ([#10370](https://github.com/angular/angular/issues/10370)) ([763ca60](https://github.com/angular/angular/commit/763ca60))
* **core:** add AddModuleFactoryLoader ([6fcf962](https://github.com/angular/angular/commit/6fcf962))
* **core:** allow to add precompiled tokens via a provider ([7073cf7](https://github.com/angular/angular/commit/7073cf7)), closes [#9874](https://github.com/angular/angular/issues/9874)
* **core:** introduce `[@AppModule](https://github.com/AppModule)` ([17e4cfc](https://github.com/angular/angular/commit/17e4cfc)), closes [#9730](https://github.com/angular/angular/issues/9730)
* **core:** introduce `ModuleWithProviders`. ([f02da4e](https://github.com/angular/angular/commit/f02da4e))
* **core:** introduce `NgModuleRef.destroy` and call `ngOnDestroy` on all providers ([ecdaded](https://github.com/angular/angular/commit/ecdaded))
* **core:** support `ngOnDestroy` on providers of a directive. ([c161ed4](https://github.com/angular/angular/commit/c161ed4))
* **ExpressionChangedAfterItHasBeenCheckedException:** more meaningful error message ([2de8364](https://github.com/angular/angular/commit/2de8364)), closes [#9882](https://github.com/angular/angular/issues/9882)
* **ExpressionParser:** add support for `this` ([0ca05ee](https://github.com/angular/angular/commit/0ca05ee))
* **facade:** add support for all thenables ([#10278](https://github.com/angular/angular/issues/10278)) ([58d9e7f](https://github.com/angular/angular/commit/58d9e7f))
* **forms:** add ability to reset forms ([#9974](https://github.com/angular/angular/issues/9974)) ([da8eb9f](https://github.com/angular/angular/commit/da8eb9f)), closes [#4914](https://github.com/angular/angular/issues/4914) [#4933](https://github.com/angular/angular/issues/4933)
* **forms:** add get method for easy access to child controls ([#10428](https://github.com/angular/angular/issues/10428)) ([8d44999](https://github.com/angular/angular/commit/8d44999))
* **forms:** add invalid prop to abstract controls ([#10439](https://github.com/angular/angular/issues/10439)) ([e0eea6c](https://github.com/angular/angular/commit/e0eea6c))
* **forms:** add modules for forms and deprecatedForms ([#9859](https://github.com/angular/angular/issues/9859)) ([9d265b6](https://github.com/angular/angular/commit/9d265b6)), closes [#9732](https://github.com/angular/angular/issues/9732)
* **forms:** allow both patching and strict setting of values ([#10537](https://github.com/angular/angular/issues/10537)) ([fcafdff](https://github.com/angular/angular/commit/fcafdff))
* **forms:** updateValue() for form groups and form arrays ([#9901](https://github.com/angular/angular/issues/9901)) ([30a332e](https://github.com/angular/angular/commit/30a332e)), closes [#9553](https://github.com/angular/angular/issues/9553)
* **HtmlLexer:** better hint on unclosed ICU message errors ([4117836](https://github.com/angular/angular/commit/4117836)), closes [#10227](https://github.com/angular/angular/issues/10227)
* **http:** add content-type override support for http request ([#10211](https://github.com/angular/angular/issues/10211)) ([bdb5912](https://github.com/angular/angular/commit/bdb5912))
* **http:** add options method to Http ([#10540](https://github.com/angular/angular/issues/10540)) ([0bd97ec](https://github.com/angular/angular/commit/0bd97ec)), closes [#10500](https://github.com/angular/angular/issues/10500) [#7918](https://github.com/angular/angular/issues/7918)
* **http:** add support for ArrayBuffer ([1266460](https://github.com/angular/angular/commit/1266460))
* **http:** add support for blob as a response type ([#10190](https://github.com/angular/angular/issues/10190)) ([76b8a49](https://github.com/angular/angular/commit/76b8a49))
* **i18n:** merge translations ([7a8ef1e](https://github.com/angular/angular/commit/7a8ef1e))
* **i18n:** xmb serializer ([cc5cfe8](https://github.com/angular/angular/commit/cc5cfe8))
* **i18n:** xtb serializer ([0eee1d5](https://github.com/angular/angular/commit/0eee1d5))
* **I18nAst:** introduce an intermediate AST ([48f230a](https://github.com/angular/angular/commit/48f230a))
* **ICU:** enable ICU extraction even when when in is not used ([3050ae1](https://github.com/angular/angular/commit/3050ae1))
* **ICU:** extract ICU messages ([28e8b2f](https://github.com/angular/angular/commit/28e8b2f))
* **NgStyle:** add support for the style.unit notation ([#10496](https://github.com/angular/angular/issues/10496)) ([8b18ef4](https://github.com/angular/angular/commit/8b18ef4)), closes [#10326](https://github.com/angular/angular/issues/10326)
* **ngUpgrade:** add support for NgModules ([6b564ec](https://github.com/angular/angular/commit/6b564ec))
* **NumberPipe:** add string support ([#10163](https://github.com/angular/angular/issues/10163)) ([f3dd91e](https://github.com/angular/angular/commit/f3dd91e)), closes [#10159](https://github.com/angular/angular/issues/10159)
* **router:** activateroute should expose its route config ([2fdb39e](https://github.com/angular/angular/commit/2fdb39e))
* **router:** add a validation to make sure pathMatch is set correctly ([3c3e9dd](https://github.com/angular/angular/commit/3c3e9dd))
* **router:** add activate and deactivate events to RouterOutlet ([245b091](https://github.com/angular/angular/commit/245b091))
* **router:** add isActive to router ([5162fb6](https://github.com/angular/angular/commit/5162fb6))
* **router:** add parent, children, firstChild to ActivatedRoute ([550ab31](https://github.com/angular/angular/commit/550ab31))
* **router:** add queryParams and fragment to every activated route ([422d380](https://github.com/angular/angular/commit/422d380))
* **router:** add RouterAppModule ([8aa2a0c](https://github.com/angular/angular/commit/8aa2a0c))
* **router:** add RouterTestModule ([72544ba](https://github.com/angular/angular/commit/72544ba))
* **router:** add support for canActivateChild ([9e3d13f](https://github.com/angular/angular/commit/9e3d13f))
* **router:** add support for lazily loaded modules ([8ebb8e4](https://github.com/angular/angular/commit/8ebb8e4))
* **router:** add the ANALYZE_FOR_PRECOMPILE provider to make dev ergonomics better ([96a9e66](https://github.com/angular/angular/commit/96a9e66))
* **router:** Allow navigation without updating the URL ([#9608](https://github.com/angular/angular/issues/9608)) ([63b82cd](https://github.com/angular/angular/commit/63b82cd))
* **router:** empty-path routes should inherit matrix params ([a77db44](https://github.com/angular/angular/commit/a77db44))
* **router:** guards and data resolvers can now return promises ([a5dc570](https://github.com/angular/angular/commit/a5dc570))
* **router:** implement canLoad ([62e7c0f](https://github.com/angular/angular/commit/62e7c0f))
* **router:** rename UrlPathWithParams into UrlSegment ([6f68330](https://github.com/angular/angular/commit/6f68330))
* **router:** support sibling modules providing routes ([29caa37](https://github.com/angular/angular/commit/29caa37))
* **router:** update routerLink DSL to handle aux routes ([ded518d](https://github.com/angular/angular/commit/ded518d))
* **router:** update the example app to use lazily-loaded modules ([6fbe56d](https://github.com/angular/angular/commit/6fbe56d))
* **Router:** add extra validation for when route was passed as Array ([#9942](https://github.com/angular/angular/issues/9942)) ([aa88438](https://github.com/angular/angular/commit/aa88438))
* **security:** categorize <track src> as a regular URL. ([a441b5b](https://github.com/angular/angular/commit/a441b5b)), closes [#10089](https://github.com/angular/angular/issues/10089)
* **security:** only warn when actually sanitizing HTML. ([#10272](https://github.com/angular/angular/issues/10272)) ([482c019](https://github.com/angular/angular/commit/482c019)), closes [#10206](https://github.com/angular/angular/issues/10206)
* **security:** trust resource URLs as URLs. ([#10220](https://github.com/angular/angular/issues/10220)) ([51f3d22](https://github.com/angular/angular/commit/51f3d22))
* **testing:** add implicit test module ([8d746e3](https://github.com/angular/angular/commit/8d746e3)), closes [#9846](https://github.com/angular/angular/issues/9846)
* **xmb/xtb:** support dtd ([e34a04d](https://github.com/angular/angular/commit/e34a04d))
### BREAKING CHANGES
* core:
## Bootstrap changes
```
import {NgModule} from '@angular/core';
@NgModule({
declarations: […], // directives, components, and pipes owned by this NgModule
imports: [BrowserModule],
providers: […], // additional providers
boostrap: [MainComponent],
})
class MyAppModule {}
// Ahead of Time compile
import {platformBrowser} from @angular/platform-browser;
platformBrowser().bootstrapModuleFactory(MyAppModuleNgFactory);
// JIT compile long form
import {platformBrowserDynamic} from @angular/platform-browser-dynamic;
platformBrowserDynamic().bootstrapModule(MyAppModule);
```
* browser:
- short form bootstrap does no longer allow
to inject compiler internals (i.e. everything
from `@angular/compiler`). Inject `Compiler` instead.
* core:
- `ApplicationRef.waitForAsyncInitializers` is deprecated. Use
`AppInitStatus.donePromise` / `AppInitStatus.done` instead.
* core:
- `ApplicationRef.registerBootstrapListener` is deprecated. Provide a multi
provider for the new token `APP_BOOTSTRAP_LISTENER` instead.
* core:
- `ApplicationRef.dispose` is deprecated. Destroy the module that was
created during bootstrap instead by calling `NgModuleRef.destroy`.
- `AplicationRef.registerDisposeListener` is deprecated.
Use the `ngOnDestroy` lifecycle hook for providers or
`NgModuleRef.onDestroy` instead.
- `disposePlatform` is deprecated. Use `destroyPlatform` instead.
- `PlatformRef.dipose()` is deprecated. Use `PlatformRef.destroy()`
instead.
- `PlatformRef.registerDisposeListener` is deprecated. Use
`PlatformRef.onDestroy` instead.
- `PlaformRef.diposed` is deprecated. Use `PlatformRef.destroyed`
instead.
* testing:
* `withProviders`, use `TestBed.withModule` instead
* `addProviders`, use `TestBed.configureTestingModule` instead
* `TestComponentBuilder`, use `TestBed.configureTestModule` / `TestBed.override...` / `TestBed.createComponent` instead.
* core:
- ES5 users can no longer use the `View(…)` function to provide `ViewMetadata`.
This mirrors the removal of the `@View` decorator a while ago.
* core:
- `bootstrapModule` and `bootstrapModuleFactory` have been moved to be members of `PlaformRef`.
E.g. `platformBrowserDynamic().bootstrapModule(MyModule)`.
* core:
- By default, Angular will error during parsing
on unknown properties,
even if they are on elements with a `-` in their name
(aka custom elements). If you application is using
custom elements, fill the new parameter `@NgModule.schemas`
with the value `[CUSTOM_ELEMENTS_SCHEMA]`.
E.g. :
```
@NgModule({
declarations: [MyComponentThatUsesAWebComponent],
imports: [BrowserModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
boostrap: [MyComponentThatUsesAWebComponent],
})
export class MyAppModule{}
```
* core:
- `coreLoadAndBootstrap` and `coreBootstrap` can't be used any more (without migration support).
Use `bootstrapModule` / `bootstrapModuleFactory` instead.
- All Components listed in routes have to be part of the `declarations` of an NgModule.
Either directly on the bootstrap module / lazy loaded module, or in an NgModule imported by them.
* router:
`UrlPathWithParams` => `UrlSegment`
`UrlSegment` => `UrlSegmentGroup`
* core:
- `ApplicationRef.run` is deprecated. Use `NgZone.run` directly
- `ApplicationRef.injector` is deprecated. Inject an `Injector` or
use `NgModuleRef.injector` instead
- `ApplicationRef.zone` is deprecated. Inject `NgZone` instead.
* testing: `TestInjector` is now renamed to `TestBed`
Before:
```js
import {TestInjector, getTestInjector} from '@angular/core/testing';
```
After:
```js
import {TestBed, getTestBed} from '@angular/core/testing';
```
* http: The behavior in this commit is the same as before PR 7260 : the objects sent with the request are converted to a string, therefore there is no need for the user to take care of the serialization.
* platform-browser: The following API was never intended to be public and is removed:
```js
import {verifyNoBrowserErrors} from '@angular/platform-browser/testing_e2e';
```
Consider using Protractor's console plugin: https://github.com/angular/protractor-console-plugin
* ICU:
"{" is used a a delimiter for ICU messages then it could not be used in text nodes.
"{" should be escaped as "{{ '{' }}"
Before:
<span>some { valid } text</span>
After:
<span>some { invalid } text<span> <!-- throw parse error -->
<span>some {{ '{' }} valid } text</span>
* core: (deprecations)
- Instead of `coreBootstrap`, create an `@NgModule` and use `bootstrapModule`.
- Instead of `coreLoadAndBootstarp`, create an `@NgModule` and use `bootstrapModuleFactory`.
- Instead of `bootstrapWorkerApp`, create an `@NgModule` that includes the `WorkerAppModule` and use `bootstrapModule` with the `workerAppPlatform()`.
- Instead of `bootstrapWorkerUi`, create an @AppModule that includes the `WorkerUiModule` and use `bootstrapModule` with the `workerUiPlatform()` instead.
- Instead of `serverBootstrap`, create an @AppModule and use `bootstrapModule` with the `serverDynamicPlatform()` instead.
- Instead of `PLATFORM_PIPES` and `PLATFORM_DIRECTIVES`, provide platform directives/pipes via an `@NgModule`.
- Instead of `ComponentResolver`:
- use `ComponentFactoryResolver` together with `@NgModule.entryComponents` or `ANALYZE_FOR_ENTRY_COMPONENTS` provider for dynamic component creation.
- use `NgModuleFactoryLoader` for lazy loading.
- Instead of `SystemJsComponentResolver`, create an `@NgModule` and use `SystemJsNgModuleLoader`.
- Instead of `SystemJsCmpFactoryResolver`, create an `@NgModule` and use `SystemJsNgModuleFactoryLoader`
* core:
- `lockRunMode` is deprecated and no more needed.
* animations:
- animation trigger expressions within the template that are assigned as
an element attribute (e.g. `@prop`) are deprecated. Please use the
Angular2 property binding syntax (e.g. `[@prop]`) when assigning
properties.
```ts
// this is now deprecated
<div @trigger="expression"></div>
// do this instead
<div [@trigger]="expression"></div>
```
* forms:
We have removed the deprecated form directives from the built-in platform directive list, so apps are not required to package forms with their app. This also makes forms friendly to offline compilation.
Instead, we have exposed three modules:
OLD API:
- `DeprecatedFormsModule`
NEW API:
- `FormsModule`
- `ReactiveFormsModule`
If you provide one of these modules, the default forms directives and providers from that module will be available to you app-wide. Note: You can provide both the `FormsModule` and the `ReactiveFormsModule` together if you like, but they are fully-functional separately.
**Before:**
```ts
import {disableDeprecatedForms, provideForms} from @angular/forms;
bootstrap(App, [
disableDeprecatedForms(),
provideForms()
]);
```
**After:**
```ts
import {DeprecatedFormsModule} from @angular/common;
@NgModule({
declarations: [MyComponent],
imports: [BrowserModule, DeprecatedFormsModule],
boostrap: [MyComponent],
})
export class MyAppModule{}
```
* testing:
- Application providers can no longer inject compiler internals (i.e. everything
from `@angular/compiler`). Inject `Compiler` instead. This reflects the
changes to `bootstrap` for module support (3f55aa609f60f130f1d69188ed057214b1267cb3).
- Compiler providers can no longer be added via `addProviders` / `withProviders`.
Use the new method `configureCompiler` instead.
- Platform directives / pipes need to be provided via
`configureModule` and can no longer be provided via the
`PLATFORM_PIPES` / `PLATFORM_DIRECTIVES` tokens.
- `setBaseTestProviders()` was renamed into `initTestEnvironment` and
now takes a `PlatformRef` and a factory for a
`Compiler`.
- E.g. for the browser platform:
BEFORE:
```
import {setBaseTestProviders} from @angular/core/testing;
import {TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS} from @angular/platform-browser-dynamic/testing;
setBaseTestProviders(TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS);
```
AFTER:
```
import {TestBed} from @angular/core/testing;
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from @angular/platform-browser-dynamic/testing;
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
```
- E.g. for the server platform:
BEFORE:
```
import {setBaseTestProviders} from @angular/core/testing;
import {TEST_SERVER_PLATFORM_PROVIDERS,
TEST_SERVER_APPLICATION_PROVIDERS} from @angular/platform-server/testing/server;
setBaseTestProviders(TEST_SERVER_PLATFORM_PROVIDERS,
TEST_SERVER_APPLICATION_PROVIDERS);
```
AFTER:
```
import {TestBed} from @angular/core/testing;
import {ServerTestingModule, serverTestingPlatform} from @angular/platform-browser-dynamic/testing;
TestBed.initTestEnvironment(
ServerTestingModule,
serverTestingPlatform()
);
```
Related to #9726
* router: Previously both imperative (router.navigate) and declarative (routerLink) navigations
would preserve the current query params and fragment. This behavior turned out to
be confusing. This commit changes it.
Now, neither is preserved by default. To preserve them, you need to do the following:
`router.naviage("newUrl", {preserveQueryParams: true, preserveFragment: true})`
`<a routerLink="newUrl" preserveQueryParams preserveFragment></a>`
* ngUpgrade: UpgradeAdapter.addProvider are now deprecated in favor of passing in an NgModule into the adapter's constructor
Before:
```
let upgradeAdapter = new UpgradeAdapter();
upgradeAdapter.addProviders([myProvidersArray);
```
After:
```
@NgModule({
providers: myProvidersArray
})
class MyModule {}
let upgradeAdapter = new UpgradeAdapter(MyModule);
```
<a name="2.0.0-rc.4"></a>
# [2.0.0-rc.4](https://github.com/angular/angular/compare/2.0.0-rc.3...2.0.0-rc.4) (2016-06-30)
### Bug Fixes
* **animations:** ensure void => * animations are triggered when an expression is omitted ([e0b0a59](https://github.com/angular/angular/commit/e0b0a59)), closes [#9327](https://github.com/angular/angular/issues/9327) [#9381](https://github.com/angular/angular/issues/9381)
* **animations:** make sure the easing value is passed into the web-animations player ([c43aec2](https://github.com/angular/angular/commit/c43aec2)), closes [#9517](https://github.com/angular/angular/issues/9517) [#9523](https://github.com/angular/angular/issues/9523)
* **common:** add license header to localization.ts ([5150344](https://github.com/angular/angular/commit/5150344))
* **common/testing:** remove internal MockLocationStrategy from common/testing ([#9562](https://github.com/angular/angular/issues/9562)) ([dcf7512](https://github.com/angular/angular/commit/dcf7512))
* **compiler:** don't inject `viewProviders` into content child elements ([9ed8f2d](https://github.com/angular/angular/commit/9ed8f2d))
* **compiler:** make code easier to type check ([51d4c9d](https://github.com/angular/angular/commit/51d4c9d)), closes [#9701](https://github.com/angular/angular/issues/9701)
* **compiler:** report not existing files as errors ([e81dea6](https://github.com/angular/angular/commit/e81dea6)), closes [#9690](https://github.com/angular/angular/issues/9690)
* **Compiler:** relax childIsRecursive check ([#8705](https://github.com/angular/angular/issues/8705)) ([3d5bb23](https://github.com/angular/angular/commit/3d5bb23))
* **core:** improve error message for broken bindings ([df759b8](https://github.com/angular/angular/commit/df759b8)), closes [#6820](https://github.com/angular/angular/issues/6820) [#9536](https://github.com/angular/angular/issues/9536)
* **core:** properly report missing providers and viewProviders ([#9411](https://github.com/angular/angular/issues/9411)) ([f114dd3](https://github.com/angular/angular/commit/f114dd3)), closes [#8237](https://github.com/angular/angular/issues/8237)
* **core:** report duplicate template bindings in templates ([098b461](https://github.com/angular/angular/commit/098b461)), closes [#7315](https://github.com/angular/angular/issues/7315) [#9462](https://github.com/angular/angular/issues/9462)
* **core/testing:** clean up the core testing public API ([#9466](https://github.com/angular/angular/issues/9466)) ([8a9e9c7](https://github.com/angular/angular/commit/8a9e9c7))
* **core/testing:** move ComponentFixture to core ([#9386](https://github.com/angular/angular/issues/9386)) ([1143b03](https://github.com/angular/angular/commit/1143b03))
* **core/testing compiler/testing:** move TestComponentBuilder to core/testing ([#9590](https://github.com/angular/angular/issues/9590)) ([a33195d](https://github.com/angular/angular/commit/a33195d)), closes [#9585](https://github.com/angular/angular/issues/9585)
* **forms:** add select multiple accessor as built-in accessor ([9f00a1b](https://github.com/angular/angular/commit/9f00a1b))
* **forms:** async validator-directives process Observables correctly ([#8186](https://github.com/angular/angular/issues/8186)) ([eef9512](https://github.com/angular/angular/commit/eef9512))
* **forms:** emit statusChange when child controls have async validator ([#9652](https://github.com/angular/angular/issues/9652)) ([797914e](https://github.com/angular/angular/commit/797914e))
* **forms:** make radio button selection logic more flexible ([#9646](https://github.com/angular/angular/issues/9646)) ([ed0ade6](https://github.com/angular/angular/commit/ed0ade6)), closes [#9558](https://github.com/angular/angular/issues/9558)
* **forms:** ngModel should emit valueChanges and statusChanges asynchronously ([97a2119](https://github.com/angular/angular/commit/97a2119))
* **http:** add search param escaping for keys ([#9166](https://github.com/angular/angular/issues/9166)) ([a5f2e20](https://github.com/angular/angular/commit/a5f2e20))
* **http:** don't encode values that are allowed in query ([#9651](https://github.com/angular/angular/issues/9651)) ([1620426](https://github.com/angular/angular/commit/1620426)), closes [#9348](https://github.com/angular/angular/issues/9348)
* **ngc:** correct dependencies for compiler-cli ([826f89f](https://github.com/angular/angular/commit/826f89f)), closes [#9540](https://github.com/angular/angular/issues/9540)
* **ngc:** work with typescript[@next](https://github.com/next) ([f463e09](https://github.com/angular/angular/commit/f463e09))
* **NgSwitch:** display deprecation message only once ([398060d](https://github.com/angular/angular/commit/398060d))
* **platform-browser/testing:** clean up public api for platform-browser/testing ([#9519](https://github.com/angular/angular/issues/9519)) ([3d8eb8c](https://github.com/angular/angular/commit/3d8eb8c))
* **platform-browser/testing-e2e:** clean up unused exports from e2e testing helpers ([#9387](https://github.com/angular/angular/issues/9387)) ([894747c](https://github.com/angular/angular/commit/894747c))
* **public API:** update golden files ([ae4fa56](https://github.com/angular/angular/commit/ae4fa56))
* **security:** allow empty CSS values. ([#9675](https://github.com/angular/angular/issues/9675)) ([2d9d7f1](https://github.com/angular/angular/commit/2d9d7f1))
* **security:** no warning when sanitizing escaped html ([#9392](https://github.com/angular/angular/issues/9392)) ([#9413](https://github.com/angular/angular/issues/9413)) ([98cef76](https://github.com/angular/angular/commit/98cef76))
* **testing:** remove the `toMatchPattern` matcher (jasmine has `toMatch`) ([6420f75](https://github.com/angular/angular/commit/6420f75))
* public api surface fixes + stability markers ([24eb838](https://github.com/angular/angular/commit/24eb838)), closes [#9236](https://github.com/angular/angular/issues/9236) [#9235](https://github.com/angular/angular/issues/9235)
* support *directive on `<template>` ([#9691](https://github.com/angular/angular/issues/9691)) ([3fec279](https://github.com/angular/angular/commit/3fec279)), closes [#7315](https://github.com/angular/angular/issues/7315)
* **testing:** remove the `toThrowErrorWith` matcher (jasmine has `toThrowError`) ([e1e5c40](https://github.com/angular/angular/commit/e1e5c40))
* **typings:** don't test compiler-cli typings on TS 1.8 ([54dbed4](https://github.com/angular/angular/commit/54dbed4))
* **upgrade:** add peerDependency on platform-browser-dynamic ([#9674](https://github.com/angular/angular/issues/9674)) ([e2116c5](https://github.com/angular/angular/commit/e2116c5)), closes [#9623](https://github.com/angular/angular/issues/9623)
### Features
* **compiler:** support sync runtime compile ([bf598d6](https://github.com/angular/angular/commit/bf598d6)), closes [#7084](https://github.com/angular/angular/issues/7084) [#9594](https://github.com/angular/angular/issues/9594)
* **core:** add `[@Component](https://github.com/Component).precompile` and `ComponentFactoryResolver` ([6c5b653](https://github.com/angular/angular/commit/6c5b653)), closes [#9543](https://github.com/angular/angular/issues/9543)
* **core:** split ChangeDetectorStrategy into ChangeDetectionStrategy and ChangeDetectorStatus ([e12b127](https://github.com/angular/angular/commit/e12b127))
* **DomRenderer:** Adding support for document fragments in SVG foreign objects ([#9458](https://github.com/angular/angular/issues/9458)) ([3644eef](https://github.com/angular/angular/commit/3644eef))
* **forms:** add support for formArrayName ([c03e1f2](https://github.com/angular/angular/commit/c03e1f2)), closes [#9251](https://github.com/angular/angular/issues/9251)
* **forms:** add support for standalone ngModel dirs inside forms ([6edf047](https://github.com/angular/angular/commit/6edf047)), closes [#9230](https://github.com/angular/angular/issues/9230)
* **forms:** expose ValidatorFn and AsyncValidatorFn ([17dcbf6](https://github.com/angular/angular/commit/17dcbf6)), closes [#8834](https://github.com/angular/angular/issues/8834)
* **forms:** make valueChanges and statusChanges available on abstract control directives ([de12710](https://github.com/angular/angular/commit/de12710))
* **forms:** support updating of validators on exiting controls ([#9516](https://github.com/angular/angular/issues/9516)) ([638fd74](https://github.com/angular/angular/commit/638fd74))
* **forms:** use formControlName on radio buttons when name is absent ([#9681](https://github.com/angular/angular/issues/9681)) ([0961bd1](https://github.com/angular/angular/commit/0961bd1))
* **QueryList:** implement some() ([#9464](https://github.com/angular/angular/issues/9464)) ([f6a410a](https://github.com/angular/angular/commit/f6a410a)), closes [#9443](https://github.com/angular/angular/issues/9443)
* **router:** add pathMatch property to replace terminal ([fcfddbf](https://github.com/angular/angular/commit/fcfddbf))
* **router:** implement data and resolve ([f2f1ec0](https://github.com/angular/angular/commit/f2f1ec0))
* **router:** use componentFactoryResolver ([dc64e90](https://github.com/angular/angular/commit/dc64e90))
* **security:** allow more HTML5 elements and attributes in sanitizers ([6605eb3](https://github.com/angular/angular/commit/6605eb3)), closes [#9438](https://github.com/angular/angular/issues/9438)
### BREAKING CHANGES
* http: The changes to Http's URLSearchParams serialization now
prevent encoding of these characters inside query parameters
which were previously converted to percent-encoded values `@ : $ , ; + ; ? /`
The default encoding behavior can be overridden by extending
QueryEncoder, as documented in the URLSearchParams service.
* Previously multiple template bindings on one element
(ex. `<div *ngIf='..' *ngFor='...'>`) were allowed but most of the time
were leading to undesired result. It is possible that a small number
of applications will see template parse errors that should be fixed by
nesting elements or using `<template>` tags explicitly.
* DomEventsPlugin and KeyEventsPlugin previously exported from core are no longer public - these classes are implementation detail.
Previously deprecated BROWSER_PROVIDERS was completely removed from platform-browser.
* core/testing compiler/testing: `TestComponentBuilder` is now imported from `@angular/core/testing`. Imports
from `@angular/compiler/testing` are deprecated.
Before:
```
import {TestComponentBuilder, TestComponentRenderer, ComponentFixtureAutoDetect} from '@angular/compiler/testing';
```
After:
```
import {TestComponentBuilder, TestComponentRenderer, ComponentFixtureAutoDetect} from '@angular/core/testing';
```
* common/testing: MockLocationStrategy was intended to be internal only and is now removed
from the `@angular/common/testing` public api.
Use `SpyLocation` from `@angular/common/testing` for location testing.
* compiler: `TestComponentBuilder.createSync` now takes a component type
and throws if not all templates are either inlined
are compiled before via `createAsync`.
* core/testing: Remove the following APIs from `@angular/core/testing`, which have been deprecated or were
never intended to be publicly exported:
```
injectAsync
clearPendingTimers
Log
MockAppliacationHref
MockNgZone
clearPendingTimers
getTypeOf
instantiateType
```
Instead of `injectAsync`, use `async(inject())`.
`clearPendingTimers` is no longer required.
* platform-browser/testing: The following are no longer publicly exported APIs. They were intended as internal
utilities and you should use your own util:
```
browserDetection,
dispatchEvent,
el,
normalizeCSS,
stringifyElement,
expect (and custom matchers for Jasmine)
```
* testing:
Before:
expect(...).toThrowErrorWith(msg);
After:
expect(...).toThrowError(msg);
Before:
expect(...).toMatchPattern(pattern);
After:
expect(...).toMatch(pattern);
* core/testing: `ComponentFixture` will be moving out of `@angular/compiler/testing` to `@angular/core/testing` in
this release. For now, it is deprecated from `@angular/compiler/testing`.
* The async function now determines whether it should return a promise
or instead call a done function parameter. Importing Jasmine functions
from `@angular/core/testing` is no longer necessary and is now deprecated.
Additionally, beforeEachProviders is also deprecated, as it is specific
to the testing framework. Instead, use the new addProviders method directly.
Before:
```js
import {beforeEachProviders, it, describe, inject} from '@angular/core/testing';
describe('my code', () => {
beforeEachProviders(() => [MyService]);
it('does stuff', inject([MyService], (service) => {
// actual test
});
});
```
After:
```js
import {addProviders, inject} from '@angular/core/testing';
describe('my code', () => {
beforeEach(() => {
addProviders([MyService]);
});
it('does stuff', inject([MyService], (service) => {
// actual test
});
});
```
<a name="2.0.0-rc.3"></a>
# 2.0.0-rc.3 (2016-06-21)
### Bug Fixes
* **animations:** ensure starting styles are applied when a delay is present ([ba46ca6](https://github.com/angular/angular/commit/ba46ca6)), closes [#9326](https://github.com/angular/angular/issues/9326) [#9328](https://github.com/angular/angular/issues/9328)
* **BrowserUtil:** fix `supportsIntlApi()` ([76a4187](https://github.com/angular/angular/commit/76a4187))
* **change_detection:** ChangeDetectorRef reattach should restore original mode ([773c349](https://github.com/angular/angular/commit/773c349)), closes [#7078](https://github.com/angular/angular/issues/7078) [#7080](https://github.com/angular/angular/issues/7080)
* **compiler:** codegen view query generic types ([e157a06](https://github.com/angular/angular/commit/e157a06))
* **compiler:** properly report unresolved dependencies ([fdf6bc1](https://github.com/angular/angular/commit/fdf6bc1)), closes [#9332](https://github.com/angular/angular/issues/9332) [#9341](https://github.com/angular/angular/issues/9341)
* **compiler:** StaticReflector ignores unregistered decorators. (#9266) ([791153c](https://github.com/angular/angular/commit/791153c)), closes [#9265](https://github.com/angular/angular/issues/9265)
* **core/testing:** show full error ([297f0fd](https://github.com/angular/angular/commit/297f0fd))
* **forms:** ngModel should export as ngModel ([8e6e90e](https://github.com/angular/angular/commit/8e6e90e))
* **guards:** Cancel in-flight guards if one returns false ([97cf0e4](https://github.com/angular/angular/commit/97cf0e4))
* **HtmlParser:** add missing ; ([c60ef45](https://github.com/angular/angular/commit/c60ef45))
* **HtmlParser:** consider `<ng-container>` when adding required parents ([9ba400d](https://github.com/angular/angular/commit/9ba400d))
* **HtmlParser:** do not add required parents to template root elements ([e484c62](https://github.com/angular/angular/commit/e484c62)), closes [#5967](https://github.com/angular/angular/issues/5967)
* **HTTP/XhrBackend:** correctly set the status code on errors (#9355) ([12c4904](https://github.com/angular/angular/commit/12c4904)), closes [angular/http#54](https://github.com/angular/http/issues/54)
* **NumberPipe:** fix broken RegExp ([49bf3f5](https://github.com/angular/angular/commit/49bf3f5))
* **partition:** fix partition when `<!-- i18n -->` is the only child ([58b18d7](https://github.com/angular/angular/commit/58b18d7))
* **perf:** support prod mode again ([c0f2a22](https://github.com/angular/angular/commit/c0f2a22)), closes [#9318](https://github.com/angular/angular/issues/9318) [#8508](https://github.com/angular/angular/issues/8508) [#9318](https://github.com/angular/angular/issues/9318)
* **platform-server:** cleanup public api of platform-server ([8675b8d](https://github.com/angular/angular/commit/8675b8d)), closes [#9237](https://github.com/angular/angular/issues/9237) [#9205](https://github.com/angular/angular/issues/9205)
* **upgrade:** fix bundling issue and fix e2e test ([8c076d5](https://github.com/angular/angular/commit/8c076d5)), closes [#9244](https://github.com/angular/angular/issues/9244)
* **XmbSerializer:** add meaning attribute, escape attribute values ([c9c81e1](https://github.com/angular/angular/commit/c9c81e1))
### Features
* **benchpress:** add custom user metric to benchpress ([6686bc6](https://github.com/angular/angular/commit/6686bc6)), closes [#9229](https://github.com/angular/angular/issues/9229)
* **compiler:** make interpolation symbols configurable (`@Component` config) (#9367) ([1b28cf7](https://github.com/angular/angular/commit/1b28cf7)), closes [#9158](https://github.com/angular/angular/issues/9158)
* **compiler-cli:** add a `debug` option to control the output ([1eaa193](https://github.com/angular/angular/commit/1eaa193)), closes [#9208](https://github.com/angular/angular/issues/9208)
* **core:** ensure CSS parser tracks start/end values and understands complex pseudo selecto ([935c39a](https://github.com/angular/angular/commit/935c39a))
* **datePipe:** numeric string support ([5c8d315](https://github.com/angular/angular/commit/5c8d315))
* **DomElementSchemaRegistry:** add support for `<ng-content>` and `<ng-container>` ([b620f4f](https://github.com/angular/angular/commit/b620f4f))
* **I18N Expander:** do not add extra `<ul>` & `<li>` around ICU messages (#9283) ([721f53f](https://github.com/angular/angular/commit/721f53f)), closes [#9072](https://github.com/angular/angular/issues/9072)
* **MessageExtractor:** do not expand ICU messages before extraction ([04a50f5](https://github.com/angular/angular/commit/04a50f5))
* **QueryList:** support index in callbacks ([5fe6075](https://github.com/angular/angular/commit/5fe6075)), closes [#9278](https://github.com/angular/angular/issues/9278)
* **radio:** support radio button sharing a control ([39e0b49](https://github.com/angular/angular/commit/39e0b49))
* **security:** fail more detectably when using a safe value in an interpolation. ([8879aa1](https://github.com/angular/angular/commit/8879aa1))
### BREAKING CHANGES
* Parse5Adapter is no longer exported as public API, use serverBootstrap()
Parse5Adapter is an implementation detail not a public API
* `containsRegexp` is no more exported from `@angular/core/testing`. It should not have been part of the public API in the first place.
<a name="2.0.0-rc.2"></a>
# 2.0.0-rc.2 (2016-06-15)
@ -714,7 +1440,7 @@ After:
* **i18n:** add ngPlural directive ([df1f78e](https://github.com/angular/angular/commit/df1f78e))
* **i18n:** implement a simple version of message extractor ([095db67](https://github.com/angular/angular/commit/095db67)), closes [#7454](https://github.com/angular/angular/issues/7454)
* **shadow_css:** support `/deep/` and `>>>` ([cb38d72](https://github.com/angular/angular/commit/cb38d72)), closes [#7562](https://github.com/angular/angular/issues/7562) [#7563](https://github.com/angular/angular/issues/7563)
* **TAG_DEFINITIONS:** include <meta> and <base> ([2c7c3e3](https://github.com/angular/angular/commit/2c7c3e3)), closes [#7455](https://github.com/angular/angular/issues/7455)
* **TAG_DEFINITIONS:** include `<meta>` and `<base>` ([2c7c3e3](https://github.com/angular/angular/commit/2c7c3e3)), closes [#7455](https://github.com/angular/angular/issues/7455)
### BREAKING CHANGES
@ -903,7 +1629,7 @@ And install typings such as `jasmine`, `angular-protractor`, or `selenium-webdri
to satisfy the type-checker.
If you rely on es6 APIs other than Promises and Collections, you will need to
install the es6-shim typing instead of using the <reference> tag above.
install the es6-shim typing instead of using the `<reference>` tag above.
Angular previously exposed typings for the entire ES6 API.
<a name="2.0.0-beta.5"></a>
@ -935,7 +1661,7 @@ This release was incorrect; replaced with beta.6.
### Features
* **change_detection:** allow all legal programs in the dev mode ([42231f5](https://github.com/angular/angular/commit/42231f5))
* **dart/transform:** Generate all code into <file>.template.dart ([8c36aa8](https://github.com/angular/angular/commit/8c36aa8))
* **dart/transform:** Generate all code into `<file>.template.dart` ([8c36aa8](https://github.com/angular/angular/commit/8c36aa8))
* **debug:** replace DebugElement with new Debug DOM ([e1bf3d3](https://github.com/angular/angular/commit/e1bf3d3))
* **ngFor:** add custom trackBy function support ([cee2318](https://github.com/angular/angular/commit/cee2318)), closes [#6779](https://github.com/angular/angular/issues/6779)
* **upgrade:** support bindToController with binding definitions ([99e6500](https://github.com/angular/angular/commit/99e6500)), closes [#4784](https://github.com/angular/angular/issues/4784)
@ -1304,7 +2030,7 @@ Use imports from `angular2/compiler` instead.
* **HtmlLexer:** tag name must follow "<" without space ([47f1d12](https://github.com/angular/angular/commit/47f1d12))
* **HtmlParser:** Do not add parent element for template children ([3a43861](https://github.com/angular/angular/commit/3a43861)), closes [#5638](https://github.com/angular/angular/issues/5638)
* **HtmlParser:** ignore LF immediately following pre, textarea & listing ([eb0ea93](https://github.com/angular/angular/commit/eb0ea93)), closes [#5630](https://github.com/angular/angular/issues/5630) [#5688](https://github.com/angular/angular/issues/5688)
* **HtmlParser:** mark <source> elements as void ([50490b5](https://github.com/angular/angular/commit/50490b5)), closes [#5663](https://github.com/angular/angular/issues/5663) [#5668](https://github.com/angular/angular/issues/5668)
* **HtmlParser:** mark `<source>` elements as void ([50490b5](https://github.com/angular/angular/commit/50490b5)), closes [#5663](https://github.com/angular/angular/issues/5663) [#5668](https://github.com/angular/angular/issues/5668)
* **npm:** move es6-shim from devDependencies to dependencies ([21542ed](https://github.com/angular/angular/commit/21542ed))
* **package:** relock RxJS to alpha.11 ([4b1618c](https://github.com/angular/angular/commit/4b1618c)), closes [#5643](https://github.com/angular/angular/issues/5643) [#5644](https://github.com/angular/angular/issues/5644)
* **router:** set correct redirect/default URL from hashchange ([aa85856](https://github.com/angular/angular/commit/aa85856)), closes [#5590](https://github.com/angular/angular/issues/5590) [#5683](https://github.com/angular/angular/issues/5683)
@ -2291,7 +3017,7 @@ class HelloCmp implements OnInit {
* **http/http:** allow for commonjs as ngHttp ([16eb8ce](https://github.com/angular/angular/commit/16eb8ce)), closes [#3633](https://github.com/angular/angular/issues/3633)
* **injector:** support getRootInjectors on dehydrated injectors. ([92da543](https://github.com/angular/angular/commit/92da543)), closes [#3760](https://github.com/angular/angular/issues/3760)
* **injectors:** reset the construction counter in dynamic strategy. ([272ad61](https://github.com/angular/angular/commit/272ad61)), closes [#3635](https://github.com/angular/angular/issues/3635)
* <template> tag for browsers that do not suppor them ([ddcfd46](https://github.com/angular/angular/commit/ddcfd46)), closes [#3636](https://github.com/angular/angular/issues/3636)
* `<template>` tag for browsers that do not suppor them ([ddcfd46](https://github.com/angular/angular/commit/ddcfd46)), closes [#3636](https://github.com/angular/angular/issues/3636)
* **karma:** corrected race condition with RX loading ([8dc509f](https://github.com/angular/angular/commit/8dc509f))
* **parser:** detect and report interpolation in expressions ([b039ec3](https://github.com/angular/angular/commit/b039ec3)), closes [#3645](https://github.com/angular/angular/issues/3645) [#3750](https://github.com/angular/angular/issues/3750)
* **router:** allow router-link to link to redirects ([72e0b8f](https://github.com/angular/angular/commit/72e0b8f)), closes [#3335](https://github.com/angular/angular/issues/3335) [#3624](https://github.com/angular/angular/issues/3624)

View File

@ -95,7 +95,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
* In GitHub, send a pull request to `angular:master`.
* If we suggest changes then:
* Make the required updates.
* Re-run the Angular 2 test suites for JS and Dart to ensure tests are still passing.
* Re-run the Angular 2 test suites to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
```shell

View File

@ -5,15 +5,9 @@ JS and Dart versions. It also explains the basic mechanics of using `git`, `node
* [Prerequisite Software](#prerequisite-software)
* [Getting the Sources](#getting-the-sources)
* [Environment Variable Setup](#environment-variable-setup)
* [Installing NPM Modules and Dart Packages](#installing-npm-modules-and-dart-packages)
* [Build commands](#build-commands)
* [Installing NPM Modules](#installing-npm-modules)
* [Building](#building)
* [Running Tests Locally](#running-tests-locally)
* [Code Style](#code-style)
* [Project Information](#project-information)
* [CI using Travis](#ci-using-travis)
* [Transforming Dart code](#transforming-dart-code)
* [Debugging](#debugging)
See the [contribution guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md)
if you'd like to contribute to Angular.
@ -32,15 +26,6 @@ following products on your development machine:
(version `>=3.5.3 <4.0`), which comes with Node. Depending on your system, you can install Node either from
source or as a pre-packaged bundle.
* *Optional*: [Dart](https://www.dartlang.org) (version `>=1.13.2 <2.0.0`), specifically the Dart SDK and
Dartium (a version of [Chromium](http://www.chromium.org) with native support for Dart through
the Dart VM). Visit Dart's [Downloads page](https://www.dartlang.org/downloads) page for
instructions. You can also download both **stable** and **dev** channel versions from the
[download archive](https://www.dartlang.org/downloads/archive/). In that case, on Windows, Dart
must be added to the `PATH` (e.g. `path-to-dart-sdk-folder\bin`) and a new `DARTIUM_BIN`
environment variable must be created, pointing to the executable (e.g.
`path-to-dartium-folder\chrome.exe`).
* [Java Development Kit](http://www.oracle.com/technetwork/es/java/javase/downloads/index.html) which is used
to execute the selenium standalone server for e2e testing.
@ -65,42 +50,7 @@ cd angular
# Add the main Angular repository as an upstream remote to your repository:
git remote add upstream https://github.com/angular/angular.git
```
## Environment Variable Setup
Define the environment variables listed below. These are mainly needed for the testing. The
notation shown here is for [`bash`](http://www.gnu.org/software/bash); adapt as appropriate for
your favorite shell.
Examples given below of possible values for initializing the environment variables assume **Mac OS
X** and that you have installed the Dart Editor in the directory named by
`DART_EDITOR_DIR=/Applications/dart`. This is only for illustrative purposes.
```shell
# DARTIUM_BIN: path to a Dartium browser executable; used by Karma to run Dart tests
export DARTIUM_BIN="$DART_EDITOR_DIR/chromium/Chromium.app/Contents/MacOS/Chromium"
```
Add the Dart SDK `bin` directory to your path and/or define `DART_SDK` (this is also detailed
[here](https://www.dartlang.org/tools/pub/installing.html)):
```shell
# DART_SDK: path to a Dart SDK directory
export DART_SDK="$DART_EDITOR_DIR/dart-sdk"
# Update PATH to include the Dart SDK bin directory
PATH+=":$DART_SDK/bin"
```
And specify where the pubs dependencies are downloaded. By default, this directory is located under .pub_cache
in your home directory (on Mac and Linux), or in AppData\Roaming\Pub\Cache (on Windows).
```shell
# PUB_CACHE: location of pub dependencies
export PUB_CACHE="/Users/<user>/.pub-cache"
```
## Installing NPM Modules and Dart Packages
## Installing NPM Modules
Next, install the JavaScript modules and Dart packages needed to build and test Angular:
@ -124,243 +74,67 @@ use in these instructions.
*Option 2*: defining a bash alias like `alias nbin='PATH=$(npm bin):$PATH'` as detailed in this
[Stackoverflow answer](http://stackoverflow.com/questions/9679932/how-to-use-package-installed-locally-in-node-modules/15157360#15157360) and used like this: e.g., `nbin gulp build`.
## Build commands
To build Angular and prepare tests, run:
## Windows only
In order to create the right symlinks, run **as administrator**:
```shell
$(npm bin)/gulp build
./scripts/windows/create-symlinks.sh
```
Notes:
* Results are put in the `dist` folder.
* This will also run `pub get` for the subfolders in `modules` and run `dartanalyzer` for
every file that matches `<module>/src/<module>.dart`, e.g. `di/src/di.dart`.
Before submitting a PR, do not forget to remove them:
```shell
./scripts/windows/remove-symlinks.sh
```
You can selectively build either the JS or Dart versions as follows:
## Building
* `$(npm bin)/gulp build.js`
* `$(npm bin)/gulp build.dart`
To clean out the `dist` folder, run:
To build Angular run:
```shell
$(npm bin)/gulp clean
./build.sh
```
* Results are put in the dist folder.
## Running Tests Locally
### Full test suite
* `npm test`: full test suite for both JS and Dart versions of Angular. These are the same tests
that run on Travis.
You can selectively run either the JS or Dart versions as follows:
* `$(npm bin)/gulp test.all.js`
* `$(npm bin)/gulp test.all.dart`
### Unit tests
You can run just the unit tests as follows:
* `$(npm bin)/gulp test.unit.js`: JS tests in a browser; runs in **watch mode** (i.e.
watches the test files for changes and re-runs tests when files are updated).
* `$(npm bin)/gulp test.unit.cjs`: JS tests in NodeJS; runs in **watch mode**.
* `$(npm bin)/gulp test.unit.dart`: Dart tests in Dartium; runs in **watch mode**.
If you prefer running tests in "single-run" mode rather than watch mode use:
* `$(npm bin)/gulp test.unit.js/ci`
* `$(npm bin)/gulp test.unit.cjs/ci`
* `$(npm bin)/gulp test.unit.dart/ci`
The task updates the dist folder with transpiled code whenever a source or test file changes, and
Karma is run against the new output.
**Note**: If you want to only run a single test you can alter the test you wish to run by changing
`it` to `iit` or `describe` to `ddescribe`. This will only run that individual test and make it
much easier to debug. `xit` and `xdescribe` can also be useful to exclude a test and a group of
tests respectively.
**Note**: **watch mode** needs symlinks to work, so if you're using Windows, ensure you have the
rights to built them in your operating system. On Windows, only administrators can create symbolic links by default, but you may change the policy. (see [here](https://technet.microsoft.com/library/cc766301.aspx?f=255&MSPPError=-2147217396).)
### Unit tests with Sauce Labs or Browser Stack
First, in a terminal, create a tunnel with [Sauce Connect](https://docs.saucelabs.com/reference/sauce-connect/) or [Browser Stack Local](https://www.browserstack.com/local-testing#command-line), and valid credentials.
Then, in another terminal:
- Define the credentials as environment variables, e.g.:
```
export SAUCE_USERNAME='my_user'; export SAUCE_ACCESS_KEY='my_key';
export BROWSER_STACK_USERNAME='my_user'; export BROWSER_STACK_ACCESS_KEY='my_key';
```
- Then run `gulp test.unit.js.(sauce|browserstack) --browsers=option1,option2,..,optionN`
The options are any mix of browsers and aliases which are defined in the [browser-providers.conf.js](https://github.com/angular/angular/blob/master/browser-providers.conf.js) file.
They are case insensitive, and the `SL_` or `BS_` prefix must not be added for browsers.
Some examples of commands:
```
gulp test.unit.js.sauce --browsers=Safari8,ie11 //run in Sauce Labs with Safari 8 and IE11
gulp test.unit.js.browserstack --browsers=Safari,IE //run in Browser Stack with Safari 7, Safari 8, Safari 9, IE 9, IE 10 and IE 11
gulp test.unit.js.sauce --browsers=IOS,safari8,android5.1 //run in Sauce Labs with iOS 7, iOS 8, iOs 9, Safari 8 and Android 5.1
```
### E2E tests
1. `$(npm bin)/gulp build.js.cjs` (builds benchpress and tests into `dist/js/cjs` folder).
2. `$(npm bin)/gulp serve.js.prod serve.dart` (runs a local webserver).
3. `$(npm bin)/protractor protractor-js.conf.js`: JS e2e tests.
4. `$(npm bin)/protractor protractor-dart2js.conf.js`: dart2js e2e tests.
Angular specific command line options when running protractor:
- `$(npm bin)/protractor protractor-{js|dart2js}-conf.js --ng-help`
### Performance tests
1. `$(npm bin)/gulp build.js.cjs` (builds benchpress and tests into `dist/js/cjs` folder)
2. `$(npm bin)/gulp serve.js.prod serve.dart` (runs a local webserver)
3. `$(npm bin)/protractor protractor-js.conf.js --benchmark`: JS performance tests
4. `$(npm bin)/protractor protractor-dart2js.conf.js --benchmark`: dart2js performance tests
Angular specific command line options when running protractor (e.g. force gc, ...):
`$(npm bin)/protractor protractor-{js|dart2js}-conf.js --ng-help`
## Code Style
### Formatting with <a name="clang-format">clang-format</a>
We use [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to automatically enforce code
style for our TypeScript code. This allows us to focus our code reviews more on the content, and
less on style nit-picking. It also lets us encode our style guide in the `.clang-format` file in the
repository, allowing many tools and editors to share our settings.
To check the formatting of your code, run
gulp lint
Note that the continuous build on CircleCI will fail the build if files aren't formatted according
to the style guide.
Your life will be easier if you include the formatter in your standard workflow. Otherwise, you'll
likely forget to check the formatting, and waste time waiting for a build on Travis that fails due
to some whitespace difference.
* Use `gulp format` to format everything.
* Use `gulp lint` to check if your code is `clang-format` clean. This also gives
you a command line to format your code.
* `clang-format` also includes a git hook, run `git clang-format` to format all files you
touched.
* You can run this as a **git pre-commit hook** to automatically format your delta regions when you
commit a change. In the angular repo, run
```
$ echo -e '#!/bin/sh\nexec git clang-format --style file' > .git/hooks/pre-commit
$ chmod u+x !$
```
**NOTE**: To use ```git clang-format``` use have to make sure that ```git-clang-format``` is in your
```PATH```. The easiest way is probably to just ```npm install -g clang-format``` as it comes with
```git-clang-format```.
* **WebStorm** can run clang-format on the current file.
1. Under Preferences, open Tools > External Tools.
1. Plus icon to Create Tool
1. Fill in the form:
- Name: clang-format
- Description: Format
- Synchronize files after execution: checked
- Open console: not checked
- Show in: Editor menu
- Program: `$ProjectFileDir$/node_modules/.bin/clang-format`
- Parameters: `-i -style=file $FilePath$`
- Working directory: `$ProjectFileDir$`
* `clang-format` integrations are also available for many popular editors (`vim`, `emacs`,
`Sublime Text`, etc.).
### Linting
We use [tslint](https://github.com/palantir/tslint) for linting. See linting rules in [gulpfile](gulpfile.js). To lint, run
To run tests:
```shell
$ gulp lint
$ ./test.sh node # Run all angular tests on node
$ ./test.sh browser # Run all angular tests in browser
$ ./test.sh browserNoRouter # Optionally run all angular tests without router in browser
$ ./test.sh tools # Run angular tooling (not framework) tests
```
## Generating the API documentation
You should execute the 3 test suites before submitting a PR to github.
The following gulp task will generate the API docs in the `dist/angular.io/partials/api/angular2`:
All the tests are executed on our Continuous Integration infrastructure and a PR could only be merged once the tests pass.
```shell
$(npm bin)/gulp docs/angular.io
- CircleCI fails if your code is not formatted properly,
- Travis CI fails if any of the test suite describe above fails.
## Update the public API tests
If you happen to modify the public API of Angular, API golden files must be updated using:
``` shell
$ gulp public-api:update
```
You can serve the generated documentation to check how it would render on [angular.io](https://angular.io/):
- check out the [angular.io repo](https://github.com/angular/angular.io) locally,
- install dependencies as described in the [angular.io README](https://github.com/angular/angular.io/blob/master/README.md),
- copy the generated documentation from your local angular repo at `angular/dist/angular.io/partials/api/angular2` to your local angular.io repo at `angular.io/public/docs/js/latest/api`,
- run `harp compile` at the root of the angular.io repo to check the generated documentation for errors,
- run `harp server` and open a browser at `http://localhost:9000/docs/js/latest/api/` to check the rendered documentation.
Note: The command `./test.sh tools` fails when the API doesn't match the golden files.
## Project Information
## Formatting your source code
### Folder structure
Angular uses [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to format the source code. If the source code
is not properly formatted, the CI will fail and the PR can not be merged.
* `modules/*`: modules that will be loaded in the browser
* `tools/*`: tools that are needed to build Angular
* `dist/*`: build files are placed here.
You can automatically format your code by running:
### File suffixes
``` shell
$ gulp format
```
* `*.ts`: TypeScript files that get transpiled to Dart and EcmaScript 5/6
* `*.dart`: Dart files that don't get transpiled
## CI using Travis
For instructions on setting up Continuous Integration using Travis, see the instructions given
[here](https://github.com/angular/angular.dart/blob/master/travis.md).
## Transforming Dart code
See the [wiki](//github.com/angular/angular/wiki/Angular-2-Dart-Transformer).
## Debugging
### Debug the transpiler
If you need to debug the transpiler:
- add a `debugger;` statement in the transpiler code,
- from the root folder, execute `node debug $(npm bin)/gulp build` to enter the node
debugger
- press "c" to execute the program until you reach the `debugger;` statement,
- you can then type "repl" to enter the REPL and inspect variables in the context.
See the [Node.js manual](http://nodejs.org/api/debugger.html) for more information.
Notes:
- You can also execute `node $(npm bin)/karma start karma-dart.conf.js` depending on which
code you want to debug (the former will process the "modules" folder while the later processes
the transpiler specs).
- You can also add `debugger;` statements in the specs (JavaScript). The execution will halt when
the developer tools are opened in the browser running Karma.
### Debug the tests
If you need to debug the tests:
- add a `debugger;` statement to the test you want to debug (or the source code),
- execute karma `$(npm bin)/gulp test.js`,
- press the top right "DEBUG" button,
- open the DevTools and press F5,
- the execution halts at the `debugger;` statement
**Note (WebStorm users)**:
1. Create a Karma run config from WebStorm.
2. Then in the "Run" menu, press "Debug 'karma-js.conf.js'", and WebStorm will stop in the generated
code on the `debugger;` statement.
3. You can then step into the code and add watches.
The `debugger;` statement is needed because WebStorm will stop in a transpiled file. Breakpoints in
the original source files are not supported at the moment.

View File

@ -12,7 +12,9 @@ Angular
=========
Angular is a development platform for building mobile and desktop web applications. This is the
repository for [Angular 2][ng2], both the JavaScript (JS) and [Dart][dart] versions.
repository for [Angular 2][ng2] Typescript/JavaScript (JS).
Angular2 for [Dart][dart] can be found at [dart-lang/angular2][ng2dart].
Angular 2 is currently in **Release Candidate**.
@ -34,3 +36,4 @@ guidelines for [contributing][contributing] and then check out one of our issues
[ng2]: http://angular.io
[ngDart]: http://angulardart.org
[ngJS]: http://angularjs.org
[ng2dart]: https://github.com/dart-lang/angular2

View File

@ -1,376 +0,0 @@
# Developer Tools for Dart
Use these tools and techniques to increase your app's performance
and reliability.
* [Angular debugging tools](#angular-debugging-tools)
* [Code size](#code-size)
* [Performance](#performance)
## Angular debugging tools
Starting with alpha.38, Angular provides a set of debugging tools
that are accessible from any browser's developer console.
In Chrome, you can get to the dev console by pressing
Ctrl + Shift + J (on Mac: Cmd + Opt + J).
### Enabling the debugging tools
By default the debugging tools are disabled.
Enable the debugging tools as follows:
```dart
import 'package:angular2/platform/browser.dart';
main() async {
var appRef = await bootstrap(Application);
enableDebugTools(appRef);
}
```
<!-- Change function name to enableDebuggingTools? -->
### Using the debugging tools
In the browser, open the dev console. The top-level object is called `ng` and
contains more specific tools inside it.
For example, to run the change detection profiler on your app:
```javascript
// In the dev console:
ng.profiler.timeChangeDetection();
```
The [Change detection profiler](#change-detection-profiler) section
has more details.
<!-- Point to API docs when they're published, if they're useful.
They should be under
http://www.dartdocs.org/documentation/angular2/latest
and/or
https://angular.io/docs/js/latest/api/. -->
## Code size
Code must be downloaded, parsed, and executed. Too much code can lead to
slow application start-up time, especially on slow networks and low-end devices.
The tools and techniques in this section can help you to identify
unnecessarily large code and to reduce code size.
### Finding contributors to code size
Options for investigating code size include the `--dump-info` dart2js option,
ng2soyc, `reflector.trackUsage()`, and code coverage information
from the Dart VM.
#### Use --dump-info
The `--dump-info` option of `dart2js` outputs information about what happened
during compilation. You can specify `--dump-info` in `pubspec.yaml`:
```yaml
transformers:
...
- $dart2js:
commandLineOptions:
- --dump-info
```
The [Dump Info Visualizer](https://github.com/dart-lang/dump-info-visualizer)
can help you analyze the output.
For more information, see the
[dart2js_info API reference](http://dart-lang.github.io/dart2js_info/doc/api/).
#### Use ng2soyc.dart
[ng2soyc](https://github.com/angular/ng2soyc.dart) is a utility for analyzing
code size contributors in Angular 2 applications. It groups code size by
library and, assuming your library names follow
[standard naming conventions](https://www.dartlang.org/articles/style-guide/#do-prefix-library-names-with-the-package-name-and-a-dot-separated-path)
(package.library.sublibrary...), gives the code size breakdown at
each level. To reduce noise in the output of very large apps, ng2soyc provides
an option to hide libraries that are too small, so you can focus on the biggest
contributors.
#### Find unused reflection data
Your app might have types that are annotated with `@Component` or `@Injectable`
but never used.
To find these unused types, use `reflector.trackUsage()` and then,
after exercising your app, `reflector.listUnusedKeys()`.
For example:
```
import 'package:angular2/src/core/reflection/reflection.dart';
...
main() async {
reflector.trackUsage();
await bootstrap(AppComponent);
print('Unused keys: ${reflector.listUnusedKeys()}');
}
```
When you run that code (in Dartium or another browser),
you'll see a list of types that Angular _can_ inject but hasn't needed to.
Consider removing those types or their `@Component`/`@Injectable` annotation
to decrease your app's code size.
Three conditions must be true for `listUnusedKeys()` to return helpful data:
1. The angular2 transformer must run on the app.
2. If you're running a JavaScript version of the app,
the app must not be minified, so that the names are readable.
3. You must exercise your app in as many ways as possible
before calling `listUnusedKeys()`.
Otherwise, you might get false positives:
keys that haven't been used only because you didn't exercise
the relevant feature of the app.
To run the angular2 transformer, first specify it in `pubspec.yaml`:
```
name: hello_world
...
transformers:
- angular2:
entry_points: web/main.dart
```
Then use pub to run the transformer. If you use `pub serve`,
it provides both Dart and unminified (by default) JavaScript versions.
If you want to serve actual files, then use `pub build` in debug mode
to generate Dart and unminified JavaScript files:
`pub build --mode=debug`.
The `reflector.trackUsage()` method makes Angular track the reflection
information used by the app. Reflection information (`ReflectionInfo`) is a data
structure that stores information that Angular uses for locating DI factories
and for generating change detectors and other code related to a
given type.
#### Use code coverage to find dead code
When running in Dartium (or in the Dart VM, in general) you can request code
coverage information from the VM. You can either use
[observatory](https://www.dartlang.org/tools/observatory/) or download
the coverage file and use your own tools to inspect it. Lines of code that are
not covered are top candidates for dead code.
Keep in mind, however, that uncovered code is not sufficient evidence of dead
code, only necessary evidence. It is perfectly possible that you simply didn't
exercise your application in a way that triggers the execution of uncovered
code. A common example is error handling code. Just because your testing never
encountered an error does not mean the error won't happen in production. You
therefore don't have to rush and remove all the `catch` blocks.
### Reducing code size
To reduce code size, you can disable reflection,
enable minification, and manually remove dead code.
You can also try less safe options such as
telling dart2js to trust type annotations.
#### Disable reflection
`dart:mirrors` allows discovering program metadata at runtime. However, this
means that `dart2js` needs to retain that metadata and thus increase the size
of resulting JS output. In practice, however, it is possible to extract most
metadata necessary for your metaprogramming tasks statically using a
transformer and `package:analyzer`, and act on it before compiling to JS.
#### Enable minification
Minification shortens all your `longMethodNames` into 2- or 3-letter long
symbols. `dart2js` ensures that this kind of renaming is done safely, without
breaking the functionality of your programs. You can enable it in `pubspec.yaml`
under `$dart2js` transformer:
```yaml
transformers:
...
- $dart2js:
minify: true
```
#### Manually remove dead code
`dart2js` comes with dead code elimination out-of-the-box. However, it may not
always be able to tell if a piece of code could be used. Consider the following
example:
```dart
/// This function decides which serialization format to use
void setupSerializers() {
if (server.doYouSupportProtocolBuffers()) {
useProtobufSerializers();
} else {
useJsonSerializers();
}
}
```
In this example the application asks the server what kind of serialization
format it uses and dynamically chooses one or the other. `dart2js` can't
tell whether the server responds with yes or no, so it must retain both
kinds of serializers. However, if you know that your server supports
protocol buffers, you can remove that `if` block entirely and default to
protocol buffers.
Code coverage (see above) is a good way to find dead code in your app.
#### Unsafe options
Dart also provides more aggressive optimization options. However, you have to
be careful when using them and as of today the benefits aren't that clear. If
your type annotations are inaccurate you may end up with non-Darty runtime
behavior, including the classic "undefined is not a function" tautology, as
well as the "keep on truckin'" behavior, e.g. `null + 1 == 1` and
`{} + [] == 0`.
`--trust-type-annotations` tells `dart2js` to trust that your type annotations
are correct. So if you have a function `foo(Bar bar)` the compiler can omit the
check that `bar` is truly `Bar` when calling methods on it.
`--trust-primitives` tells `dart2js` that primitive types, such as numbers and
booleans are never `null` when performing arithmetic, and that your program
does not run into range error when operating on lists, letting the compiler
remove some of the error checking code.
Specify these options in `pubspec.yaml`.
Example:
```yaml
transformers:
...
- $dart2js:
commandLineOptions:
- --trust-type-annotations
- --trust-primitives
```
## Performance
### Change detection profiler
If your application is janky (it misses frames) or is slow according to other
metrics, you need to find out why. This tool helps by measuring the average
speed of _change detection_, a phase in Angular's
lifecycle that detects changes in values that are bound to the UI.
Janky UI updates can result from slowness either in _computing_ the changes or
in _applying_ those changes to the UI.
For your app to be performant, the process of _computing_ changes must be very
fast—preferably **under 3 milliseconds**.
Fast change computation leaves room for
the application logic, UI updates, and browser rendering pipeline
to fit within a 16 ms frame (assuming a target frame rate of 60 FPS).
The change detection profiler repeatedly performs change detection
without invoking any user actions, such as clicking buttons or entering
text in input fields. It then computes the average amount of time
(in milliseconds) to perform a single cycle of change detection and
prints that to the console. This number depends on the current state of the UI. You are likely to see different numbers
as you go from one screen in your application to another.
#### Running the profiler
Before running the profiler, enable the debugging tools
and put the app into the state you want to measure:
1. If you haven't already done so,
[enable the debugging tools](#enabling-the-debugging-tools).
2. Navigate the app to a screen whose performance you want to profile.
3. Make sure the screen is in a state that you want to measure.
For example, you might want to profile the screen several times,
with different amounts and kinds of data.
To run the profiler, enter the following in the dev console:
```javascript
ng.profiler.timeChangeDetection();
```
The results are visible in the console.
#### Recording CPU profiles
To record a profile, pass `{record: true}` to `timeChangeDetection()`:
```javascript
ng.profiler.timeChangeDetection({record: true});
```
Then open the **Profiles** tab. The recorded profile has the title
**Change Detection**. In Chrome, if you record the profile repeatedly, all the
profiles are nested under Change Detection.
#### Interpreting the numbers
In a properly designed application, repeated attempts to detect changes without
any user actions result in no changes to the UI. It is
also desirable to have the cost of a user action be proportional to the amount
of UI changes required. For example, popping up a menu with 5 items should be
vastly faster than rendering a table of 500 rows and 10 columns. Therefore,
change detection with no UI updates should be as fast as possible.
#### Investigating slow change detection
So you found a screen in your application on which the profiler reports a very
high number (i.e. >3ms). This is where a recorded CPU profile can help. Enable
recording while profiling:
```javascript
ng.profiler.timeChangeDetection({record: true});
```
Then look for hot spots using
[Chrome CPU profiler](https://developer.chrome.com/devtools/docs/cpu-profiling).
#### Reducing change detection cost
There are many reasons for slow change detection. To gain intuition about
possible causes it helps to understand how change detection works. Such a
discussion is outside the scope of this document,
but here are some key concepts.
<!-- TODO: link to change detection docs -->
By default, Angular uses a _dirty checking_ mechanism to find model changes.
This mechanism involves evaluating every bound expression that's active on the
UI. These usually include text interpolation via `{{expression}}` and property
bindings via `[prop]="expression"`. If any of the evaluated expressions are
costly to compute, they might contribute to slow change detection. A good way to
speed things up is to use plain class fields in your expressions and avoid any
kind of computation. For example:
```dart
@View(
template: '<button [enabled]="isEnabled">{{title}}</button>'
)
class FancyButton {
// GOOD: no computation, just returns the value
bool isEnabled;
// BAD: computes the final value upon request
String _title;
String get title => _title.trim().toUpperCase();
}
```
Most cases like these can be solved by precomputing the value and storing the
final value in a field.
Angular also supports a second type of change detection: the _push_ model. In
this model, Angular does not poll your component for changes. Instead, the
component tells Angular when it changes, and only then does Angular perform
the update. This model is suitable in situations when your data model uses
observable or immutable objects.
<!-- TODO: link to discussion of push model -->

View File

@ -13,7 +13,7 @@ var CIconfiguration = {
'IE9': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'IE10': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'IE11': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'Edge': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Edge': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'Android4.1': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android4.2': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android4.3': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
@ -38,7 +38,7 @@ var customLaunchers = {
'SL_CHROME': {
base: 'SauceLabs',
browserName: 'chrome',
version: '50'
version: '52'
},
'SL_CHROMEBETA': {
base: 'SauceLabs',
@ -53,7 +53,7 @@ var customLaunchers = {
'SL_FIREFOX': {
base: 'SauceLabs',
browserName: 'firefox',
version: '45'
version: '46'
},
'SL_FIREFOXBETA': {
base: 'SauceLabs',
@ -69,13 +69,13 @@ var customLaunchers = {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.9',
version: '7'
version: '7.0'
},
'SL_SAFARI8': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.10',
version: '8'
version: '8.0'
},
'SL_SAFARI9': {
base: 'SauceLabs',
@ -99,7 +99,7 @@ var customLaunchers = {
base: 'SauceLabs',
browserName: 'iphone',
platform: 'OS X 10.10',
version: '9.1'
version: '9.3'
},
'SL_IE9': {
base: 'SauceLabs',
@ -202,7 +202,7 @@ var customLaunchers = {
base: 'BrowserStack',
device: 'iPhone 6S',
os: 'ios',
os_version: '9.0'
os_version: '9.1'
},
'BS_IE9': {
base: 'BrowserStack',

View File

@ -35,7 +35,7 @@ cd -
TSCONFIG=./modules/tsconfig.json
echo "====== (all)COMPILING: \$(npm bin)/tsc -p ${TSCONFIG} ====="
# compile ts code
TSC="node dist/tools/@angular/tsc-wrapped/src/main"
TSC="node --max-old-space-size=3000 dist/tools/@angular/tsc-wrapped/src/main"
$TSC -p modules/tsconfig.json
rm -rf ./dist/packages-dist
@ -73,12 +73,12 @@ do
echo "====== TSC 1.8 d.ts compat for ${DESTDIR} ====="
# safely strips 'readonly' specifier from d.ts files to make them compatible with tsc 1.8
if [[ ${TRAVIS} ]]; then
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -e 's/\(^ *(static |private )*\)*readonly */\1/g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -E 's/^( +)abstract ([[:alnum:]]+\:)/\1\2/g'
if [ "$(uname)" == "Darwin" ]; then
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -e 's/\(^ *(static |private )*\)*readonly */\1/g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -E 's/^( +)abstract ([[:alnum:]]+\:)/\1\2/g'
else
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -e 's/\(^ *(static |private )*\)*readonly */\1/g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -E 's/^( +)abstract ([[:alnum:]]+\:)/\1\2/g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -e 's/\(^ *(static |private )*\)*readonly */\1/g'
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -E 's/^( +)abstract ([[:alnum:]]+\:)/\1\2/g'
fi
if [[ ${PACKAGE} != compiler-cli ]]; then
@ -94,27 +94,28 @@ do
echo "====== BUNDLING: ${SRCDIR} ====="
mkdir ${DESTDIR}/bundles
if [[ ${PACKAGE} != router ]]; then
(
cd ${SRCDIR}
echo "..." # here just to have grep match something and not exit with 1
../../../node_modules/.bin/rollup -c rollup.config.js
) 2>&1 | grep -v "as external dependency"
(
cd ${SRCDIR}
echo "..." # here just to have grep match something and not exit with 1
../../../node_modules/.bin/rollup -c rollup.config.js
) 2>&1 | grep -v "as external dependency"
$(npm bin)/tsc \
--out ${UMD_ES5_PATH} \
--target es5 \
--lib "es6,dom" \
--allowJs \
${UMD_ES6_PATH}
$(npm bin)/tsc \
--out ${UMD_ES5_PATH} \
--target es5 \
--lib "es6,dom" \
--allowJs \
${UMD_ES6_PATH}
rm ${UMD_ES6_PATH}
rm ${UMD_ES6_PATH}
cat ./modules/@angular/license-banner.txt > ${UMD_ES5_PATH}.tmp
cat ${UMD_ES5_PATH} >> ${UMD_ES5_PATH}.tmp
mv ${UMD_ES5_PATH}.tmp ${UMD_ES5_PATH}
cat ./modules/@angular/license-banner.txt > ${UMD_ES5_PATH}.tmp
cat ${UMD_ES5_PATH} >> ${UMD_ES5_PATH}.tmp
mv ${UMD_ES5_PATH}.tmp ${UMD_ES5_PATH}
$(npm bin)/uglifyjs -c --screw-ie8 -o ${UMD_ES5_MIN_PATH} ${UMD_ES5_PATH}
fi
$(npm bin)/uglifyjs -c --screw-ie8 -o ${UMD_ES5_MIN_PATH} ${UMD_ES5_PATH}
fi
done
echo "====== COMPILING: \$(npm bin)/tsc -p benchpress/tsconfig.json ====="
$(npm bin)/tsc -p ./modules/benchpress/tsconfig.json

View File

@ -8,8 +8,11 @@ require('./tools/check-environment')(
const gulp = require('gulp');
const path = require('path');
const os = require('os');
const srcsToFmt = ['tools/**/*.ts', 'modules/@angular/**/*.ts'];
const srcsToFmt =
['tools/**/*.ts', 'modules/@angular/**/*.ts', '!tools/public_api_guard/**/*.d.ts',
'modules/benchpress/**/*.ts', 'modules/playground/**/*.ts'];
gulp.task('format:enforce', () => {
const format = require('gulp-clang-format');
@ -25,12 +28,77 @@ gulp.task('format', () => {
format.format('file', clangFormat)).pipe(gulp.dest('.'));
});
const entrypoints = [
'dist/packages-dist/core/index.d.ts',
'dist/packages-dist/core/testing.d.ts',
'dist/packages-dist/common/index.d.ts',
'dist/packages-dist/common/testing.d.ts',
// The API surface of the compiler is currently unstable - all of the important APIs are exposed
// via @angular/core, @angular/platform-browser or @angular/platform-browser-dynamic instead.
//'dist/packages-dist/compiler/index.d.ts',
//'dist/packages-dist/compiler/testing.d.ts',
'dist/packages-dist/upgrade/index.d.ts',
'dist/packages-dist/platform-browser/index.d.ts',
'dist/packages-dist/platform-browser/testing.d.ts',
'dist/packages-dist/platform-browser-dynamic/index.d.ts',
'dist/packages-dist/platform-browser-dynamic/testing.d.ts',
'dist/packages-dist/platform-server/index.d.ts',
'dist/packages-dist/platform-server/testing.d.ts',
'dist/packages-dist/http/index.d.ts',
'dist/packages-dist/http/testing.d.ts',
'dist/packages-dist/forms/index.d.ts',
'dist/packages-dist/router/index.d.ts'
];
const publicApiDir = path.normalize('tools/public_api_guard');
const publicApiArgs = [
'--rootDir', 'dist/packages-dist',
'--stripExportPattern', '^__',
'--allowModuleIdentifiers', 'jasmine',
'--allowModuleIdentifiers', 'protractor',
'--allowModuleIdentifiers', 'angular',
'--onStabilityMissing', 'error'
].concat(entrypoints);
gulp.task('build.sh', (done) => {
const childProcess = require('child_process');
childProcess.exec(path.join(__dirname, 'build.sh'), error => done(error));
});
// Note that these two commands work on built d.ts files instead of the source
gulp.task('public-api:enforce', (done) => {
const childProcess = require('child_process');
childProcess
.spawn(
path.join(__dirname, `/node_modules/.bin/ts-api-guardian${/^win/.test(os.platform()) ? '.cmd' : ''}`),
['--verifyDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
.on('close', (errorCode) => {
if (errorCode !== 0) {
done(new Error(
'Public API differs from golden file. Please run `gulp public-api:update`.'));
} else {
done();
}
});
});
gulp.task('public-api:update', ['build.sh'], (done) => {
const childProcess = require('child_process');
childProcess
.spawn(
path.join(__dirname, `/node_modules/.bin/ts-api-guardian${/^win/.test(os.platform()) ? '.cmd' : ''}`),
['--outDir', publicApiDir].concat(publicApiArgs), {stdio: 'inherit'})
.on('close', (errorCode) => done(errorCode));
});
gulp.task('lint', ['format:enforce', 'tools:build'], () => {
const tslint = require('gulp-tslint');
// Built-in rules are at
// https://github.com/palantir/tslint#supported-rules
const tslintConfig = require('./tslint.json');
return gulp.src(['modules/@angular/**/*.ts', '!modules/@angular/*/test/**'])
return gulp.src(['modules/@angular/**/*.ts', 'modules/benchpress/**/*.ts'])
.pipe(tslint({
tslint: require('tslint').default,
configuration: tslintConfig,
@ -41,6 +109,22 @@ gulp.task('lint', ['format:enforce', 'tools:build'], () => {
gulp.task('tools:build', (done) => { tsc('tools/', done); });
gulp.task('check-cycle', (done) => {
const madge = require('madge');
var dependencyObject = madge(['dist/all/'], {
format: 'cjs',
extensions: ['.js'],
onParseFile: function(data) { data.src = data.src.replace(/\/\* circular \*\//g, "//"); }
});
var circularDependencies = dependencyObject.circular().getArray();
if (circularDependencies.length > 0) {
console.log('Found circular dependencies!');
console.log(circularDependencies);
process.exit(1);
}
done();
});
gulp.task('serve', () => {
let connect = require('gulp-connect');
@ -56,12 +140,29 @@ gulp.task('serve', () => {
});
function tsc(projectPath, done) {
let child_process = require('child_process');
gulp.task('changelog', () => {
const conventionalChangelog = require('gulp-conventional-changelog');
child_process
return gulp.src('CHANGELOG.md')
.pipe(conventionalChangelog({
preset: 'angular',
releaseCount: 1
}, {
// Conventional Changelog Context
// We have to manually set version number so it doesn't get prefixed with `v`
// See https://github.com/conventional-changelog/conventional-changelog-core/issues/10
currentTag: require('./package.json').version
}))
.pipe(gulp.dest('./'));
});
function tsc(projectPath, done) {
const childProcess = require('child_process');
childProcess
.spawn(
`${__dirname}/node_modules/.bin/tsc`, ['-p', path.join(__dirname, projectPath)],
path.normalize(`${__dirname}/node_modules/.bin/tsc`) + (/^win/.test(os.platform()) ? '.cmd' : ''),
['-p', path.join(__dirname, projectPath)],
{stdio: 'inherit'})
.on('close', (errorCode) => done(errorCode));
}

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,7 @@ module.exports = function(config) {
exclude: [
'dist/all/@angular/**/e2e_test/**',
'dist/all/@angular/examples/**',
'dist/all/@angular/router/**',
'dist/all/@angular/compiler-cli/**',
'dist/all/angular1_router.js',
'dist/all/@angular/platform-browser/testing/e2e_util.js'

View File

@ -1,6 +0,0 @@
Angular2
=========
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo. This is the repository for the upcoming 2.0 version. If you're looking for the current official version of Angular you should go to [angular/angular.js](https://github.com/angular/angular.js)
License: Apache MIT 2.0

View File

@ -1 +0,0 @@
export 'index.dart';

View File

@ -1,5 +1,30 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {NgModule} from '@angular/core';
import {COMMON_DIRECTIVES} from './src/common_directives';
import {COMMON_PIPES} from './src/pipes';
export * from './src/pipes';
export * from './src/directives';
export * from './src/forms-deprecated';
export * from './src/common_directives';
export * from './src/location';
export {NgLocalization} from './src/localization';
// Note: This does not contain the location providers,
// as they need some platform specific implementations to work.
/**
* The module that includes all the basic Angular directives like {@link NgIf}, ${link NgFor}, ...
*
* @experimental
*/
@NgModule(
{declarations: [COMMON_DIRECTIVES, COMMON_PIPES], exports: [COMMON_DIRECTIVES, COMMON_PIPES]})
export class CommonModule {
}

View File

@ -1,8 +1,14 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Type} from '@angular/core';
import {CORE_DIRECTIVES} from './directives';
import {FORM_DIRECTIVES} from './forms-deprecated';
/**
* A collection of Angular core directives that are likely to be used in each and every Angular
@ -49,4 +55,4 @@ import {FORM_DIRECTIVES} from './forms-deprecated';
*
* @experimental Contains forms which are experimental.
*/
export const COMMON_DIRECTIVES: Type[][] = /*@ts2dart_const*/[CORE_DIRECTIVES, FORM_DIRECTIVES];
export const COMMON_DIRECTIVES: Type[][] = [CORE_DIRECTIVES];

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* @module
* @description
@ -7,7 +15,7 @@ export {CORE_DIRECTIVES} from './directives/core_directives';
export {NgClass} from './directives/ng_class';
export {NgFor} from './directives/ng_for';
export {NgIf} from './directives/ng_if';
export {NgLocalization, NgPlural, NgPluralCase} from './directives/ng_plural';
export {NgPlural, NgPluralCase} from './directives/ng_plural';
export {NgStyle} from './directives/ng_style';
export {NgSwitch, NgSwitchCase, NgSwitchDefault} from './directives/ng_switch';
export {NgTemplateOutlet} from './directives/ng_template_outlet';

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Type} from '../facade/lang';
import {NgClass} from './ng_class';
@ -8,8 +16,6 @@ import {NgStyle} from './ng_style';
import {NgSwitch, NgSwitchCase, NgSwitchDefault} from './ng_switch';
import {NgTemplateOutlet} from './ng_template_outlet';
/**
* A collection of Angular core directives that are likely to be used in each and every Angular
* application.
@ -52,7 +58,7 @@ import {NgTemplateOutlet} from './ng_template_outlet';
*
* @stable
*/
export const CORE_DIRECTIVES: Type[] = /*@ts2dart_const*/[
export const CORE_DIRECTIVES: Type[] = [
NgClass,
NgFor,
NgIf,

View File

@ -1,9 +1,18 @@
import {CollectionChangeRecord, Directive, DoCheck, ElementRef, IterableDiffer, IterableDiffers, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, OnDestroy, Renderer} from '@angular/core';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {CollectionChangeRecord, Directive, DoCheck, ElementRef, Input, IterableDiffer, IterableDiffers, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
import {StringMapWrapper, isListLikeIterable} from '../facade/collection';
import {isArray, isPresent, isString} from '../facade/lang';
/**
* The `NgClass` directive conditionally adds and removes CSS classes on an HTML element based on
* an expression's evaluation result.
@ -65,8 +74,8 @@ import {isArray, isPresent, isString} from '../facade/lang';
*
* @stable
*/
@Directive({selector: '[ngClass]', inputs: ['rawClass: ngClass', 'initialClasses: class']})
export class NgClass implements DoCheck, OnDestroy {
@Directive({selector: '[ngClass]'})
export class NgClass implements DoCheck {
private _iterableDiffer: IterableDiffer;
private _keyValueDiffer: KeyValueDiffer;
private _initialClasses: string[] = [];
@ -76,6 +85,8 @@ export class NgClass implements DoCheck, OnDestroy {
private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers,
private _ngEl: ElementRef, private _renderer: Renderer) {}
@Input('class')
set initialClasses(v: string) {
this._applyInitialClasses(true);
this._initialClasses = isPresent(v) && isString(v) ? v.split(' ') : [];
@ -83,7 +94,8 @@ export class NgClass implements DoCheck, OnDestroy {
this._applyClasses(this._rawClass, false);
}
set rawClass(v: string|string[]|Set<string>|{[key: string]: any}) {
@Input()
set ngClass(v: string|string[]|Set<string>|{[key: string]: any}) {
this._cleanupClasses(this._rawClass);
if (isString(v)) {
@ -117,8 +129,6 @@ export class NgClass implements DoCheck, OnDestroy {
}
}
ngOnDestroy(): void { this._cleanupClasses(this._rawClass); }
private _cleanupClasses(rawClassVal: string[]|Set<string>|{[key: string]: any}): void {
this._applyClasses(rawClassVal, true);
this._applyInitialClasses(false);

View File

@ -1,4 +1,12 @@
import {ChangeDetectorRef, CollectionChangeRecord, DefaultIterableDiffer, Directive, DoCheck, EmbeddedViewRef, IterableDiffer, IterableDiffers, TemplateRef, TrackByFn, ViewContainerRef} from '@angular/core';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectorRef, CollectionChangeRecord, DefaultIterableDiffer, Directive, DoCheck, EmbeddedViewRef, Input, IterableDiffer, IterableDiffers, OnChanges, SimpleChanges, TemplateRef, TrackByFn, ViewContainerRef} from '@angular/core';
import {BaseException} from '../facade/exceptions';
import {getTypeNameForDebugging, isBlank, isPresent} from '../facade/lang';
@ -68,76 +76,76 @@ export class NgForRow {
*
* @stable
*/
@Directive({selector: '[ngFor][ngForOf]', inputs: ['ngForTrackBy', 'ngForOf', 'ngForTemplate']})
export class NgFor implements DoCheck {
/** @internal */
_ngForOf: any;
/** @internal */
_ngForTrackBy: TrackByFn;
@Directive({selector: '[ngFor][ngForOf]'})
export class NgFor implements DoCheck, OnChanges {
@Input() ngForOf: any;
@Input() ngForTrackBy: TrackByFn;
private _differ: IterableDiffer;
constructor(
private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<NgForRow>,
private _iterableDiffers: IterableDiffers, private _cdr: ChangeDetectorRef) {}
set ngForOf(value: any) {
this._ngForOf = value;
if (isBlank(this._differ) && isPresent(value)) {
try {
this._differ = this._iterableDiffers.find(value).create(this._cdr, this._ngForTrackBy);
} catch (e) {
throw new BaseException(
`Cannot find a differ supporting object '${value}' of type '${getTypeNameForDebugging(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
}
}
}
@Input()
set ngForTemplate(value: TemplateRef<NgForRow>) {
if (isPresent(value)) {
this._templateRef = value;
}
}
set ngForTrackBy(value: TrackByFn) { this._ngForTrackBy = value; }
ngOnChanges(changes: SimpleChanges): void {
if ('ngForOf' in changes) {
// React on ngForOf changes only once all inputs have been initialized
const value = changes['ngForOf'].currentValue;
if (isBlank(this._differ) && isPresent(value)) {
try {
this._differ = this._iterableDiffers.find(value).create(this._cdr, this.ngForTrackBy);
} catch (e) {
throw new BaseException(
`Cannot find a differ supporting object '${value}' of type '${getTypeNameForDebugging(value)}'. NgFor only supports binding to Iterables such as Arrays.`);
}
}
}
}
ngDoCheck() {
if (isPresent(this._differ)) {
var changes = this._differ.diff(this._ngForOf);
const changes = this._differ.diff(this.ngForOf);
if (isPresent(changes)) this._applyChanges(changes);
}
}
private _applyChanges(changes: DefaultIterableDiffer) {
// TODO(rado): check if change detection can produce a change record that is
// easier to consume than current.
var recordViewTuples: RecordViewTuple[] = [];
changes.forEachRemovedItem(
(removedRecord: CollectionChangeRecord) =>
recordViewTuples.push(new RecordViewTuple(removedRecord, null)));
const insertTuples: RecordViewTuple[] = [];
changes.forEachOperation(
(item: CollectionChangeRecord, adjustedPreviousIndex: number, currentIndex: number) => {
if (item.previousIndex == null) {
let view = this._viewContainer.createEmbeddedView(
this._templateRef, new NgForRow(null, null, null), currentIndex);
let tuple = new RecordViewTuple(item, view);
insertTuples.push(tuple);
} else if (currentIndex == null) {
this._viewContainer.remove(adjustedPreviousIndex);
} else {
let view = this._viewContainer.get(adjustedPreviousIndex);
this._viewContainer.move(view, currentIndex);
let tuple = new RecordViewTuple(item, <EmbeddedViewRef<NgForRow>>view);
insertTuples.push(tuple);
}
});
changes.forEachMovedItem(
(movedRecord: CollectionChangeRecord) =>
recordViewTuples.push(new RecordViewTuple(movedRecord, null)));
var insertTuples = this._bulkRemove(recordViewTuples);
changes.forEachAddedItem(
(addedRecord: CollectionChangeRecord) =>
insertTuples.push(new RecordViewTuple(addedRecord, null)));
this._bulkInsert(insertTuples);
for (var i = 0; i < insertTuples.length; i++) {
for (let i = 0; i < insertTuples.length; i++) {
this._perViewChange(insertTuples[i].view, insertTuples[i].record);
}
for (var i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
for (let i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i);
viewRef.context.index = i;
viewRef.context.count = ilen;
}
changes.forEachIdentityChange((record: any /** TODO #9100 */) => {
changes.forEachIdentityChange((record: any) => {
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(record.currentIndex);
viewRef.context.$implicit = record.item;
});
@ -146,46 +154,8 @@ export class NgFor implements DoCheck {
private _perViewChange(view: EmbeddedViewRef<NgForRow>, record: CollectionChangeRecord) {
view.context.$implicit = record.item;
}
private _bulkRemove(tuples: RecordViewTuple[]): RecordViewTuple[] {
tuples.sort(
(a: RecordViewTuple, b: RecordViewTuple) =>
a.record.previousIndex - b.record.previousIndex);
var movedTuples: RecordViewTuple[] = [];
for (var i = tuples.length - 1; i >= 0; i--) {
var tuple = tuples[i];
// separate moved views from removed views.
if (isPresent(tuple.record.currentIndex)) {
tuple.view =
<EmbeddedViewRef<NgForRow>>this._viewContainer.detach(tuple.record.previousIndex);
movedTuples.push(tuple);
} else {
this._viewContainer.remove(tuple.record.previousIndex);
}
}
return movedTuples;
}
private _bulkInsert(tuples: RecordViewTuple[]): RecordViewTuple[] {
tuples.sort((a, b) => a.record.currentIndex - b.record.currentIndex);
for (var i = 0; i < tuples.length; i++) {
var tuple = tuples[i];
if (isPresent(tuple.view)) {
this._viewContainer.insert(tuple.view, tuple.record.currentIndex);
} else {
tuple.view = this._viewContainer.createEmbeddedView(
this._templateRef, new NgForRow(null, null, null), tuple.record.currentIndex);
}
}
return tuples;
}
}
class RecordViewTuple {
view: EmbeddedViewRef<NgForRow>;
record: any;
constructor(record: any, view: EmbeddedViewRef<NgForRow>) {
this.record = record;
this.view = view;
}
constructor(public record: any, public view: EmbeddedViewRef<NgForRow>) {}
}

View File

@ -1,8 +1,17 @@
import {Directive, TemplateRef, ViewContainerRef} from '@angular/core';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {isBlank} from '../facade/lang';
/**
* Removes or recreates a portion of the DOM tree based on an {expression}.
*
@ -27,14 +36,15 @@ import {isBlank} from '../facade/lang';
*
* @stable
*/
@Directive({selector: '[ngIf]', inputs: ['ngIf']})
@Directive({selector: '[ngIf]'})
export class NgIf {
private _prevCondition: boolean = null;
constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<Object>) {
}
set ngIf(newCondition: any /* boolean */) {
@Input()
set ngIf(newCondition: any) {
if (newCondition && (isBlank(this._prevCondition) || !this._prevCondition)) {
this._prevCondition = true;
this._viewContainer.createEmbeddedView(this._templateRef);

View File

@ -1,16 +1,18 @@
import {AfterContentInit, Attribute, ContentChildren, Directive, Input, QueryList, TemplateRef, ViewContainerRef} from '@angular/core';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Map} from '../facade/collection';
import {NumberWrapper, isPresent} from '../facade/lang';
import {Attribute, Directive, Host, Input, OnInit, TemplateRef, ViewContainerRef} from '@angular/core';
import {isPresent} from '../facade/lang';
import {NgLocalization, getPluralCategory} from '../localization';
import {SwitchView} from './ng_switch';
const _CATEGORY_DEFAULT = 'other';
/**
* @experimental
*/
export abstract class NgLocalization { abstract getPluralCategory(value: any): string; }
/**
* `ngPlural` is an i18n directive that displays DOM sub-trees that match the switch expression
@ -27,9 +29,6 @@ export abstract class NgLocalization { abstract getPluralCategory(value: any): s
* value matches aren't found and the value maps to its category using the `getPluralCategory`
* function provided.
*
* If no matching views are found for a switch expression, inner elements marked
* `[ngPluralCase]="other"` will be displayed.
*
* ```typescript
* class MyLocalization extends NgLocalization {
* getPluralCategory(value: any) {
@ -68,28 +67,11 @@ export abstract class NgLocalization { abstract getPluralCategory(value: any): s
* ```
* @experimental
*/
@Directive({selector: '[ngPluralCase]'})
export class NgPluralCase {
/** @internal */
_view: SwitchView;
constructor(
@Attribute('ngPluralCase') public value: string, template: TemplateRef<Object>,
viewContainer: ViewContainerRef) {
this._view = new SwitchView(viewContainer, template);
}
}
/**
* @experimental
*/
@Directive({selector: '[ngPlural]'})
export class NgPlural implements AfterContentInit {
export class NgPlural {
private _switchValue: number;
private _activeView: SwitchView;
private _caseViews = new Map<any, SwitchView>();
@ContentChildren(NgPluralCase) cases: QueryList<NgPluralCase> = null;
private _caseViews: {[k: string]: SwitchView} = {};
constructor(private _localization: NgLocalization) {}
@ -99,21 +81,15 @@ export class NgPlural implements AfterContentInit {
this._updateView();
}
ngAfterContentInit() {
this.cases.forEach((pluralCase: NgPluralCase): void => {
this._caseViews.set(this._formatValue(pluralCase), pluralCase._view);
});
this._updateView();
}
addCase(value: string, switchView: SwitchView): void { this._caseViews[value] = switchView; }
/** @internal */
_updateView(): void {
this._clearViews();
var view: SwitchView = this._caseViews.get(this._switchValue);
if (!isPresent(view)) view = this._getCategoryView(this._switchValue);
this._activateView(view);
var key =
getPluralCategory(this._switchValue, Object.keys(this._caseViews), this._localization);
this._activateView(this._caseViews[key]);
}
/** @internal */
@ -127,22 +103,16 @@ export class NgPlural implements AfterContentInit {
this._activeView = view;
this._activeView.create();
}
/** @internal */
_getCategoryView(value: number): SwitchView {
var category: string = this._localization.getPluralCategory(value);
var categoryView: SwitchView = this._caseViews.get(category);
return isPresent(categoryView) ? categoryView : this._caseViews.get(_CATEGORY_DEFAULT);
}
/** @internal */
_isValueView(pluralCase: NgPluralCase): boolean { return pluralCase.value[0] === '='; }
/** @internal */
_formatValue(pluralCase: NgPluralCase): any {
return this._isValueView(pluralCase) ? this._stripValue(pluralCase.value) : pluralCase.value;
}
/** @internal */
_stripValue(value: string): number { return NumberWrapper.parseInt(value.substring(1), 10); }
}
/**
* @experimental
*/
@Directive({selector: '[ngPluralCase]'})
export class NgPluralCase {
constructor(
@Attribute('ngPluralCase') public value: string, template: TemplateRef<Object>,
viewContainer: ViewContainerRef, @Host() ngPlural: NgPlural) {
ngPlural.addCase(value, new SwitchView(viewContainer, template));
}
}

View File

@ -1,8 +1,17 @@
import {Directive, DoCheck, ElementRef, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, DoCheck, ElementRef, Input, KeyValueChangeRecord, KeyValueDiffer, KeyValueDiffers, Renderer} from '@angular/core';
import {isBlank, isPresent} from '../facade/lang';
/**
* The `NgStyle` directive changes styles based on a result of expression evaluation.
*
@ -12,7 +21,8 @@ import {isBlank, isPresent} from '../facade/lang';
*
* ### Syntax
*
* - `<div [ngStyle]="{'font-style': style}"></div>`
* - `<div [ngStyle]="{'font-style': styleExp}"></div>`
* - `<div [ngStyle]="{'max-width.px': widthExp}"></div>`
* - `<div [ngStyle]="styleExp"></div>` - here the `styleExp` must evaluate to an object
*
* ### Example ([live demo](http://plnkr.co/edit/YamGS6GkUh9GqWNQhCyM?p=preview)):
@ -56,26 +66,27 @@ import {isBlank, isPresent} from '../facade/lang';
*
* @stable
*/
@Directive({selector: '[ngStyle]', inputs: ['rawStyle: ngStyle']})
@Directive({selector: '[ngStyle]'})
export class NgStyle implements DoCheck {
/** @internal */
_rawStyle: {[key: string]: string};
_ngStyle: {[key: string]: string};
/** @internal */
_differ: KeyValueDiffer;
constructor(
private _differs: KeyValueDiffers, private _ngEl: ElementRef, private _renderer: Renderer) {}
set rawStyle(v: {[key: string]: string}) {
this._rawStyle = v;
@Input()
set ngStyle(v: {[key: string]: string}) {
this._ngStyle = v;
if (isBlank(this._differ) && isPresent(v)) {
this._differ = this._differs.find(this._rawStyle).create(null);
this._differ = this._differs.find(this._ngStyle).create(null);
}
}
ngDoCheck() {
if (isPresent(this._differ)) {
var changes = this._differ.diff(this._rawStyle);
var changes = this._differ.diff(this._ngStyle);
if (isPresent(changes)) {
this._applyChanges(changes);
}
@ -83,15 +94,19 @@ export class NgStyle implements DoCheck {
}
private _applyChanges(changes: any): void {
changes.forEachRemovedItem(
(record: KeyValueChangeRecord) => { this._setStyle(record.key, null); });
changes.forEachAddedItem(
(record: KeyValueChangeRecord) => { this._setStyle(record.key, record.currentValue); });
changes.forEachChangedItem(
(record: KeyValueChangeRecord) => { this._setStyle(record.key, record.currentValue); });
changes.forEachRemovedItem(
(record: KeyValueChangeRecord) => { this._setStyle(record.key, null); });
}
private _setStyle(name: string, val: string): void {
this._renderer.setElementStyle(this._ngEl.nativeElement, name, val);
const nameParts = name.split('.');
const nameToSet = nameParts[0];
const valToSet = isPresent(val) && nameParts.length === 2 ? `${val}${nameParts[1]}` : val;
this._renderer.setElementStyle(this._ngEl.nativeElement, nameToSet, valToSet);
}
}

View File

@ -1,9 +1,20 @@
import {Directive, Host, TemplateRef, ViewContainerRef} from '@angular/core';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ListWrapper, Map} from '../facade/collection';
import {Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {ListWrapper} from '../facade/collection';
import {isBlank, isPresent, normalizeBlank} from '../facade/lang';
const _CASE_DEFAULT = /*@ts2dart_const*/ new Object();
const _CASE_DEFAULT = new Object();
// TODO: remove when fully deprecated
let _warned: boolean = false;
export class SwitchView {
constructor(
@ -17,7 +28,7 @@ export class SwitchView {
/**
* Adds or removes DOM sub-trees when their match expressions match the switch expression.
*
* Elements within `NgSwitch` but without `ngSwitchCase` or `NgSwitchDefault` directives will be
* Elements within `NgSwitch` but without `NgSwitchCase` or `NgSwitchDefault` directives will be
* preserved at the location as specified in the template.
*
* `NgSwitch` simply inserts nested elements based on which match expression matches the value
@ -57,7 +68,7 @@ export class SwitchView {
* <template ngSwitchDefault>&gt; 2, STOP!</template>
* </p>
* `,
* directives: [NgSwitch, ngSwitchCase, NgSwitchDefault]
* directives: [NgSwitch, NgSwitchCase, NgSwitchDefault]
* })
* export class App {
* value = 'init';
@ -72,13 +83,14 @@ export class SwitchView {
*
* @experimental
*/
@Directive({selector: '[ngSwitch]', inputs: ['ngSwitch']})
@Directive({selector: '[ngSwitch]'})
export class NgSwitch {
private _switchValue: any;
private _useDefault: boolean = false;
private _valueViews = new Map<any, SwitchView[]>();
private _activeViews: SwitchView[] = [];
@Input()
set ngSwitch(value: any) {
// Empty the currently active ViewContainers
this._emptyAllActiveViews();
@ -172,16 +184,13 @@ export class NgSwitch {
*
* @experimental
*/
@Directive({selector: '[ngSwitchCase],[ngSwitchWhen]', inputs: ['ngSwitchCase', 'ngSwitchWhen']})
@Directive({selector: '[ngSwitchCase],[ngSwitchWhen]'})
export class NgSwitchCase {
// `_CASE_DEFAULT` is used as a marker for a not yet initialized value
/** @internal */
_value: any = _CASE_DEFAULT;
/** @internal */
_view: SwitchView;
// TODO: remove when fully deprecated
/** @internal */
_warned: boolean;
private _switch: NgSwitch;
constructor(
@ -191,14 +200,16 @@ export class NgSwitchCase {
this._view = new SwitchView(viewContainer, templateRef);
}
@Input()
set ngSwitchCase(value: any) {
this._switch._onCaseValueChanged(this._value, value, this._view);
this._value = value;
}
@Input()
set ngSwitchWhen(value: any) {
if (!this._warned) {
this._warned = true;
if (!_warned) {
_warned = true;
console.warn('*ngSwitchWhen is deprecated and will be removed. Use *ngSwitchCase instead');
}
this._switch._onCaseValueChanged(this._value, value, this._view);

View File

@ -1,8 +1,12 @@
import {Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef} from '@angular/core';
import {isPresent} from '../facade/lang';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, EmbeddedViewRef, Input, OnChanges, TemplateRef, ViewContainerRef} from '@angular/core';
/**
* Creates and inserts an embedded view based on a prepared `TemplateRef`.
@ -13,13 +17,17 @@ import {isPresent} from '../facade/lang';
* Note: using the key `$implicit` in the context object will set it's value as default.
*
* ### Syntax
* - `<template [ngTemplateOutlet]="templateRefExpression"
* [ngOutletContext]="objectExpression"></template>`
*
* ```
* <template [ngTemplateOutlet]="templateRefExpression"
* [ngOutletContext]="objectExpression">
* </template>
* ```
*
* @experimental
*/
@Directive({selector: '[ngTemplateOutlet]'})
export class NgTemplateOutlet {
export class NgTemplateOutlet implements OnChanges {
private _viewRef: EmbeddedViewRef<any>;
private _context: Object;
private _templateRef: TemplateRef<any>;
@ -27,29 +35,17 @@ export class NgTemplateOutlet {
constructor(private _viewContainerRef: ViewContainerRef) {}
@Input()
set ngOutletContext(context: Object) {
if (this._context !== context) {
this._context = context;
if (isPresent(this._viewRef)) {
this.createView();
}
}
}
set ngOutletContext(context: Object) { this._context = context; }
@Input()
set ngTemplateOutlet(templateRef: TemplateRef<Object>) {
if (this._templateRef !== templateRef) {
this._templateRef = templateRef;
this.createView();
}
}
set ngTemplateOutlet(templateRef: TemplateRef<Object>) { this._templateRef = templateRef; }
private createView() {
if (isPresent(this._viewRef)) {
ngOnChanges() {
if (this._viewRef) {
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._viewRef));
}
if (isPresent(this._templateRef)) {
if (this._templateRef) {
this._viewRef = this._viewContainerRef.createEmbeddedView(this._templateRef, this._context);
}
}

View File

@ -1,63 +0,0 @@
library angular2.directives.observable_list_iterable_diff;
import 'package:observe/observe.dart' show ObservableList;
import 'package:angular2/core.dart';
import 'package:angular2/src/core/change_detection/differs/default_iterable_differ.dart';
import 'dart:async';
class ObservableListDiff extends DefaultIterableDiffer {
ChangeDetectorRef _ref;
ObservableListDiff(this._ref);
bool _updated = true;
ObservableList _collection;
StreamSubscription _subscription;
onDestroy() {
if (this._subscription != null) {
this._subscription.cancel();
this._subscription = null;
this._collection = null;
}
}
DefaultIterableDiffer diff(ObservableList collection) {
if (collection is! ObservableList) {
throw "Cannot change the type of a collection";
}
// A new collection instance is passed in.
// - We need to set up a listener.
// - We need to diff collection.
if (!identical(_collection, collection)) {
_collection = collection;
if (_subscription != null) _subscription.cancel();
_subscription = collection.changes.listen((_) {
_updated = true;
_ref.markForCheck();
});
_updated = false;
return super.diff(collection);
// An update has been registered since the last change detection check.
// - We reset the flag.
// - We diff the collection.
} else if (_updated) {
_updated = false;
return super.diff(collection);
// No updates has been registered.
} else {
return null;
}
}
}
class ObservableListDiffFactory implements IterableDifferFactory {
const ObservableListDiffFactory();
bool supports(obj) => obj is ObservableList;
IterableDiffer create(ChangeDetectorRef cdRef, [Function trackByFn]) {
return new ObservableListDiff(cdRef);
}
}

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* @module
* @description
@ -10,8 +18,9 @@
* Forms providers are not included in default providers; you must import these providers
* explicitly.
*/
import {Type} from '@angular/core';
import {NgModule, Type} from '@angular/core';
import {FORM_DIRECTIVES} from './forms-deprecated/directives';
import {RadioControlRegistry} from './forms-deprecated/directives/radio_control_value_accessor';
import {FormBuilder} from './forms-deprecated/form_builder';
@ -48,4 +57,19 @@ export {NG_ASYNC_VALIDATORS, NG_VALIDATORS, Validators} from './forms-deprecated
*
* @experimental
*/
export const FORM_PROVIDERS: Type[] = /*@ts2dart_const*/[FormBuilder, RadioControlRegistry];
export const FORM_PROVIDERS: Type[] = [FormBuilder, RadioControlRegistry];
/**
* The ng module for the deprecated forms API.
* @deprecated
*/
@NgModule({
providers: [
FORM_PROVIDERS,
],
declarations: FORM_DIRECTIVES,
exports: FORM_DIRECTIVES
})
export class DeprecatedFormsModule {
}

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Type} from '@angular/core';
import {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
@ -50,7 +58,7 @@ export {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValida
* ```
* @experimental
*/
export const FORM_DIRECTIVES: Type[] = /*@ts2dart_const*/[
export const FORM_DIRECTIVES: Type[] = [
NgControlName,
NgControlGroup,

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {unimplemented} from '../../facade/exceptions';
import {isPresent} from '../../facade/lang';
import {AbstractControl} from '../model';

View File

@ -1,8 +1,16 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, ElementRef, Renderer, forwardRef} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
export const CHECKBOX_VALUE_ACCESSOR: any = /*@ts2dart_const*/ {
export const CHECKBOX_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CheckboxControlValueAccessor),
multi: true

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AbstractControlDirective} from './abstract_control_directive';
import {Form} from './form_interface';

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core';
/**
@ -33,5 +41,4 @@ export interface ControlValueAccessor {
* See {@link DefaultValueAccessor} for how to implement one.
* @experimental
*/
export const NG_VALUE_ACCESSOR: OpaqueToken =
/*@ts2dart_const*/ new OpaqueToken('NgValueAccessor');
export const NG_VALUE_ACCESSOR: OpaqueToken = new OpaqueToken('NgValueAccessor');

View File

@ -1,15 +1,22 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, ElementRef, Renderer, forwardRef} from '@angular/core';
import {isBlank} from '../../facade/lang';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
export const DEFAULT_VALUE_ACCESSOR: any = /*@ts2dart_const*/
/* @ts2dart_Provider */ {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DefaultValueAccessor),
multi: true
};
export const DEFAULT_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DefaultValueAccessor),
multi: true
};
/**
* The default accessor for writing a value and listening to changes that is used by the

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Control, ControlGroup} from '../model';
import {NgControl} from './ng_control';

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {unimplemented} from '../../facade/exceptions';
import {AbstractControlDirective} from './abstract_control_directive';

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, Host, Inject, OnDestroy, OnInit, Optional, Self, SkipSelf, forwardRef} from '@angular/core';
import {ControlGroup} from '../model';
@ -8,11 +16,10 @@ import {Form} from './form_interface';
import {composeAsyncValidators, composeValidators, controlPath} from './shared';
import {AsyncValidatorFn, ValidatorFn} from './validators';
export const controlGroupProvider: any =
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
provide: ControlContainer,
useExisting: forwardRef(() => NgControlGroup)
};
export const controlGroupProvider: any = {
provide: ControlContainer,
useExisting: forwardRef(() => NgControlGroup)
};
/**
* Creates and binds a control group to a DOM element.

View File

@ -1,6 +1,14 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, Host, Inject, OnChanges, OnDestroy, Optional, Self, SimpleChanges, SkipSelf, forwardRef} from '@angular/core';
import {EventEmitter, ObservableWrapper} from '../../facade/async';
import {EventEmitter} from '../../facade/async';
import {Control} from '../model';
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators';
@ -11,11 +19,10 @@ import {composeAsyncValidators, composeValidators, controlPath, isPropertyUpdate
import {AsyncValidatorFn, ValidatorFn} from './validators';
export const controlNameBinding: any =
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
provide: NgControl,
useExisting: forwardRef(() => NgControlName)
};
export const controlNameBinding: any = {
provide: NgControl,
useExisting: forwardRef(() => NgControlName)
};
/**
* Creates and binds a control with a specified name to a DOM element.
@ -115,7 +122,7 @@ export class NgControlName extends NgControl implements OnChanges,
viewToModelUpdate(newValue: any): void {
this.viewModel = newValue;
ObservableWrapper.callEmit(this.update, newValue);
this.update.emit(newValue);
}
get path(): string[] { return controlPath(this.name, this._parent); }

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, Self} from '@angular/core';
import {isPresent} from '../../facade/lang';

View File

@ -1,6 +1,14 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, Inject, Optional, Self, forwardRef} from '@angular/core';
import {EventEmitter, ObservableWrapper, PromiseWrapper} from '../../facade/async';
import {EventEmitter} from '../../facade/async';
import {ListWrapper} from '../../facade/collection';
import {isPresent} from '../../facade/lang';
import {AbstractControl, Control, ControlGroup} from '../model';
@ -12,18 +20,22 @@ import {NgControl} from './ng_control';
import {NgControlGroup} from './ng_control_group';
import {composeAsyncValidators, composeValidators, setUpControl, setUpControlGroup} from './shared';
export const formDirectiveProvider: any =
/*@ts2dart_const*/ {provide: ControlContainer, useExisting: forwardRef(() => NgForm)};
export const formDirectiveProvider: any = {
provide: ControlContainer,
useExisting: forwardRef(() => NgForm)
};
let _formWarningDisplayed: boolean = false;
const resolvedPromise = Promise.resolve(null);
/**
* If `NgForm` is bound in a component, `<form>` elements in that component will be
* upgraded to use the Angular form system.
*
* ### Typical Use
*
* Include `FORM_DIRECTIVES` in the `directives` section of a {@link View} annotation
* Include `FORM_DIRECTIVES` in the `directives` section of a {@link Component} annotation
* to use `NgForm` and its associated controls.
*
* ### Structure
@ -110,7 +122,7 @@ export class NgForm extends ControlContainer implements Form {
console.warn(`
*It looks like you're using the old forms module. This will be opt-in in the next RC, and
will eventually be removed in favor of the new forms module. For more information, see:
https://docs.google.com/document/u/1/d/1RIezQqE4aEhBRmArIAS1mRIZtWFf6JxN_7B4meyWK0Y/pub
https://docs.google.com/document/d/1RIezQqE4aEhBRmArIAS1mRIZtWFf6JxN_7B4meyWK0Y/preview
`);
}
}
@ -126,7 +138,7 @@ export class NgForm extends ControlContainer implements Form {
get controls(): {[key: string]: AbstractControl} { return this.form.controls; }
addControl(dir: NgControl): void {
PromiseWrapper.scheduleMicrotask(() => {
resolvedPromise.then(() => {
var container = this._findContainer(dir.path);
var ctrl = new Control();
setUpControl(ctrl, dir);
@ -138,7 +150,7 @@ export class NgForm extends ControlContainer implements Form {
getControl(dir: NgControl): Control { return <Control>this.form.find(dir.path); }
removeControl(dir: NgControl): void {
PromiseWrapper.scheduleMicrotask(() => {
resolvedPromise.then(() => {
var container = this._findContainer(dir.path);
if (isPresent(container)) {
container.removeControl(dir.name);
@ -147,7 +159,7 @@ export class NgForm extends ControlContainer implements Form {
}
addControlGroup(dir: NgControlGroup): void {
PromiseWrapper.scheduleMicrotask(() => {
resolvedPromise.then(() => {
var container = this._findContainer(dir.path);
var group = new ControlGroup({});
setUpControlGroup(group, dir);
@ -157,7 +169,7 @@ export class NgForm extends ControlContainer implements Form {
}
removeControlGroup(dir: NgControlGroup): void {
PromiseWrapper.scheduleMicrotask(() => {
resolvedPromise.then(() => {
var container = this._findContainer(dir.path);
if (isPresent(container)) {
container.removeControl(dir.name);
@ -170,7 +182,7 @@ export class NgForm extends ControlContainer implements Form {
}
updateModel(dir: NgControl, value: any): void {
PromiseWrapper.scheduleMicrotask(() => {
resolvedPromise.then(() => {
var ctrl = <Control>this.form.find(dir.path);
ctrl.updateValue(value);
});
@ -178,7 +190,7 @@ export class NgForm extends ControlContainer implements Form {
onSubmit(): boolean {
this._submitted = true;
ObservableWrapper.callEmit(this.ngSubmit, null);
this.ngSubmit.emit(null);
return false;
}

View File

@ -1,6 +1,14 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, Inject, OnChanges, Optional, Self, SimpleChanges, forwardRef} from '@angular/core';
import {EventEmitter, ObservableWrapper} from '../../facade/async';
import {EventEmitter} from '../../facade/async';
import {StringMapWrapper} from '../../facade/collection';
import {Control} from '../model';
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators';
@ -10,11 +18,10 @@ import {NgControl} from './ng_control';
import {composeAsyncValidators, composeValidators, isPropertyUpdated, selectValueAccessor, setUpControl} from './shared';
import {AsyncValidatorFn, ValidatorFn} from './validators';
export const formControlBinding: any =
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
provide: NgControl,
useExisting: forwardRef(() => NgFormControl)
};
export const formControlBinding: any = {
provide: NgControl,
useExisting: forwardRef(() => NgFormControl)
};
/**
* Binds an existing {@link Control} to a DOM element.
@ -111,7 +118,7 @@ export class NgFormControl extends NgControl implements OnChanges {
viewToModelUpdate(newValue: any): void {
this.viewModel = newValue;
ObservableWrapper.callEmit(this.update, newValue);
this.update.emit(newValue);
}
private _isControlChanged(changes: {[key: string]: any}): boolean {

View File

@ -1,6 +1,14 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, Inject, OnChanges, Optional, Self, SimpleChanges, forwardRef} from '@angular/core';
import {EventEmitter, ObservableWrapper} from '../../facade/async';
import {EventEmitter} from '../../facade/async';
import {ListWrapper, StringMapWrapper} from '../../facade/collection';
import {BaseException} from '../../facade/exceptions';
import {isBlank} from '../../facade/lang';
@ -13,11 +21,10 @@ import {NgControl} from './ng_control';
import {NgControlGroup} from './ng_control_group';
import {composeAsyncValidators, composeValidators, setUpControl, setUpControlGroup} from './shared';
export const formDirectiveProvider: any =
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
provide: ControlContainer,
useExisting: forwardRef(() => NgFormModel)
};
export const formDirectiveProvider: any = {
provide: ControlContainer,
useExisting: forwardRef(() => NgFormModel)
};
let _formModelWarningDisplayed: boolean = false;
@ -126,7 +133,7 @@ export class NgFormModel extends ControlContainer implements Form,
console.warn(`
*It looks like you're using the old forms module. This will be opt-in in the next RC, and
will eventually be removed in favor of the new forms module. For more information, see:
https://docs.google.com/document/u/1/d/1RIezQqE4aEhBRmArIAS1mRIZtWFf6JxN_7B4meyWK0Y/pub
https://docs.google.com/document/d/1RIezQqE4aEhBRmArIAS1mRIZtWFf6JxN_7B4meyWK0Y/preview
`);
}
}
@ -184,7 +191,7 @@ export class NgFormModel extends ControlContainer implements Form,
onSubmit(): boolean {
this._submitted = true;
ObservableWrapper.callEmit(this.ngSubmit, null);
this.ngSubmit.emit(null);
return false;
}

View File

@ -1,6 +1,14 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, Inject, OnChanges, Optional, Self, SimpleChanges, forwardRef} from '@angular/core';
import {EventEmitter, ObservableWrapper} from '../../facade/async';
import {EventEmitter} from '../../facade/async';
import {Control} from '../model';
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators';
@ -9,11 +17,10 @@ import {NgControl} from './ng_control';
import {composeAsyncValidators, composeValidators, isPropertyUpdated, selectValueAccessor, setUpControl} from './shared';
import {AsyncValidatorFn, ValidatorFn} from './validators';
export const formControlBinding: any =
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
provide: NgControl,
useExisting: forwardRef(() => NgModel)
};
export const formControlBinding: any = {
provide: NgControl,
useExisting: forwardRef(() => NgModel)
};
/**
* Binds a domain model to a form control.
@ -87,6 +94,6 @@ export class NgModel extends NgControl implements OnChanges {
viewToModelUpdate(newValue: any): void {
this.viewModel = newValue;
ObservableWrapper.callEmit(this.update, newValue);
this.update.emit(newValue);
}
}

View File

@ -1,20 +0,0 @@
library angular2.core.forms.normalize_validators;
import 'package:angular2/src/common/forms/directives/validators.dart' show Validator;
Function normalizeValidator(dynamic validator){
if (validator is Validator) {
return (c) => validator.validate(c);
} else {
return validator;
}
}
Function normalizeAsyncValidator(dynamic validator){
if (validator is Validator) {
return (c) => validator.validate(c);
} else {
return validator;
}
}

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AbstractControl} from '../model';
import {AsyncValidatorFn, Validator, ValidatorFn} from './validators';
@ -12,7 +20,7 @@ export function normalizeValidator(validator: ValidatorFn | Validator): Validato
export function normalizeAsyncValidator(validator: AsyncValidatorFn | Validator): AsyncValidatorFn {
if ((<Validator>validator).validate !== undefined) {
return (c: AbstractControl) => Promise.resolve((<Validator>validator).validate(c));
return (c: AbstractControl) => (<Validator>validator).validate(c);
} else {
return <AsyncValidatorFn>validator;
}

View File

@ -1,10 +1,18 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, ElementRef, Renderer, forwardRef} from '@angular/core';
import {NumberWrapper} from '../../facade/lang';
import {NumberWrapper, isBlank} from '../../facade/lang';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
export const NUMBER_VALUE_ACCESSOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
export const NUMBER_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NumberValueAccessor),
multi: true
@ -36,7 +44,9 @@ export class NumberValueAccessor implements ControlValueAccessor {
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
writeValue(value: number): void {
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', value);
// The value needs to be normalized for IE9, otherwise it is set to 'null' when null
const normalizedValue = isBlank(value) ? '' : value;
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', normalizedValue);
}
registerOnChange(fn: (_: number) => void): void {

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, ElementRef, Injectable, Injector, Input, OnDestroy, OnInit, Renderer, forwardRef} from '@angular/core';
import {ListWrapper} from '../../facade/collection';
@ -6,7 +14,7 @@ import {isPresent} from '../../facade/lang';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
import {NgControl} from './ng_control';
export const RADIO_VALUE_ACCESSOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
export const RADIO_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RadioControlValueAccessor),
multi: true

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, ElementRef, Host, Input, OnDestroy, Optional, Renderer, forwardRef} from '@angular/core';
import {MapWrapper} from '../../facade/collection';
@ -5,7 +13,7 @@ import {StringWrapper, isBlank, isPresent, isPrimitive, looseIdentical} from '..
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
export const SELECT_VALUE_ACCESSOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
export const SELECT_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SelectControlValueAccessor),
multi: true

View File

@ -1,11 +1,19 @@
import {Directive, ElementRef, Host, Input, OnDestroy, Optional, Renderer, forwardRef} from '@angular/core';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Directive, ElementRef, Host, Input, OnDestroy, OpaqueToken, Optional, Renderer, Type, forwardRef} from '@angular/core';
import {MapWrapper} from '../../facade/collection';
import {StringWrapper, isBlank, isPresent, isPrimitive, isString, looseIdentical} from '../../facade/lang';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
const SELECT_MULTIPLE_VALUE_ACCESSOR = {
export const SELECT_MULTIPLE_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SelectMultipleControlValueAccessor),
multi: true
@ -39,7 +47,7 @@ abstract class HTMLCollection {
*/
@Directive({
selector: 'select[multiple][ngControl],select[multiple][ngFormControl],select[multiple][ngModel]',
host: {'(input)': 'onChange($event.target)', '(blur)': 'onTouched()'},
host: {'(change)': 'onChange($event.target)', '(blur)': 'onTouched()'},
providers: [SELECT_MULTIPLE_VALUE_ACCESSOR]
})
export class SelectMultipleControlValueAccessor implements ControlValueAccessor {
@ -174,4 +182,4 @@ export class NgSelectMultipleOption implements OnDestroy {
}
}
export const SELECT_DIRECTIVES = [SelectMultipleControlValueAccessor, NgSelectMultipleOption];
export const SELECT_DIRECTIVES = [SelectMultipleControlValueAccessor, NgSelectMultipleOption];

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ListWrapper, StringMapWrapper} from '../../facade/collection';
import {BaseException} from '../../facade/exceptions';
import {hasConstructor, isBlank, isPresent, looseIdentical} from '../../facade/lang';
@ -15,6 +23,7 @@ import {normalizeAsyncValidator, normalizeValidator} from './normalize_validator
import {NumberValueAccessor} from './number_value_accessor';
import {RadioControlValueAccessor} from './radio_control_value_accessor';
import {SelectControlValueAccessor} from './select_control_value_accessor';
import {SelectMultipleControlValueAccessor} from './select_multiple_control_value_accessor';
import {AsyncValidatorFn, ValidatorFn} from './validators';
@ -25,8 +34,8 @@ export function controlPath(name: string, parent: ControlContainer): string[] {
}
export function setUpControl(control: Control, dir: NgControl): void {
if (isBlank(control)) _throwError(dir, 'Cannot find control');
if (isBlank(dir.valueAccessor)) _throwError(dir, 'No value accessor for');
if (isBlank(control)) _throwError(dir, 'Cannot find control with');
if (isBlank(dir.valueAccessor)) _throwError(dir, 'No value accessor for form control with');
control.validator = Validators.compose([control.validator, dir.validator]);
control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]);
@ -47,14 +56,21 @@ export function setUpControl(control: Control, dir: NgControl): void {
}
export function setUpControlGroup(control: ControlGroup, dir: NgControlGroup) {
if (isBlank(control)) _throwError(dir, 'Cannot find control');
if (isBlank(control)) _throwError(dir, 'Cannot find control with');
control.validator = Validators.compose([control.validator, dir.validator]);
control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]);
}
function _throwError(dir: AbstractControlDirective, message: string): void {
var path = dir.path.join(' -> ');
throw new BaseException(`${message} '${path}'`);
let messageEnd: string;
if (dir.path.length > 1) {
messageEnd = `path: '${dir.path.join(' -> ')}'`;
} else if (dir.path[0]) {
messageEnd = `name: '${dir.path}'`;
} else {
messageEnd = 'unspecified name';
}
throw new BaseException(`${message} ${messageEnd}`);
}
export function composeValidators(validators: /* Array<Validator|Function> */ any[]): ValidatorFn {
@ -90,14 +106,15 @@ export function selectValueAccessor(
} else if (
hasConstructor(v, CheckboxControlValueAccessor) || hasConstructor(v, NumberValueAccessor) ||
hasConstructor(v, SelectControlValueAccessor) ||
hasConstructor(v, SelectMultipleControlValueAccessor) ||
hasConstructor(v, RadioControlValueAccessor)) {
if (isPresent(builtinAccessor))
_throwError(dir, 'More than one built-in value accessor matches');
_throwError(dir, 'More than one built-in value accessor matches form control with');
builtinAccessor = v;
} else {
if (isPresent(customAccessor))
_throwError(dir, 'More than one custom value accessor matches');
_throwError(dir, 'More than one custom value accessor matches form control with');
customAccessor = v;
}
});
@ -106,6 +123,6 @@ export function selectValueAccessor(
if (isPresent(builtinAccessor)) return builtinAccessor;
if (isPresent(defaultAccessor)) return defaultAccessor;
_throwError(dir, 'No valid value accessor for');
_throwError(dir, 'No valid value accessor for form control with');
return null;
}

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Attribute, Directive, forwardRef} from '@angular/core';
import {NumberWrapper} from '../../facade/lang';
@ -22,12 +30,14 @@ import {NG_VALIDATORS, Validators} from '../validators';
* }
* }
* ```
*
* @experimental
*/
export interface Validator { validate(c: AbstractControl): {[key: string]: any}; }
const REQUIRED = /*@ts2dart_const*/ Validators.required;
export const REQUIRED = Validators.required;
export const REQUIRED_VALIDATOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
export const REQUIRED_VALIDATOR: any = {
provide: NG_VALIDATORS,
useValue: REQUIRED,
multi: true
@ -64,7 +74,7 @@ export interface AsyncValidatorFn {
*
* {@example common/forms/ts/validators/validators.ts region='min'}
*/
export const MIN_LENGTH_VALIDATOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
export const MIN_LENGTH_VALIDATOR: any = {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => MinLengthValidator),
multi: true
@ -97,7 +107,7 @@ export class MinLengthValidator implements Validator {
*
* {@example common/forms/ts/validators/validators.ts region='max'}
*/
export const MAX_LENGTH_VALIDATOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
export const MAX_LENGTH_VALIDATOR: any = {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => MaxLengthValidator),
multi: true
@ -124,7 +134,7 @@ export class MaxLengthValidator implements Validator {
}
export const PATTERN_VALIDATOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
export const PATTERN_VALIDATOR: any = {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => PatternValidator),
multi: true

View File

@ -1,10 +1,18 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Injectable} from '@angular/core';
import {StringMapWrapper} from '../facade/collection';
import {isArray, isPresent} from '../facade/lang';
import {AsyncValidatorFn, ValidatorFn} from './directives/validators';
import * as modelModule from './model';
import {AbstractControl, Control, ControlArray, ControlGroup} from './model';
@ -59,22 +67,21 @@ export class FormBuilder {
*
* See the {@link ControlGroup} constructor for more details.
*/
group(controlsConfig: {[key: string]: any}, extra: {[key: string]: any} = null):
modelModule.ControlGroup {
group(controlsConfig: {[key: string]: any}, extra: {[key: string]: any} = null): ControlGroup {
var controls = this._reduceControls(controlsConfig);
var optionals = <{[key: string]: boolean}>(
isPresent(extra) ? StringMapWrapper.get(extra, 'optionals') : null);
var validator: ValidatorFn = isPresent(extra) ? StringMapWrapper.get(extra, 'validator') : null;
var asyncValidator: AsyncValidatorFn =
isPresent(extra) ? StringMapWrapper.get(extra, 'asyncValidator') : null;
return new modelModule.ControlGroup(controls, optionals, validator, asyncValidator);
return new ControlGroup(controls, optionals, validator, asyncValidator);
}
/**
* Construct a new {@link Control} with the given `value`,`validator`, and `asyncValidator`.
*/
control(value: Object, validator: ValidatorFn = null, asyncValidator: AsyncValidatorFn = null):
modelModule.Control {
return new modelModule.Control(value, validator, asyncValidator);
Control {
return new Control(value, validator, asyncValidator);
}
/**
@ -83,15 +90,14 @@ export class FormBuilder {
*/
array(
controlsConfig: any[], validator: ValidatorFn = null,
asyncValidator: AsyncValidatorFn = null): modelModule.ControlArray {
asyncValidator: AsyncValidatorFn = null): ControlArray {
var controls = controlsConfig.map(c => this._createControl(c));
return new modelModule.ControlArray(controls, validator, asyncValidator);
return new ControlArray(controls, validator, asyncValidator);
}
/** @internal */
_reduceControls(controlsConfig: {[k: string]: any}):
{[key: string]: modelModule.AbstractControl} {
var controls: {[key: string]: modelModule.AbstractControl} = {};
_reduceControls(controlsConfig: {[k: string]: any}): {[key: string]: AbstractControl} {
var controls: {[key: string]: AbstractControl} = {};
StringMapWrapper.forEach(controlsConfig, (controlConfig: any, controlName: string) => {
controls[controlName] = this._createControl(controlConfig);
});
@ -99,10 +105,9 @@ export class FormBuilder {
}
/** @internal */
_createControl(controlConfig: any): modelModule.AbstractControl {
if (controlConfig instanceof modelModule.Control ||
controlConfig instanceof modelModule.ControlGroup ||
controlConfig instanceof modelModule.ControlArray) {
_createControl(controlConfig: any): AbstractControl {
if (controlConfig instanceof Control || controlConfig instanceof ControlGroup ||
controlConfig instanceof ControlArray) {
return controlConfig;
} else if (isArray(controlConfig)) {

View File

@ -1,8 +1,20 @@
import {EventEmitter, Observable, ObservableWrapper} from '../facade/async';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {PromiseObservable} from 'rxjs/observable/PromiseObservable';
import {EventEmitter, Observable} from '../facade/async';
import {ListWrapper, StringMapWrapper} from '../facade/collection';
import {isBlank, isPresent, isPromise, normalizeBool} from '../facade/lang';
import {AsyncValidatorFn, ValidatorFn} from './directives/validators';
/**
* Indicates that a Control is valid, i.e. that no errors exist in the input value.
*/
@ -44,7 +56,7 @@ function _find(control: AbstractControl, path: Array<string|number>| string) {
}
function toObservable(r: any): Observable<any> {
return isPromise(r) ? ObservableWrapper.fromPromise(r) : r;
return isPromise(r) ? PromiseObservable.create(r) : r;
}
/**
@ -127,8 +139,8 @@ export abstract class AbstractControl {
}
if (emitEvent) {
ObservableWrapper.callEmit(this._valueChanges, this._value);
ObservableWrapper.callEmit(this._statusChanges, this._status);
this._valueChanges.emit(this._value);
this._statusChanges.emit(this._status);
}
if (isPresent(this._parent) && !onlySelf) {
@ -145,14 +157,14 @@ export abstract class AbstractControl {
this._status = PENDING;
this._cancelExistingSubscription();
var obs = toObservable(this.asyncValidator(this));
this._asyncValidationSubscription = ObservableWrapper.subscribe(
obs, (res: {[key: string]: any}) => this.setErrors(res, {emitEvent: emitEvent}));
this._asyncValidationSubscription = obs.subscribe(
{next: (res: {[key: string]: any}) => this.setErrors(res, {emitEvent: emitEvent})});
}
}
private _cancelExistingSubscription(): void {
if (isPresent(this._asyncValidationSubscription)) {
ObservableWrapper.dispose(this._asyncValidationSubscription);
this._asyncValidationSubscription.unsubscribe();
}
}
@ -186,7 +198,7 @@ export abstract class AbstractControl {
this._status = this._calculateStatus();
if (emitEvent) {
ObservableWrapper.callEmit(this._statusChanges, this._status);
this._statusChanges.emit(this._status);
}
if (isPresent(this._parent)) {

View File

@ -1,10 +1,20 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core';
import {ObservableWrapper} from '../facade/async';
import {toPromise} from 'rxjs/operator/toPromise';
import {StringMapWrapper} from '../facade/collection';
import {isBlank, isPresent, isPromise, isString} from '../facade/lang';
import {PromiseWrapper} from '../facade/promise';
import {AsyncValidatorFn, ValidatorFn} from './directives/validators';
import * as modelModule from './model';
import {AbstractControl} from './model';
/**
* Providers for validators to be used for {@link Control}s in a form.
@ -16,7 +26,7 @@ import * as modelModule from './model';
* {@example core/forms/ts/ng_validators/ng_validators.ts region='ng_validators'}
* @experimental
*/
export const NG_VALIDATORS: OpaqueToken = /*@ts2dart_const*/ new OpaqueToken('NgValidators');
export const NG_VALIDATORS: OpaqueToken = new OpaqueToken('NgValidators');
/**
* Providers for asynchronous validators to be used for {@link Control}s
@ -28,8 +38,7 @@ export const NG_VALIDATORS: OpaqueToken = /*@ts2dart_const*/ new OpaqueToken('Ng
*
* @experimental
*/
export const NG_ASYNC_VALIDATORS: OpaqueToken =
/*@ts2dart_const*/ new OpaqueToken('NgAsyncValidators');
export const NG_ASYNC_VALIDATORS: OpaqueToken = new OpaqueToken('NgAsyncValidators');
/**
* Provides a set of validators used by form controls.
@ -49,7 +58,7 @@ export class Validators {
/**
* Validator that requires controls to have a non-empty value.
*/
static required(control: modelModule.AbstractControl): {[key: string]: boolean} {
static required(control: AbstractControl): {[key: string]: boolean} {
return isBlank(control.value) || (isString(control.value) && control.value == '') ?
{'required': true} :
null;
@ -59,7 +68,7 @@ export class Validators {
* Validator that requires controls to have a value of a minimum length.
*/
static minLength(minLength: number): ValidatorFn {
return (control: modelModule.AbstractControl): {[key: string]: any} => {
return (control: AbstractControl): {[key: string]: any} => {
if (isPresent(Validators.required(control))) return null;
var v: string = control.value;
return v.length < minLength ?
@ -72,7 +81,7 @@ export class Validators {
* Validator that requires controls to have a value of a maximum length.
*/
static maxLength(maxLength: number): ValidatorFn {
return (control: modelModule.AbstractControl): {[key: string]: any} => {
return (control: AbstractControl): {[key: string]: any} => {
if (isPresent(Validators.required(control))) return null;
var v: string = control.value;
return v.length > maxLength ?
@ -85,7 +94,7 @@ export class Validators {
* Validator that requires a control to match a regex to its value.
*/
static pattern(pattern: string): ValidatorFn {
return (control: modelModule.AbstractControl): {[key: string]: any} => {
return (control: AbstractControl): {[key: string]: any} => {
if (isPresent(Validators.required(control))) return null;
let regex = new RegExp(`^${pattern}$`);
let v: string = control.value;
@ -97,7 +106,7 @@ export class Validators {
/**
* No-op validator.
*/
static nullValidator(c: modelModule.AbstractControl): {[key: string]: boolean} { return null; }
static nullValidator(c: AbstractControl): {[key: string]: boolean} { return null; }
/**
* Compose multiple validators into a single function that returns the union
@ -108,7 +117,7 @@ export class Validators {
var presentValidators = validators.filter(isPresent);
if (presentValidators.length == 0) return null;
return function(control: modelModule.AbstractControl) {
return function(control: AbstractControl) {
return _mergeErrors(_executeValidators(control, presentValidators));
};
}
@ -118,24 +127,22 @@ export class Validators {
var presentValidators = validators.filter(isPresent);
if (presentValidators.length == 0) return null;
return function(control: modelModule.AbstractControl) {
return function(control: AbstractControl) {
let promises = _executeAsyncValidators(control, presentValidators).map(_convertToPromise);
return PromiseWrapper.all(promises).then(_mergeErrors);
return Promise.all(promises).then(_mergeErrors);
};
}
}
function _convertToPromise(obj: any): Promise<any> {
return isPromise(obj) ? obj : ObservableWrapper.toPromise(obj);
return isPromise(obj) ? obj : toPromise.call(obj);
}
function _executeValidators(
control: modelModule.AbstractControl, validators: ValidatorFn[]): any[] {
function _executeValidators(control: AbstractControl, validators: ValidatorFn[]): any[] {
return validators.map(v => v(control));
}
function _executeAsyncValidators(
control: modelModule.AbstractControl, validators: AsyncValidatorFn[]): any[] {
function _executeAsyncValidators(control: AbstractControl, validators: AsyncValidatorFn[]): any[] {
return validators.map(v => v(control));
}

View File

@ -0,0 +1,26 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* @experimental
*/
export abstract class NgLocalization { abstract getPluralCategory(value: any): string; }
/**
* Returns the plural category for a given value.
* - "=value" when the case exists,
* - the plural category otherwise
*
* @internal
*/
export function getPluralCategory(
value: number, cases: string[], ngLocalization: NgLocalization): string {
const nbCase = `=${value}`;
return cases.indexOf(nbCase) > -1 ? nbCase : ngLocalization.getPluralCategory(value);
}

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export * from './location/platform_location';
export * from './location/location_strategy';
export * from './location/hash_location_strategy';

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Inject, Injectable, Optional} from '@angular/core';
import {isPresent} from '../facade/lang';
@ -69,16 +77,13 @@ export class HashLocationStrategy extends LocationStrategy {
getBaseHref(): string { return this._baseHref; }
path(): string {
path(includeHash: boolean = false): string {
// the hash value is always prefixed with a `#`
// and if it is empty then it will stay empty
var path = this._platformLocation.hash;
if (!isPresent(path)) path = '#';
// Dart will complain if a call to substring is
// executed with a position value that extends the
// length of string.
return (path.length > 0 ? path.substring(1) : path);
return path.length > 0 ? path.substring(1) : path;
}
prepareExternalUrl(internal: string): string {

View File

@ -1,6 +1,12 @@
import {EventEmitter, Injectable} from '@angular/core';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ObservableWrapper} from '../facade/async';
import {EventEmitter, Injectable} from '@angular/core';
import {LocationStrategy} from './location_strategy';
@ -61,15 +67,18 @@ export class Location {
this._platformStrategy = platformStrategy;
var browserBaseHref = this._platformStrategy.getBaseHref();
this._baseHref = Location.stripTrailingSlash(_stripIndexHtml(browserBaseHref));
this._platformStrategy.onPopState((ev) => {
ObservableWrapper.callEmit(this._subject, {'url': this.path(), 'pop': true, 'type': ev.type});
});
this._platformStrategy.onPopState(
(ev) => { this._subject.emit({'url': this.path(true), 'pop': true, 'type': ev.type}); });
}
/**
* Returns the normalized URL path.
*/
path(): string { return this.normalize(this._platformStrategy.path()); }
// TODO: vsavkin. Remove the boolean flag and always include hash once the deprecated router is
// removed.
path(includeHash: boolean = false): string {
return this.normalize(this._platformStrategy.path(includeHash));
}
/**
* Normalizes the given path and compares to the current normalized path.
@ -132,7 +141,7 @@ export class Location {
subscribe(
onNext: (value: any) => void, onThrow: (exception: any) => void = null,
onReturn: () => void = null): Object {
return ObservableWrapper.subscribe(this._subject, onNext, onThrow, onReturn);
return this._subject.subscribe({next: onNext, error: onThrow, complete: onReturn});
}
/**

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {OpaqueToken} from '@angular/core';
import {UrlChangeListener} from './platform_location';
@ -20,7 +28,7 @@ import {UrlChangeListener} from './platform_location';
* @stable
*/
export abstract class LocationStrategy {
abstract path(): string;
abstract path(includeHash?: boolean): string;
abstract prepareExternalUrl(internal: string): string;
abstract pushState(state: any, title: string, url: string, queryParams: string): void;
abstract replaceState(state: any, title: string, url: string, queryParams: string): void;
@ -61,4 +69,4 @@ export abstract class LocationStrategy {
* ```
* @stable
*/
export const APP_BASE_HREF: OpaqueToken = /*@ts2dart_const*/ new OpaqueToken('appBaseHref');
export const APP_BASE_HREF: OpaqueToken = new OpaqueToken('appBaseHref');

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Inject, Injectable, Optional} from '@angular/core';
import {BaseException} from '../facade/exceptions';
@ -17,44 +25,17 @@ import {PlatformLocation, UrlChangeListener} from './platform_location';
* `PathLocationStrategy` is the default binding for {@link LocationStrategy}
* provided in {@link ROUTER_PROVIDERS}.
*
* If you're using `PathLocationStrategy`, you must provide a provider for
* {@link APP_BASE_HREF} to a string representing the URL prefix that should
* be preserved when generating and recognizing URLs.
* If you're using `PathLocationStrategy`, you must provide a {@link APP_BASE_HREF}
* or add a base element to the document. This URL prefix that will be preserved
* when generating and recognizing URLs.
*
* For instance, if you provide an `APP_BASE_HREF` of `'/my/app'` and call
* `location.go('/foo')`, the browser's URL will become
* `example.com/my/app/foo`.
*
* ### Example
*
* ```
* import {Component} from '@angular/core';
* import {bootstrap} from '@angular/platform-browser/browser';
* import {
* Location,
* APP_BASE_HREF
* } from '@angular/common';
* import {
* ROUTER_DIRECTIVES,
* ROUTER_PROVIDERS,
* RouteConfig
* } from '@angular/router';
*
* @Component({directives: [ROUTER_DIRECTIVES]})
* @RouteConfig([
* {...},
* ])
* class AppCmp {
* constructor(location: Location) {
* location.go('/foo');
* }
* }
*
* bootstrap(AppCmp, [
* ROUTER_PROVIDERS, // includes binding to PathLocationStrategy
* {provide: APP_BASE_HREF, useValue: '/my/app'}
* ]);
* ```
* Similarly, if you add `<base href='/my/app'/>` to the document and call
* `location.go('/foo')`, the browser's URL will become
* `example.com/my/app/foo`.
*
* @stable
*/
@ -90,9 +71,11 @@ export class PathLocationStrategy extends LocationStrategy {
return Location.joinWithSlash(this._baseHref, internal);
}
path(): string {
return this._platformLocation.pathname +
path(includeHash: boolean = false): string {
const pathname = this._platformLocation.pathname +
Location.normalizeQueryParams(this._platformLocation.search);
const hash = this._platformLocation.hash;
return hash && includeHash ? `${pathname}${hash}` : pathname;
}
pushState(state: any, title: string, url: string, queryParams: string) {

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* This class should not be used directly by an application developer. Instead, use
* {@link Location}.
@ -45,8 +53,11 @@ export abstract class PlatformLocation {
/**
* A serializable version of the event from onPopState or onHashChange
*
* @stable
* @experimental
*/
export interface UrlChangeEvent { type: string; }
/**
* @experimental
*/
export interface UrlChangeListener { (e: UrlChangeEvent): any; }

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* @module
* @description

View File

@ -1,5 +1,13 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectorRef, OnDestroy, Pipe, WrappedValue} from '@angular/core';
import {EventEmitter, Observable, ObservableWrapper} from '../facade/async';
import {EventEmitter, Observable} from '../facade/async';
import {isBlank, isPresent, isPromise} from '../facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
@ -11,12 +19,12 @@ interface SubscriptionStrategy {
class ObservableStrategy implements SubscriptionStrategy {
createSubscription(async: any, updateLatestValue: any): any {
return ObservableWrapper.subscribe(async, updateLatestValue, e => { throw e; });
return async.subscribe({next: updateLatestValue, error: (e: any) => { throw e; }});
}
dispose(subscription: any): void { ObservableWrapper.dispose(subscription); }
dispose(subscription: any): void { subscription.unsubscribe(); }
onDestroy(subscription: any): void { ObservableWrapper.dispose(subscription); }
onDestroy(subscription: any): void { subscription.unsubscribe(); }
}
class PromiseStrategy implements SubscriptionStrategy {
@ -117,7 +125,7 @@ export class AsyncPipe implements OnDestroy {
_selectStrategy(obj: Observable<any>|Promise<any>|EventEmitter<any>): any {
if (isPromise(obj)) {
return _promiseStrategy;
} else if (ObservableWrapper.isObservable(obj)) {
} else if ((<any>obj).subscribe) {
return _observableStrategy;
} else {
throw new InvalidPipeArgumentException(AsyncPipe, obj);

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* @module
* @description
@ -24,7 +32,7 @@ import {UpperCasePipe} from './uppercase_pipe';
*
* @experimental Contains i18n pipes which are experimental
*/
export const COMMON_PIPES = /*@ts2dart_const*/[
export const COMMON_PIPES = [
AsyncPipe,
UpperCasePipe,
LowerCasePipe,

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Pipe, PipeTransform} from '@angular/core';
import {StringMapWrapper} from '../facade/collection';
import {DateFormatter} from '../facade/intl';
@ -43,9 +51,6 @@ var defaultLocale: string = 'en-US';
*
* In javascript, only the components specified will be respected (not the ordering,
* punctuations, ...) and details of the formatting will be dependent on the locale.
* On the other hand in Dart version, you can also include quoted text as well as some extra
* date/time components such as quarter. For more information see:
* https://www.dartdocs.org/documentation/intl/0.13.0/intl/DateFormat-class.html
*
* `format` can also be one of the following predefined formats:
*

View File

@ -1,31 +1,52 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Pipe, PipeTransform} from '@angular/core';
import {StringWrapper, isPresent, isStringMap} from '../facade/lang';
import {StringWrapper, isBlank, isStringMap} from '../facade/lang';
import {NgLocalization, getPluralCategory} from '../localization';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
const _INTERPOLATION_REGEXP: RegExp = /#/g;
/**
*
* Maps a value to a string that pluralizes the value properly.
*
* ## Usage
*
* expression | i18nPlural:mapping
*
* where `expression` is a number and `mapping` is an object that indicates the proper text for
* when the `expression` evaluates to 0, 1, or some other number. You can interpolate the actual
* value into the text using the `#` sign.
* where `expression` is a number and `mapping` is an object that mimics the ICU format,
* see http://userguide.icu-project.org/formatparse/messages
*
* ## Example
*
* ```
* <div>
* {{ messages.length | i18nPlural: messageMapping }}
* </div>
* class MyLocalization extends NgLocalization {
* getPluralCategory(value: any) {
* if(value > 1) {
* return 'other';
* }
* }
* }
*
* @Component({
* selector: 'app',
* template: `
* <div>
* {{ messages.length | i18nPlural: messageMapping }}
* </div>
* `,
* providers: [{provide: NgLocalization, useClass: MyLocalization}]
* })
*
* class MyApp {
* messages: any[];
* messageMapping: any = {
* messageMapping: {[k:string]: string} = {
* '=0': 'No messages.',
* '=1': 'One message.',
* 'other': '# messages.'
@ -38,17 +59,17 @@ const _INTERPOLATION_REGEXP: RegExp = /#/g;
*/
@Pipe({name: 'i18nPlural', pure: true})
export class I18nPluralPipe implements PipeTransform {
constructor(private _localization: NgLocalization) {}
transform(value: number, pluralMap: {[count: string]: string}): string {
var key: string;
var valueStr: string;
if (isBlank(value)) return '';
if (!isStringMap(pluralMap)) {
throw new InvalidPipeArgumentException(I18nPluralPipe, pluralMap);
}
key = value === 0 || value === 1 ? `=${value}` : 'other';
valueStr = isPresent(value) ? value.toString() : '';
const key = getPluralCategory(value, Object.keys(pluralMap), this._localization);
return StringWrapper.replaceAll(pluralMap[key], _INTERPOLATION_REGEXP, valueStr);
return StringWrapper.replaceAll(pluralMap[key], _INTERPOLATION_REGEXP, value.toString());
}
}

View File

@ -1,8 +1,14 @@
import {Pipe, PipeTransform} from '@angular/core';
import {StringMapWrapper} from '../facade/collection';
import {isStringMap} from '../facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Pipe, PipeTransform} from '@angular/core';
import {isBlank, isStringMap} from '../facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
/**
*
@ -25,8 +31,8 @@ import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
* class MyApp {
* gender: string = 'male';
* inviteMap: any = {
* 'male': 'Invite her.',
* 'female': 'Invite him.',
* 'male': 'Invite him.',
* 'female': 'Invite her.',
* 'other': 'Invite them.'
* }
* ...
@ -38,10 +44,12 @@ import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
@Pipe({name: 'i18nSelect', pure: true})
export class I18nSelectPipe implements PipeTransform {
transform(value: string, mapping: {[key: string]: string}): string {
if (isBlank(value)) return '';
if (!isStringMap(mapping)) {
throw new InvalidPipeArgumentException(I18nSelectPipe, mapping);
}
return StringMapWrapper.contains(mapping, value) ? mapping[value] : mapping['other'];
return mapping.hasOwnProperty(value) ? mapping[value] : '';
}
}

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {BaseException} from '../facade/exceptions';
import {Type, stringify} from '../facade/lang';

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Pipe, PipeTransform} from '@angular/core';
import {Json} from '../facade/lang';

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Pipe, PipeTransform} from '@angular/core';
import {isBlank, isString} from '../facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';

View File

@ -1,27 +1,44 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Pipe, PipeTransform} from '@angular/core';
import {BaseException} from '../facade/exceptions';
import {NumberFormatStyle, NumberFormatter} from '../facade/intl';
import {NumberWrapper, RegExpWrapper, Type, isBlank, isNumber, isPresent} from '../facade/lang';
import {NumberWrapper, Type, isBlank, isNumber, isPresent, isString} from '../facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
var defaultLocale: string = 'en-US';
const _NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(\-(\d+))?)?$/g;
const _NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(\-(\d+))?)?$/;
/**
* Internal function to format numbers used by Decimal, Percent and Date pipes.
*/
function formatNumber(
pipe: Type, value: number, style: NumberFormatStyle, digits: string, currency: string = null,
currencyAsSymbol: boolean = false): string {
pipe: Type, value: number | string, style: NumberFormatStyle, digits: string,
currency: string = null, currencyAsSymbol: boolean = false): string {
if (isBlank(value)) return null;
// Convert strings to numbers
value = isString(value) && NumberWrapper.isNumeric(value) ? +value : value;
if (!isNumber(value)) {
throw new InvalidPipeArgumentException(pipe, value);
}
var minInt = 1, minFraction = 0, maxFraction = 3;
let minInt: number;
let minFraction: number;
let maxFraction: number;
if (style !== NumberFormatStyle.Currency) {
// rely on Intl default for currency
minInt = 1;
minFraction = 0;
maxFraction = 3;
}
if (isPresent(digits)) {
var parts = RegExpWrapper.firstMatch(_NUMBER_FORMAT_REGEXP, digits);
if (isBlank(parts)) {
throw new BaseException(`${digits} is not a valid digit info for number pipes`);
var parts = digits.match(_NUMBER_FORMAT_REGEXP);
if (parts === null) {
throw new Error(`${digits} is not a valid digit info for number pipes`);
}
if (isPresent(parts[1])) { // min integer digits
minInt = NumberWrapper.parseIntAutoRadix(parts[1]);
@ -33,7 +50,7 @@ function formatNumber(
maxFraction = NumberWrapper.parseIntAutoRadix(parts[5]);
}
}
return NumberFormatter.format(value, defaultLocale, style, {
return NumberFormatter.format(value as number, defaultLocale, style, {
minimumIntegerDigits: minInt,
minimumFractionDigits: minFraction,
maximumFractionDigits: maxFraction,

View File

@ -1,5 +1,13 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Pipe, PipeTransform} from '@angular/core';
import {RegExpWrapper, StringWrapper, isBlank, isFunction, isNumber, isString} from '../facade/lang';
import {StringWrapper, isBlank, isFunction, isNumber, isString} from '../facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
/**
@ -53,7 +61,7 @@ export class ReplacePipe implements PipeTransform {
}
if (isFunction(replacement)) {
const rgxPattern = isString(pattern) ? RegExpWrapper.create(pattern) : pattern;
const rgxPattern = isString(pattern) ? new RegExp(pattern, 'g') : pattern;
return StringWrapper.replaceAllMapped(
input, rgxPattern, <(m: string[]) => string>replacement);

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Pipe, PipeTransform} from '@angular/core';
import {ListWrapper} from '../facade/collection';
import {StringWrapper, isArray, isBlank, isString} from '../facade/lang';

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Pipe, PipeTransform} from '@angular/core';
import {isBlank, isString} from '../facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';

View File

@ -1,9 +1,16 @@
import {beforeEach, beforeEachProviders, ddescribe, xdescribe, describe, expect, iit, inject, it, xit,} from '@angular/core/testing/testing_internal';
import {ComponentFixture, TestComponentBuilder} from '@angular/compiler/testing';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {ListWrapper, StringMapWrapper, SetWrapper} from '../../src/facade/collection';
import {Component, provide} from '@angular/core';
import {NgFor, NgClass} from '@angular/common';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {NgClass, NgFor} from '@angular/common';
import {Component} from '@angular/core';
import {ComponentFixture, TestComponentBuilder} from '@angular/core/testing';
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, expect, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {ListWrapper, StringMapWrapper} from '../../src/facade/collection';
function detectChangesAndCheck(fixture: ComponentFixture<any>, classes: string) {
fixture.detectChanges();
@ -20,7 +27,7 @@ export function main() {
var template = '<div *ngFor="let item of items" [ngClass]="item"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
.then((fixture: ComponentFixture<TestComponent>) => {
fixture.debugElement.componentInstance.items = [['0']];
fixture.detectChanges();
fixture.debugElement.componentInstance.items = [['1']];
@ -574,7 +581,7 @@ export function main() {
}));
});
})
});
}
@Component({selector: 'test-cmp', directives: [NgClass, NgFor], template: ''})

View File

@ -1,18 +1,25 @@
import {beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xit,} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {NgFor, NgIf} from '@angular/common';
import {Component, ContentChild, TemplateRef} from '@angular/core';
import {TestComponentBuilder} from '@angular/core/testing';
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {expect} from '@angular/platform-browser/testing/matchers';
import {ListWrapper} from '../../src/facade/collection';
import {IS_DART} from '../../src/facade/lang';
import {Component, TemplateRef, ContentChild} from '@angular/core';
import {NgFor} from '@angular/common';
import {NgIf} from '@angular/common';
import {By} from '@angular/platform-browser/src/dom/debug/by';
let thisArg: any;
export function main() {
describe('ngFor', () => {
var TEMPLATE =
const TEMPLATE =
'<div><copy-me template="ngFor let item of items">{{item.toString()}};</copy-me></div>';
it('should reflect initial elements',
@ -102,7 +109,7 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template =
const template =
'<ul><li template="ngFor let item of items">{{item["name"]}};</li></ul>';
tcb.overrideTemplate(TestComponent, template)
@ -135,7 +142,7 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template = '<ul><li template="ngFor let item of null">{{item}};</li></ul>';
const template = '<ul><li template="ngFor let item of null">{{item}};</li></ul>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
@ -166,25 +173,18 @@ export function main() {
});
}));
if (!IS_DART) {
it('should throw on non-iterable ref and suggest using an array',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
tcb.overrideTemplate(TestComponent, TEMPLATE)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.items = 'whaaa';
try {
fixture.detectChanges()
} catch (e) {
expect(e.message).toContain(
`Cannot find a differ supporting object 'whaaa' of type 'string'. NgFor only supports binding to Iterables such as Arrays.`);
async.done();
}
});
}));
}
it('should throw on non-iterable ref and suggest using an array',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
tcb.overrideTemplate(TestComponent, TEMPLATE).createAsync(TestComponent).then((fixture) => {
fixture.debugElement.componentInstance.items = 'whaaa';
expect(() => fixture.detectChanges())
.toThrowError(
/Cannot find a differ supporting object 'whaaa' of type 'string'. NgFor only supports binding to Iterables such as Arrays/);
async.done();
});
}));
it('should throw on ref changing to string',
inject(
@ -221,7 +221,7 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template = '<div>' +
const template = '<div>' +
'<div template="ngFor let item of items">' +
'<div template="ngFor let subitem of item">' +
'{{subitem}}-{{item.length}};' +
@ -250,7 +250,7 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template = '<div><template ngFor let-item [ngForOf]="items">' +
const template = '<div><template ngFor let-item [ngForOf]="items">' +
'<div template="ngFor let subitem of item">' +
'{{subitem}}-{{item.length}};' +
'</div></template></div>';
@ -273,15 +273,15 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template =
const template =
`<div><template ngFor let-item [ngForOf]="items" let-i="index"><div>{{i}}|</div>` +
`<div *ngIf="i % 2 == 0">even|</div></template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
var el = fixture.debugElement.nativeElement;
var items = [1];
const el = fixture.debugElement.nativeElement;
const items = [1];
fixture.debugElement.componentInstance.items = items;
fixture.detectChanges();
expect(el).toHaveText('0|even|');
@ -302,7 +302,7 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template =
const template =
'<div><copy-me template="ngFor: let item of items; let i=index">{{i.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
@ -323,7 +323,7 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template =
const template =
'<div><copy-me template="ngFor: let item of items; let isFirst=first">{{isFirst.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
@ -344,7 +344,7 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template =
const template =
'<div><copy-me template="ngFor: let item of items; let isLast=last">{{isLast.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
@ -365,7 +365,7 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template =
const template =
'<div><copy-me template="ngFor: let item of items; let isEven=even">{{isEven.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
@ -386,7 +386,7 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template =
const template =
'<div><copy-me template="ngFor: let item of items; let isOdd=odd">{{isOdd.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
@ -415,7 +415,7 @@ export function main() {
'<test-cmp><li template="let item; let i=index">{{i}}: {{item}};</li></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
var testComponent = fixture.debugElement.children[0];
const testComponent = fixture.debugElement.children[0];
testComponent.componentInstance.items = ['a', 'b', 'c'];
fixture.detectChanges();
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
@ -433,7 +433,7 @@ export function main() {
.overrideTemplate(ComponentUsingTestComponent, '<test-cmp></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
var testComponent = fixture.debugElement.children[0];
const testComponent = fixture.debugElement.children[0];
testComponent.componentInstance.items = ['a', 'b', 'c'];
fixture.detectChanges();
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
@ -453,7 +453,7 @@ export function main() {
'<test-cmp><li template="let item; let i=index">{{i}}: {{item}};</li></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
var testComponent = fixture.debugElement.children[0];
const testComponent = fixture.debugElement.children[0];
testComponent.componentInstance.items = ['a', 'b', 'c'];
fixture.detectChanges();
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
@ -462,24 +462,39 @@ export function main() {
});
}));
describe('track by', function() {
describe('track by', () => {
it('should set the context to the component instance',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
const template =
`<template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackByContext.bind(this)"></template>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
thisArg = null;
fixture.detectChanges();
expect(thisArg).toBe(fixture.debugElement.componentInstance);
async.done();
});
}));
it('should not replace tracked items',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template =
const template =
`<template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackById" let-i="index">
<p>{{items[i]}}</p>
</template>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
var buildItemList =
() => {
fixture.debugElement.componentInstance.items = [{'id': 'a'}];
fixture.detectChanges();
return fixture.debugElement.queryAll(By.css('p'))[0];
}
var buildItemList = () => {
fixture.debugElement.componentInstance.items = [{'id': 'a'}];
fixture.detectChanges();
return fixture.debugElement.queryAll(By.css('p'))[0];
};
var firstP = buildItemList();
var finalP = buildItemList();
@ -487,11 +502,12 @@ export function main() {
async.done();
});
}));
it('should update implicit local variable on view',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template =
const template =
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -509,7 +525,7 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template =
const template =
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -530,7 +546,7 @@ export function main() {
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template =
const template =
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackByIndex">{{item}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -560,6 +576,7 @@ class TestComponent {
constructor() { this.items = [1, 2]; }
trackById(index: number, item: any): string { return item['id']; }
trackByIndex(index: number, item: any): number { return index; }
trackByContext(): void { thisArg = this; }
}
@Component({selector: 'outer-cmp', directives: [TestComponent], template: ''})

View File

@ -1,14 +1,17 @@
import {beforeEach, ddescribe, describe, iit, inject, it, xit,} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing';
import {TestComponentBuilder} from '@angular/compiler/testing';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {Component} from '@angular/core';
import {NgIf} from '@angular/common';
import {IS_DART} from '../../src/facade/lang';
import {Component} from '@angular/core';
import {TestComponentBuilder} from '@angular/core/testing';
import {AsyncTestCompleter, beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
describe('ngIf directive', () => {
@ -183,84 +186,58 @@ export function main() {
});
}));
it('should not add the element twice if the condition goes from true to true (JS)',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var html = '<div><copy-me template="ngIf numberCondition">hello</copy-me></div>';
if (!IS_DART) {
it('should not add the element twice if the condition goes from true to true (JS)',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var html = '<div><copy-me template="ngIf numberCondition">hello</copy-me></div>';
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(getDOM()
.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me')
.length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('hello');
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(getDOM()
.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me')
.length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('hello');
fixture.debugElement.componentInstance.numberCondition = 2;
fixture.detectChanges();
expect(getDOM()
.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me')
.length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('hello');
fixture.debugElement.componentInstance.numberCondition = 2;
fixture.detectChanges();
expect(getDOM()
.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me')
.length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('hello');
async.done();
});
}));
async.done();
});
}));
it('should not recreate the element if the condition goes from true to true (JS)',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var html = '<div><copy-me template="ngIf numberCondition">hello</copy-me></div>';
it('should not recreate the element if the condition goes from true to true (JS)',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var html = '<div><copy-me template="ngIf numberCondition">hello</copy-me></div>';
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
getDOM().addClass(
getDOM().querySelector(fixture.debugElement.nativeElement, 'copy-me'),
'foo');
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
getDOM().addClass(
getDOM().querySelector(fixture.debugElement.nativeElement, 'copy-me'),
'foo');
fixture.debugElement.componentInstance.numberCondition = 2;
fixture.detectChanges();
expect(
getDOM().hasClass(
getDOM().querySelector(fixture.debugElement.nativeElement, 'copy-me'),
'foo'))
.toBe(true);
async.done();
});
}));
}
if (IS_DART) {
it('should not create the element if the condition is not a boolean (DART)',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var html = '<div><copy-me template="ngIf numberCondition">hello</copy-me></div>';
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
expect(() => fixture.detectChanges()).toThrowError();
expect(getDOM()
.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me')
.length)
.toEqual(0);
expect(fixture.debugElement.nativeElement).toHaveText('');
async.done();
});
}));
}
fixture.debugElement.componentInstance.numberCondition = 2;
fixture.detectChanges();
expect(getDOM().hasClass(
getDOM().querySelector(fixture.debugElement.nativeElement, 'copy-me'),
'foo'))
.toBe(true);
async.done();
});
}));
});
}

View File

@ -1,13 +1,20 @@
import {beforeEachProviders, beforeEach, ddescribe, describe, expect, iit, inject, it, xit,} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder} from '@angular/compiler/testing';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {NgLocalization, NgPlural, NgPluralCase} from '@angular/common';
import {Component, Injectable} from '@angular/core';
import {NgPlural, NgPluralCase, NgLocalization} from '@angular/common';
import {TestComponentBuilder} from '@angular/core/testing';
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
describe('switch', () => {
beforeEachProviders(() => [{provide: NgLocalization, useClass: TestLocalizationMap}]);
beforeEachProviders(() => [{provide: NgLocalization, useClass: TestLocalization}]);
it('should display the template according to the exact value',
inject(
@ -34,6 +41,27 @@ export function main() {
});
}));
// https://github.com/angular/angular/issues/9868
// https://github.com/angular/angular/issues/9882
it('should not throw when ngPluralCase contains expressions',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template = '<div>' +
'<ul [ngPlural]="switchValue">' +
'<template ngPluralCase="=0"><li>{{ switchValue }}</li></template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.switchValue = 0;
expect(() => fixture.detectChanges()).not.toThrow();
async.done();
});
}));
it('should be applicable to <ng-container> elements',
inject(
[TestComponentBuilder, AsyncTestCompleter],
@ -134,22 +162,21 @@ export function main() {
});
}
@Injectable()
export class TestLocalizationMap extends NgLocalization {
class TestLocalization extends NgLocalization {
getPluralCategory(value: number): string {
if (value > 1 && value < 4) {
return 'few';
} else if (value >= 4 && value < 10) {
return 'many';
} else {
return 'other';
}
if (value >= 4 && value < 10) {
return 'many';
}
return 'other';
}
}
@Component({selector: 'test-cmp', directives: [NgPluralCase, NgPlural], template: ''})
@Component({selector: 'test-cmp', directives: [NgPlural, NgPluralCase], template: ''})
class TestComponent {
switchValue: number = null;
}

View File

@ -1,14 +1,22 @@
import {beforeEach, beforeEachProviders, ddescribe, xdescribe, describe, expect, iit, inject, it, xit,} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {StringMapWrapper} from '../../src/facade/collection';
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, xdescribe, describe, expect, iit, inject, it, xit,} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder, ComponentFixture} from '@angular/core/testing';
import {Component} from '@angular/core';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {NgStyle} from '@angular/common/src/directives/ng_style';
function expectNativeEl(fixture: ComponentFixture<any>) {
return <any>expect(fixture.debugElement.children[0].nativeElement);
}
export function main() {
describe('binding to CSS styles', () => {
@ -22,9 +30,7 @@ export function main() {
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
expectNativeEl(fixture).toHaveCssStyle({'max-width': '40px'});
async.done();
});
@ -43,16 +49,88 @@ export function main() {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
expectNativeEl(fixture).toHaveCssStyle({'max-width': '40px'});
expr = fixture.debugElement.componentInstance.expr;
(expr as any)['max-width'] = '30%';
fixture.detectChanges();
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('30%');
expectNativeEl(fixture).toHaveCssStyle({'max-width': '30%'});
async.done();
});
}));
it('should add and remove styles specified using style.unit notation',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template = `<div [ngStyle]="{'max-width.px': expr}"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.expr = '40';
fixture.detectChanges();
expectNativeEl(fixture).toHaveCssStyle({'max-width': '40px'});
fixture.debugElement.componentInstance.expr = null;
fixture.detectChanges();
expectNativeEl(fixture).not.toHaveCssStyle('max-width');
async.done();
});
}));
it('should update styles using style.unit notation when unit changes',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
var template = `<div [ngStyle]="expr"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.expr = {'max-width.px': '40'};
fixture.detectChanges();
expectNativeEl(fixture).toHaveCssStyle({'max-width': '40px'});
fixture.debugElement.componentInstance.expr = {'max-width.em': '40'};
fixture.detectChanges();
expectNativeEl(fixture).toHaveCssStyle({'max-width': '40em'});
async.done();
});
}));
// keyValueDiffer is sensitive to key order #9115
it('should change styles specified in an object expression',
inject(
[TestComponentBuilder, AsyncTestCompleter],
(tcb: TestComponentBuilder, async: AsyncTestCompleter) => {
const template = `<div [ngStyle]="expr"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.expr = {
// height, width order is important here
height: '10px',
width: '10px'
};
fixture.detectChanges();
expectNativeEl(fixture).toHaveCssStyle({'height': '10px', 'width': '10px'});
fixture.debugElement.componentInstance.expr = {
// width, height order is important here
width: '5px',
height: '5px',
};
fixture.detectChanges();
expectNativeEl(fixture).toHaveCssStyle({'height': '5px', 'width': '5px'});
async.done();
});
@ -69,16 +147,11 @@ export function main() {
.then((fixture) => {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
expectNativeEl(fixture).toHaveCssStyle({'max-width': '40px'});
StringMapWrapper.delete(
fixture.debugElement.componentInstance.expr, 'max-width');
delete fixture.debugElement.componentInstance.expr['max-width'];
fixture.detectChanges();
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('');
expectNativeEl(fixture).not.toHaveCssStyle('max-width');
async.done();
});
@ -95,22 +168,13 @@ export function main() {
.then((fixture) => {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
expectNativeEl(fixture).toHaveCssStyle(
{'max-width': '40px', 'font-size': '12px'});
StringMapWrapper.delete(
fixture.debugElement.componentInstance.expr, 'max-width');
delete fixture.debugElement.componentInstance.expr['max-width'];
fixture.detectChanges();
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('');
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
expectNativeEl(fixture).not.toHaveCssStyle('max-width');
expectNativeEl(fixture).toHaveCssStyle({'font-size': '12px'});
async.done();
});
@ -127,28 +191,18 @@ export function main() {
.then((fixture) => {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
StringMapWrapper.delete(
fixture.debugElement.componentInstance.expr, 'max-width');
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
expectNativeEl(fixture).toHaveCssStyle(
{'max-width': '40px', 'font-size': '12px'});
delete fixture.debugElement.componentInstance.expr['max-width'];
fixture.detectChanges();
expect(getDOM().getStyle(
fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('');
expectNativeEl(fixture).not.toHaveCssStyle('max-width');
expectNativeEl(fixture).toHaveCssStyle({'font-size': '12px'});
async.done();
});
}));
})
});
}
@Component({selector: 'test-cmp', directives: [NgStyle], template: ''})

View File

@ -1,9 +1,16 @@
import {beforeEach, ddescribe, describe, expect, iit, inject, it, xit,} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {Component} from '@angular/core';
import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {NgSwitch, NgSwitchCase, NgSwitchDefault} from '@angular/common';
import {Component} from '@angular/core';
import {TestComponentBuilder} from '@angular/core/testing';
import {AsyncTestCompleter, beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
describe('switch', () => {

View File

@ -1,8 +1,16 @@
import {beforeEach, ddescribe, describe, expect, iit, inject, it, xit,} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {Component, Directive, TemplateRef, ContentChildren, QueryList} from '@angular/core';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {NgTemplateOutlet} from '@angular/common';
import {Component, ContentChildren, Directive, QueryList, TemplateRef} from '@angular/core';
import {TestComponentBuilder} from '@angular/core/testing';
import {AsyncTestCompleter, beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
describe('insert', () => {

View File

@ -1,9 +1,17 @@
import {beforeEach, ddescribe, describe, expect, iit, inject, it, xit,} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component, Directive} from '@angular/core';
import {ElementRef} from '@angular/core/src/linker/element_ref';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder} from '@angular/core/testing';
import {AsyncTestCompleter, beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
describe('non-bindable', () => {
@ -53,7 +61,7 @@ export function main() {
async.done();
});
}));
})
});
}
@Directive({selector: '[test-dec]'})

View File

@ -1,102 +0,0 @@
library angular2.test.directives.observable_list_iterable_diff_spec;
import 'package:angular2/testing_internal.dart';
import 'package:observe/observe.dart' show ObservableList;
import 'package:angular2/core.dart' show ChangeDetectorRef;
import 'package:angular2/common.dart' show ObservableListDiffFactory;
@proxy
class SpyChangeDetectorRef extends SpyObject implements ChangeDetectorRef {}
main() {
describe('ObservableListDiff', () {
var factory, changeDetectorRef;
beforeEach(() {
factory = const ObservableListDiffFactory();
changeDetectorRef = new SpyChangeDetectorRef();
});
describe("supports", () {
it("should be true for ObservableList", () {
expect(factory.supports(new ObservableList())).toBe(true);
});
it("should be false otherwise", () {
expect(factory.supports([1, 2, 3])).toBe(false);
});
});
it("should return itself when called the first time", () {
final d = factory.create(changeDetectorRef);
final c = new ObservableList.from([1, 2]);
expect(d.diff(c)).toBe(d);
});
it("should return itself when no changes between the calls", () {
final d = factory.create(changeDetectorRef);
final c = new ObservableList.from([1, 2]);
d.diff(c);
expect(d.diff(c)).toBe(null);
});
it("should return the wrapped value once a change has been triggered",
fakeAsync(() {
final d = factory.create(changeDetectorRef);
final c = new ObservableList.from([1, 2]);
d.diff(c);
c.add(3);
// same value, because we have not detected the change yet
expect(d.diff(c)).toBe(null);
// now we detect the change
flushMicrotasks();
expect(d.diff(c)).toBe(d);
}));
it("should request a change detection check upon receiving a change",
fakeAsync(() {
final d = factory.create(changeDetectorRef);
final c = new ObservableList.from([1, 2]);
d.diff(c);
c.add(3);
flushMicrotasks();
expect(changeDetectorRef.spy("markForCheck")).toHaveBeenCalledOnce();
}));
it("should return the wrapped value after changing a collection", () {
final d = factory.create(changeDetectorRef);
final c1 = new ObservableList.from([1, 2]);
final c2 = new ObservableList.from([3, 4]);
expect(d.diff(c1)).toBe(d);
expect(d.diff(c2)).toBe(d);
});
it("should not unbsubscribe from the stream of chagnes after changing a collection",
() {
final d = factory.create(changeDetectorRef);
final c1 = new ObservableList.from([1, 2]);
expect(d.diff(c1)).toBe(d);
final c2 = new ObservableList.from([3, 4]);
expect(d.diff(c2)).toBe(d);
// pushing into the first collection has no effect, and we do not see the change
c1.add(3);
expect(d.diff(c2)).toBe(null);
});
});
}

View File

@ -1,17 +1,19 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {CheckboxControlValueAccessor, Control, ControlGroup, ControlValueAccessor, DefaultValueAccessor, NgControl, NgControlGroup, NgControlName, NgForm, NgFormControl, NgFormModel, NgModel, SelectControlValueAccessor, Validator, Validators} from '@angular/common/src/forms-deprecated';
import {composeValidators, selectValueAccessor} from '@angular/common/src/forms-deprecated/directives/shared';
import {SimpleChange} from '@angular/core/src/change_detection';
import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {fakeAsync, flushMicrotasks, Log, tick,} from '@angular/core/testing';
import {SpyNgControl, SpyValueAccessor} from '../spies';
import {ControlGroup, Control, NgControlName, NgControlGroup, NgFormModel, ControlValueAccessor, Validators, NgForm, NgModel, NgFormControl, NgControl, DefaultValueAccessor, CheckboxControlValueAccessor, SelectControlValueAccessor, Validator} from '@angular/common/src/forms-deprecated';
import {selectValueAccessor, composeValidators} from '@angular/common/src/forms-deprecated/directives/shared';
import {TimerWrapper} from '../../src/facade/async';
import {PromiseWrapper} from '../../src/facade/promise';
import {SimpleChange} from '@angular/core/src/change_detection';
class DummyControlValueAccessor implements ControlValueAccessor {
writtenValue: any /** TODO #9100 */;
@ -27,14 +29,14 @@ class CustomValidatorDirective implements Validator {
function asyncValidator(expected: any /** TODO #9100 */, timeout = 0) {
return (c: any /** TODO #9100 */) => {
var completer = PromiseWrapper.completer();
var res = c.value != expected ? {'async': true} : null;
if (timeout == 0) {
completer.resolve(res);
} else {
TimerWrapper.setTimeout(() => { completer.resolve(res); }, timeout);
}
return completer.promise;
return new Promise((resolve) => {
var res = c.value != expected ? {'async': true} : null;
if (timeout == 0) {
resolve(res);
} else {
setTimeout(() => { resolve(res); }, timeout);
}
});
};
}
@ -142,7 +144,7 @@ export function main() {
dir.name = 'invalidName';
expect(() => form.addControl(dir))
.toThrowError(new RegExp('Cannot find control \'invalidName\''));
.toThrowError(new RegExp(`Cannot find control with name: 'invalidName'`));
});
it('should throw when no value accessor', () => {
@ -150,7 +152,18 @@ export function main() {
dir.name = 'login';
expect(() => form.addControl(dir))
.toThrowError(new RegExp('No value accessor for \'login\''));
.toThrowError(new RegExp(`No value accessor for form control with name: 'login'`));
});
it('should throw when no value accessor with path', () => {
const group = new NgControlGroup(form, null, null);
const dir = new NgControlName(group, null, null, null);
group.name = 'passwords';
dir.name = 'password';
expect(() => form.addControl(dir))
.toThrowError(new RegExp(
`No value accessor for form control with path: 'passwords -> password'`));
});
it('should set up validators', fakeAsync(() => {
@ -426,6 +439,14 @@ export function main() {
expect(ngModel.untouched).toBe(control.untouched);
});
it('should throw when no value accessor with unnamed control', () => {
const unnamedDir = new NgModel(null, null, null);
expect(() => unnamedDir.ngOnChanges({}))
.toThrowError(new RegExp(`No value accessor for form control with unspecified name`));
});
it('should set up validator', fakeAsync(() => {
// this will add the required validator and recalculate the validity
ngModel.ngOnChanges({});

View File

@ -1,11 +1,17 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Control, FormBuilder} from '@angular/common/src/forms-deprecated';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {PromiseWrapper} from '../../src/facade/promise';
export function main() {
function syncValidator(_: any): any { return null; }
function asyncValidator(_: any) { return PromiseWrapper.resolve(null); }
function asyncValidator(_: any) { return Promise.resolve(null); }
describe('Form Builder', () => {
var b: any /** TODO #9100 */;

View File

@ -1,23 +1,27 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {NgFor, NgIf} from '@angular/common';
import {Control, ControlGroup, ControlValueAccessor, FORM_DIRECTIVES, FORM_PROVIDERS, NG_ASYNC_VALIDATORS, NG_VALIDATORS, NgControl, NgForm, RadioButtonState, Validator, Validators} from '@angular/common/src/forms-deprecated';
import {TestComponentBuilder} from '@angular/compiler/testing';
import {ComponentFixture} from '@angular/compiler/testing';
import {Component, Directive, EventEmitter, Output} from '@angular/core';
import {Input, Provider, forwardRef} from '@angular/core';
import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {Control, ControlGroup, ControlValueAccessor, DeprecatedFormsModule, NG_ASYNC_VALIDATORS, NG_VALIDATORS, NgControl, NgForm, RadioButtonState, Validator, Validators} from '@angular/common/src/forms-deprecated';
import {Component, Directive, EventEmitter, Input, Output, Provider, forwardRef} from '@angular/core';
import {ComponentFixture, TestBed, TestComponentBuilder, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {dispatchEvent} from '@angular/platform-browser/testing';
import {dispatchEvent} from '@angular/platform-browser/testing/browser_util';
import {ObservableWrapper, TimerWrapper} from '../../src/facade/async';
import {ListWrapper} from '../../src/facade/collection';
import {PromiseWrapper} from '../../src/facade/promise';
export function main() {
describe('integration tests', () => {
beforeEach(() => TestBed.configureTestingModule({imports: [DeprecatedFormsModule]}));
it('should initialize DOM elements with the given form object',
inject(
[TestComponentBuilder, AsyncTestCompleter],
@ -47,7 +51,7 @@ export function main() {
tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((fixture) => {
expect(() => fixture.detectChanges())
.toThrowError(new RegExp(`ngFormModel expects a form. Please pass one in.`));
.toThrowError(/ngFormModel expects a form\. Please pass one in/);
async.done();
});
}));
@ -92,8 +96,8 @@ export function main() {
input.nativeElement.value = 'updatedValue';
ObservableWrapper.subscribe(
form.valueChanges, (value) => { throw 'Should not happen'; });
form.valueChanges.subscribe({next: (value: any) => { throw 'Should not happen'; }});
dispatchEvent(input.nativeElement, 'change');
async.done();
@ -123,55 +127,51 @@ export function main() {
})));
it('should mark NgForm as submitted on submit event',
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
var t = `<div>
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
var t = `<div>
<form #f="ngForm" (ngSubmit)="data=f.submitted"></form>
<span>{{data}}</span>
</div>`;
var fixture: ComponentFixture<MyComp8>;
var fixture: ComponentFixture<MyComp8>;
tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((root) => {
fixture = root;
});
tick();
tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((root) => { fixture = root; });
tick();
fixture.debugElement.componentInstance.data = false;
fixture.debugElement.componentInstance.data = false;
tick();
tick();
var form = fixture.debugElement.query(By.css('form'));
dispatchEvent(form.nativeElement, 'submit');
var form = fixture.debugElement.query(By.css('form'));
dispatchEvent(form.nativeElement, 'submit');
tick();
expect(fixture.debugElement.componentInstance.data).toEqual(true);
})));
tick();
expect(fixture.debugElement.componentInstance.data).toEqual(true);
})));
it('should mark NgFormModel as submitted on submit event',
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
var t = `<div>
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
var t = `<div>
<form #f="ngForm" [ngFormModel]="form" (ngSubmit)="data=f.submitted"></form>
<span>{{data}}</span>
</div>`;
var fixture: ComponentFixture<MyComp8>;
var fixture: ComponentFixture<MyComp8>;
tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((root) => {
fixture = root;
});
tick();
tcb.overrideTemplate(MyComp8, t).createAsync(MyComp8).then((root) => { fixture = root; });
tick();
fixture.debugElement.componentInstance.form = new ControlGroup({});
fixture.debugElement.componentInstance.data = false;
fixture.debugElement.componentInstance.form = new ControlGroup({});
fixture.debugElement.componentInstance.data = false;
tick();
tick();
var form = fixture.debugElement.query(By.css('form'));
dispatchEvent(form.nativeElement, 'submit');
var form = fixture.debugElement.query(By.css('form'));
dispatchEvent(form.nativeElement, 'submit');
tick();
expect(fixture.debugElement.componentInstance.data).toEqual(true);
})));
tick();
expect(fixture.debugElement.componentInstance.data).toEqual(true);
})));
it('should work with single controls',
inject(
@ -604,7 +604,7 @@ export function main() {
select.nativeElement.value = '2: Object';
dispatchEvent(select.nativeElement, 'change');
fixture.detectChanges();
TimerWrapper.setTimeout(() => {
setTimeout(() => {
expect(testComp.selectedCity['name']).toEqual('Buffalo');
async.done();
}, 0);
@ -829,11 +829,13 @@ export function main() {
expect(input.componentInstance.value).toEqual('!aa!');
input.componentInstance.value = '!bb!';
ObservableWrapper.subscribe(input.componentInstance.onInput, (value) => {
expect(fixture.debugElement.componentInstance.form.value).toEqual({
'name': 'bb'
});
async.done();
input.componentInstance.onInput.subscribe({
next: (value: any) => {
expect(fixture.debugElement.componentInstance.form.value).toEqual({
'name': 'bb'
});
async.done();
}
});
input.componentInstance.dispatchChangeEvent();
});
@ -1489,21 +1491,16 @@ class MyInput implements ControlValueAccessor {
writeValue(value: any /** TODO #9100 */) { this.value = `!${value}!`; }
registerOnChange(fn: any /** TODO #9100 */) { ObservableWrapper.subscribe(this.onInput, fn); }
registerOnChange(fn: any /** TODO #9100 */) { this.onInput.subscribe({next: fn}); }
registerOnTouched(fn: any /** TODO #9100 */) {}
dispatchChangeEvent() {
ObservableWrapper.callEmit(this.onInput, this.value.substring(1, this.value.length - 1));
}
dispatchChangeEvent() { this.onInput.emit(this.value.substring(1, this.value.length - 1)); }
}
function uniqLoginAsyncValidator(expectedValue: string) {
return (c: any /** TODO #9100 */) => {
var completer = PromiseWrapper.completer();
var res = (c.value == expectedValue) ? null : {'uniqLogin': true};
completer.resolve(res);
return completer.promise;
return Promise.resolve((c.value == expectedValue) ? null : {'uniqLogin': true});
};
}
@ -1513,13 +1510,7 @@ function loginIsEmptyGroupValidator(c: ControlGroup) {
@Directive({
selector: '[login-is-empty-validator]',
providers: [
/* @ts2dart_Provider */ {
provide: NG_VALIDATORS,
useValue: loginIsEmptyGroupValidator,
multi: true
}
]
providers: [{provide: NG_VALIDATORS, useValue: loginIsEmptyGroupValidator, multi: true}]
})
class LoginIsEmptyValidator {
}
@ -1541,10 +1532,7 @@ class UniqLoginValidator implements Validator {
@Component({
selector: 'my-comp',
template: '',
directives: [
FORM_DIRECTIVES, WrappedValue, MyInput, NgIf, NgFor, LoginIsEmptyValidator, UniqLoginValidator
],
providers: [FORM_PROVIDERS]
directives: [WrappedValue, MyInput, NgIf, NgFor, LoginIsEmptyValidator, UniqLoginValidator]
})
class MyComp8 {
form: any;

View File

@ -1,33 +1,39 @@
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach, inject,} from '@angular/core/testing/testing_internal';
import {fakeAsync, flushMicrotasks, Log, tick} from '@angular/core/testing';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {ControlGroup, Control, ControlArray, Validators} from '@angular/common/src/forms-deprecated';
import {IS_DART, isPresent} from '../../src/facade/lang';
import {PromiseWrapper} from '../../src/facade/promise';
import {TimerWrapper, ObservableWrapper, EventEmitter} from '../../src/facade/async';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Control, ControlArray, ControlGroup, Validators} from '@angular/common/src/forms-deprecated';
import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {EventEmitter} from '../../src/facade/async';
import {isPresent} from '../../src/facade/lang';
export function main() {
function asyncValidator(expected: any /** TODO #9100 */, timeouts = /*@ts2dart_const*/ {}) {
function asyncValidator(expected: any /** TODO #9100 */, timeouts = {}) {
return (c: any /** TODO #9100 */) => {
var completer = PromiseWrapper.completer();
var t = isPresent((timeouts as any /** TODO #9100 */)[c.value]) ?
(timeouts as any /** TODO #9100 */)[c.value] :
0;
var res = c.value != expected ? {'async': true} : null;
return new Promise((resolve) => {
var t = isPresent((timeouts as any /** TODO #9100 */)[c.value]) ?
(timeouts as any /** TODO #9100 */)[c.value] :
0;
var res = c.value != expected ? {'async': true} : null;
if (t == 0) {
completer.resolve(res);
} else {
TimerWrapper.setTimeout(() => { completer.resolve(res); }, t);
}
return completer.promise;
if (t == 0) {
resolve(res);
} else {
setTimeout(() => { resolve(res); }, t);
}
});
};
}
function asyncValidatorReturningObservable(c: any /** TODO #9100 */) {
var e = new EventEmitter();
PromiseWrapper.scheduleMicrotask(() => ObservableWrapper.callEmit(e, {'async': true}));
Promise.resolve(null).then(() => { e.emit({'async': true}); });
return e;
}
@ -172,15 +178,16 @@ export function main() {
});
it('should fire an event', fakeAsync(() => {
ObservableWrapper.subscribe(
c.valueChanges, (value) => { expect(value).toEqual('newValue'); });
c.valueChanges.subscribe(
{next: (value: any) => { expect(value).toEqual('newValue'); }});
c.updateValue('newValue');
tick();
}));
it('should not fire an event when explicitly specified', fakeAsync(() => {
ObservableWrapper.subscribe(c.valueChanges, (value) => { throw 'Should not happen'; });
c.valueChanges.subscribe({next: (value: any) => { throw 'Should not happen'; }});
c.updateValue('newValue', {emitEvent: false});
@ -195,18 +202,22 @@ export function main() {
it('should fire an event after the value has been updated',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
ObservableWrapper.subscribe(c.valueChanges, (value) => {
expect(c.value).toEqual('new');
expect(value).toEqual('new');
async.done();
c.valueChanges.subscribe({
next: (value: any) => {
expect(c.value).toEqual('new');
expect(value).toEqual('new');
async.done();
}
});
c.updateValue('new');
}));
it('should fire an event after the status has been updated to invalid', fakeAsync(() => {
ObservableWrapper.subscribe(c.statusChanges, (status) => {
expect(c.status).toEqual('INVALID');
expect(status).toEqual('INVALID');
c.statusChanges.subscribe({
next: (status: any) => {
expect(c.status).toEqual('INVALID');
expect(status).toEqual('INVALID');
}
});
c.updateValue('');
@ -217,9 +228,9 @@ export function main() {
var c = new Control('old', Validators.required, asyncValidator('expected'));
var log: any[] /** TODO #9100 */ = [];
ObservableWrapper.subscribe(c.valueChanges, (value) => log.push(`value: '${value}'`));
ObservableWrapper.subscribe(
c.statusChanges, (status) => log.push(`status: '${status}'`));
c.valueChanges.subscribe({next: (value: any) => log.push(`value: '${value}'`)});
c.statusChanges.subscribe({next: (status: any) => log.push(`status: '${status}'`)});
c.updateValue('');
tick();
@ -244,24 +255,24 @@ export function main() {
}));
// TODO: remove the if statement after making observable delivery sync
if (!IS_DART) {
it('should update set errors and status before emitting an event',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
c.valueChanges.subscribe((value: any /** TODO #9100 */) => {
expect(c.valid).toEqual(false);
expect(c.errors).toEqual({'required': true});
async.done();
});
c.updateValue('');
}));
}
it('should update set errors and status before emitting an event',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
c.valueChanges.subscribe((value: any /** TODO #9100 */) => {
expect(c.valid).toEqual(false);
expect(c.errors).toEqual({'required': true});
async.done();
});
c.updateValue('');
}));
it('should return a cold observable',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
c.updateValue('will be ignored');
ObservableWrapper.subscribe(c.valueChanges, (value) => {
expect(value).toEqual('new');
async.done();
c.valueChanges.subscribe({
next: (value: any) => {
expect(value).toEqual('new');
async.done();
}
});
c.updateValue('new');
}));
@ -422,7 +433,7 @@ export function main() {
// rename contains into has
it('should return false when the component is not included',
() => { expect(group.contains('optional')).toEqual(false); })
() => { expect(group.contains('optional')).toEqual(false); });
it('should return false when there is no component with the given name',
() => { expect(group.contains('something else')).toEqual(false); });
@ -475,10 +486,12 @@ export function main() {
it('should fire an event after the value has been updated',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
ObservableWrapper.subscribe(g.valueChanges, (value) => {
expect(g.value).toEqual({'one': 'new1', 'two': 'old2'});
expect(value).toEqual({'one': 'new1', 'two': 'old2'});
async.done();
g.valueChanges.subscribe({
next: (value: any) => {
expect(g.value).toEqual({'one': 'new1', 'two': 'old2'});
expect(value).toEqual({'one': 'new1', 'two': 'old2'});
async.done();
}
});
c1.updateValue('new1');
}));
@ -487,12 +500,14 @@ export function main() {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var controlCallbackIsCalled = false;
ObservableWrapper.subscribe(
c1.valueChanges, (value) => { controlCallbackIsCalled = true; });
ObservableWrapper.subscribe(g.valueChanges, (value) => {
expect(controlCallbackIsCalled).toBe(true);
async.done();
c1.valueChanges.subscribe({next: (value: any) => { controlCallbackIsCalled = true; }});
g.valueChanges.subscribe({
next: (value: any) => {
expect(controlCallbackIsCalled).toBe(true);
async.done();
}
});
c1.updateValue('new1');
@ -500,9 +515,11 @@ export function main() {
it('should fire an event when a control is excluded',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
ObservableWrapper.subscribe(g.valueChanges, (value) => {
expect(value).toEqual({'one': 'old1'});
async.done();
g.valueChanges.subscribe({
next: (value: any) => {
expect(value).toEqual({'one': 'old1'});
async.done();
}
});
g.exclude('two');
@ -512,9 +529,11 @@ export function main() {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
g.exclude('two');
ObservableWrapper.subscribe(g.valueChanges, (value) => {
expect(value).toEqual({'one': 'old1', 'two': 'old2'});
async.done();
g.valueChanges.subscribe({
next: (value: any) => {
expect(value).toEqual({'one': 'old1', 'two': 'old2'});
async.done();
}
});
g.include('two');
@ -524,14 +543,16 @@ export function main() {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var loggedValues: any[] /** TODO #9100 */ = [];
ObservableWrapper.subscribe(g.valueChanges, (value) => {
loggedValues.push(value);
g.valueChanges.subscribe({
next: (value: any) => {
loggedValues.push(value);
if (loggedValues.length == 2) {
expect(loggedValues).toEqual([
{'one': 'new1', 'two': 'old2'}, {'one': 'new1', 'two': 'new2'}
]);
async.done();
if (loggedValues.length == 2) {
expect(loggedValues).toEqual([
{'one': 'new1', 'two': 'old2'}, {'one': 'new1', 'two': 'new2'}
]);
async.done();
}
}
});
@ -597,7 +618,7 @@ export function main() {
expect(g.errors).toEqual({'async': true});
expect(g.find(['one']).errors).toEqual({'async': true});
}));
})
});
});
describe('ControlArray', () => {
@ -730,10 +751,12 @@ export function main() {
it('should fire an event after the value has been updated',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
ObservableWrapper.subscribe(a.valueChanges, (value) => {
expect(a.value).toEqual(['new1', 'old2']);
expect(value).toEqual(['new1', 'old2']);
async.done();
a.valueChanges.subscribe({
next: (value: any) => {
expect(a.value).toEqual(['new1', 'old2']);
expect(value).toEqual(['new1', 'old2']);
async.done();
}
});
c1.updateValue('new1');
}));
@ -742,12 +765,14 @@ export function main() {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var controlCallbackIsCalled = false;
ObservableWrapper.subscribe(
c1.valueChanges, (value) => { controlCallbackIsCalled = true; });
ObservableWrapper.subscribe(a.valueChanges, (value) => {
expect(controlCallbackIsCalled).toBe(true);
async.done();
c1.valueChanges.subscribe({next: (value: any) => { controlCallbackIsCalled = true; }});
a.valueChanges.subscribe({
next: (value: any) => {
expect(controlCallbackIsCalled).toBe(true);
async.done();
}
});
c1.updateValue('new1');
@ -755,9 +780,11 @@ export function main() {
it('should fire an event when a control is removed',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
ObservableWrapper.subscribe(a.valueChanges, (value) => {
expect(value).toEqual(['old1']);
async.done();
a.valueChanges.subscribe({
next: (value: any) => {
expect(value).toEqual(['old1']);
async.done();
}
});
a.removeAt(1);
@ -767,9 +794,11 @@ export function main() {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
a.removeAt(1);
ObservableWrapper.subscribe(a.valueChanges, (value) => {
expect(value).toEqual(['old1', 'old2']);
async.done();
a.valueChanges.subscribe({
next: (value: any) => {
expect(value).toEqual(['old1', 'old2']);
async.done();
}
});
a.push(c2);
@ -821,7 +850,7 @@ export function main() {
expect(g.errors).toEqual({'async': true});
expect(g.pending).toEqual(false);
}));
})
});
});
});
}

View File

@ -1,16 +1,37 @@
import {AbstractControl, Control, ControlArray, ControlGroup, Validators} from '@angular/common/src/forms-deprecated';
import {Log, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {EventEmitter, ObservableWrapper, TimerWrapper} from '../../src/facade/async';
import {PromiseWrapper} from '../../src/facade/promise';
import {AbstractControl, Control, ControlArray, ControlGroup, Validators} from '@angular/common/src/forms-deprecated';
import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {Observable} from 'rxjs/Observable';
import {EventEmitter} from '../../src/facade/async';
import {normalizeAsyncValidator} from '../../src/forms-deprecated/directives/normalize_validator';
export function main() {
function validator(key: string, error: any) {
return function(c: AbstractControl) {
var r = {};
(r as any /** TODO #9100 */)[key] = error;
(r as any)[key] = error;
return r;
};
}
class AsyncValidatorDirective {
constructor(private expected: string, private error: any) {}
validate(c: any): {[key: string]: any;} {
return Observable.create((obs: any) => {
const error = this.expected !== c.value ? this.error : null;
obs.next(error);
obs.complete();
});
}
}
@ -80,6 +101,17 @@ export function main() {
});
});
it('should normalize and evaluate async validator-directives correctly', fakeAsync(() => {
const c = Validators.composeAsync(
[normalizeAsyncValidator(new AsyncValidatorDirective('expected', {'one': true}))]);
let value: any = null;
c(new Control()).then((v: any) => value = v);
tick(1);
expect(value).toEqual({'one': true});
}));
describe('compose', () => {
it('should return null when given null',
() => { expect(Validators.compose(null)).toBe(null); });
@ -110,14 +142,14 @@ export function main() {
return (c: any /** TODO #9100 */) => {
var emitter = new EventEmitter();
var res = c.value != expected ? response : null;
PromiseWrapper.scheduleMicrotask(() => {
ObservableWrapper.callEmit(emitter, res);
Promise.resolve(null).then(() => {
emitter.emit(res);
// this is required because of a bug in ObservableWrapper
// where callComplete can fire before callEmit
// remove this one the bug is fixed
TimerWrapper.setTimeout(() => { ObservableWrapper.callComplete(emitter); }, 0);
setTimeout(() => { emitter.complete(); }, 0);
});
return emitter;
};
}

View File

@ -1,13 +1,20 @@
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach, inject,} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {SpyChangeDetectorRef} from '../spies';
import {isBlank} from '../../src/facade/lang';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AsyncPipe} from '@angular/common';
import {WrappedValue} from '@angular/core';
import {EventEmitter, ObservableWrapper, PromiseWrapper, TimerWrapper} from '../../src/facade/async';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {PromiseCompleter} from '../../src/facade/promise';
import {browserDetection} from '@angular/platform-browser/testing';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {EventEmitter} from '../../src/facade/async';
import {isBlank} from '../../src/facade/lang';
import {SpyChangeDetectorRef} from '../spies';
export function main() {
describe('AsyncPipe', () => {
@ -31,26 +38,25 @@ export function main() {
it('should return the latest available value wrapped',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
pipe.transform(emitter);
emitter.emit(message);
ObservableWrapper.callEmit(emitter, message);
TimerWrapper.setTimeout(() => {
setTimeout(() => {
expect(pipe.transform(emitter)).toEqual(new WrappedValue(message));
async.done();
}, 0)
}, 0);
}));
it('should return same value when nothing has changed since the last call',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
pipe.transform(emitter);
ObservableWrapper.callEmit(emitter, message);
emitter.emit(message);
TimerWrapper.setTimeout(() => {
setTimeout(() => {
pipe.transform(emitter);
expect(pipe.transform(emitter)).toBe(message);
async.done();
}, 0)
}, 0);
}));
it('should dispose of the existing subscription when subscribing to a new observable',
@ -59,25 +65,24 @@ export function main() {
var newEmitter = new EventEmitter();
expect(pipe.transform(newEmitter)).toBe(null);
emitter.emit(message);
// this should not affect the pipe
ObservableWrapper.callEmit(emitter, message);
TimerWrapper.setTimeout(() => {
setTimeout(() => {
expect(pipe.transform(newEmitter)).toBe(null);
async.done();
}, 0)
}, 0);
}));
it('should request a change detection check upon receiving a new value',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
pipe.transform(emitter);
ObservableWrapper.callEmit(emitter, message);
emitter.emit(message);
TimerWrapper.setTimeout(() => {
setTimeout(() => {
expect(ref.spy('markForCheck')).toHaveBeenCalled();
async.done();
}, 10)
}, 10);
}));
});
@ -89,13 +94,12 @@ export function main() {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
pipe.transform(emitter);
pipe.ngOnDestroy();
emitter.emit(message);
ObservableWrapper.callEmit(emitter, message);
TimerWrapper.setTimeout(() => {
setTimeout(() => {
expect(pipe.transform(emitter)).toBe(null);
async.done();
}, 0)
}, 0);
}));
});
});
@ -103,71 +107,76 @@ export function main() {
describe('Promise', () => {
var message = new Object();
var pipe: AsyncPipe;
var completer: PromiseCompleter<any>;
var resolve: (result: any) => void;
var reject: (error: any) => void;
var promise: Promise<any>;
var ref: SpyChangeDetectorRef;
// adds longer timers for passing tests in IE
var timer = (!isBlank(getDOM()) && browserDetection.isIE) ? 50 : 10;
beforeEach(() => {
completer = PromiseWrapper.completer();
promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
ref = new SpyChangeDetectorRef();
pipe = new AsyncPipe(<any>ref);
});
describe('transform', () => {
it('should return null when subscribing to a promise',
() => { expect(pipe.transform(completer.promise)).toBe(null); });
() => { expect(pipe.transform(promise)).toBe(null); });
it('should return the latest available value',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
pipe.transform(completer.promise);
pipe.transform(promise);
completer.resolve(message);
resolve(message);
TimerWrapper.setTimeout(() => {
expect(pipe.transform(completer.promise)).toEqual(new WrappedValue(message));
setTimeout(() => {
expect(pipe.transform(promise)).toEqual(new WrappedValue(message));
async.done();
}, timer)
}, timer);
}));
it('should return unwrapped value when nothing has changed since the last call',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
pipe.transform(completer.promise);
completer.resolve(message);
pipe.transform(promise);
resolve(message);
TimerWrapper.setTimeout(() => {
pipe.transform(completer.promise);
expect(pipe.transform(completer.promise)).toBe(message);
setTimeout(() => {
pipe.transform(promise);
expect(pipe.transform(promise)).toBe(message);
async.done();
}, timer)
}, timer);
}));
it('should dispose of the existing subscription when subscribing to a new promise',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
pipe.transform(completer.promise);
pipe.transform(promise);
var newCompleter = PromiseWrapper.completer();
expect(pipe.transform(newCompleter.promise)).toBe(null);
var promise = new Promise<any>(() => {});
expect(pipe.transform(promise)).toBe(null);
// this should not affect the pipe, so it should return WrappedValue
completer.resolve(message);
resolve(message);
TimerWrapper.setTimeout(() => {
expect(pipe.transform(newCompleter.promise)).toBe(null);
setTimeout(() => {
expect(pipe.transform(promise)).toBe(null);
async.done();
}, timer)
}, timer);
}));
it('should request a change detection check upon receiving a new value',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var markForCheck = ref.spy('markForCheck');
pipe.transform(completer.promise);
completer.resolve(message);
pipe.transform(promise);
resolve(message);
TimerWrapper.setTimeout(() => {
setTimeout(() => {
expect(markForCheck).toHaveBeenCalled();
async.done();
}, timer)
}, timer);
}));
describe('ngOnDestroy', () => {
@ -176,15 +185,15 @@ export function main() {
it('should dispose of the existing source',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
pipe.transform(completer.promise);
expect(pipe.transform(completer.promise)).toBe(null);
completer.resolve(message)
pipe.transform(promise);
expect(pipe.transform(promise)).toBe(null);
resolve(message);
TimerWrapper.setTimeout(() => {
expect(pipe.transform(completer.promise)).toEqual(new WrappedValue(message));
setTimeout(() => {
expect(pipe.transform(promise)).toEqual(new WrappedValue(message));
pipe.ngOnDestroy();
expect(pipe.transform(completer.promise)).toBe(null);
expect(pipe.transform(promise)).toBe(null);
async.done();
}, timer);
}));

View File

@ -1,7 +1,15 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {DatePipe} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {DateWrapper} from '../../src/facade/lang';
@ -11,7 +19,7 @@ export function main() {
var pipe: DatePipe;
beforeEach(() => {
date = DateWrapper.create(2015, 6, 15, 21, 3, 1);
date = DateWrapper.create(2015, 6, 15, 9, 3, 1);
pipe = new DatePipe();
});
@ -48,12 +56,15 @@ export function main() {
expect(pipe.transform(date, 'd')).toEqual('15');
expect(pipe.transform(date, 'E')).toEqual('Mon');
expect(pipe.transform(date, 'EEEE')).toEqual('Monday');
expect(pipe.transform(date, 'H')).toEqual('21');
expect(pipe.transform(date, 'j')).toEqual('9 PM');
expect(pipe.transform(date, 'h')).toEqual('9');
expect(pipe.transform(date, 'hh')).toEqual('09');
expect(pipe.transform(date, 'HH')).toEqual('09');
expect(pipe.transform(date, 'j')).toEqual('9 AM');
expect(pipe.transform(date, 'm')).toEqual('3');
expect(pipe.transform(date, 's')).toEqual('1');
expect(pipe.transform(date, 'mm')).toEqual('03');
expect(pipe.transform(date, 'ss')).toEqual('01');
expect(pipe.transform(date, 'Z')).toBeDefined();
});
it('should format common multi component patterns', () => {
@ -66,22 +77,22 @@ export function main() {
expect(pipe.transform(date, 'MEd')).toEqual('6Mon15');
expect(pipe.transform(date, 'MMMd')).toEqual('Jun15');
expect(pipe.transform(date, 'yMMMMEEEEd')).toEqual('Monday, June 15, 2015');
expect(pipe.transform(date, 'jms')).toEqual('9:03:01 PM');
expect(pipe.transform(date, 'ms')).toEqual('31');
expect(pipe.transform(date, 'jm')).toEqual('9:03 PM');
expect(pipe.transform(date, 'jm')).toEqual('9:03 AM');
});
it('should format with pattern aliases', () => {
expect(pipe.transform(date, 'medium')).toEqual('Jun 15, 2015, 9:03:01 PM');
expect(pipe.transform(date, 'short')).toEqual('6/15/2015, 9:03 PM');
expect(pipe.transform(date, 'medium')).toEqual('Jun 15, 2015, 9:03:01 AM');
expect(pipe.transform(date, 'short')).toEqual('6/15/2015, 9:03 AM');
expect(pipe.transform(date, 'dd/MM/yyyy')).toEqual('15/06/2015');
expect(pipe.transform(date, 'MM/dd/yyyy')).toEqual('06/15/2015');
expect(pipe.transform(date, 'fullDate')).toEqual('Monday, June 15, 2015');
expect(pipe.transform(date, 'longDate')).toEqual('June 15, 2015');
expect(pipe.transform(date, 'mediumDate')).toEqual('Jun 15, 2015');
expect(pipe.transform(date, 'shortDate')).toEqual('6/15/2015');
expect(pipe.transform(date, 'mediumTime')).toEqual('9:03:01 PM');
expect(pipe.transform(date, 'shortTime')).toEqual('9:03 PM');
expect(pipe.transform(date, 'mediumTime')).toEqual('9:03:01 AM');
expect(pipe.transform(date, 'shortTime')).toEqual('9:03 AM');
});
});
}

View File

@ -1,18 +1,31 @@
import {I18nPluralPipe} from '@angular/common';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {I18nPluralPipe, NgLocalization} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
export function main() {
describe('I18nPluralPipe', () => {
var localization: NgLocalization;
var pipe: I18nPluralPipe;
var mapping = {'=0': 'No messages.', '=1': 'One message.', 'other': 'There are some messages.'};
var interpolatedMapping = {
var mapping = {
'=0': 'No messages.',
'=1': 'One message.',
'other': 'There are # messages, that is #.'
'many': 'Many messages.',
'other': 'There are # messages, that is #.',
};
beforeEach(() => { pipe = new I18nPluralPipe(); });
beforeEach(() => {
localization = new TestLocalization();
pipe = new I18nPluralPipe(localization);
});
it('should be marked as pure',
() => { expect(new PipeResolver().resolve(I18nPluralPipe).pure).toEqual(true); });
@ -28,19 +41,19 @@ export function main() {
expect(val).toEqual('One message.');
});
it('should return other text if value is anything other than 0 or 1', () => {
var val = pipe.transform(6, mapping);
expect(val).toEqual('There are some messages.');
it('should return category messages', () => {
var val = pipe.transform(4, mapping);
expect(val).toEqual('Many messages.');
});
it('should interpolate the value into the text where indicated', () => {
var val = pipe.transform(6, interpolatedMapping);
var val = pipe.transform(6, mapping);
expect(val).toEqual('There are 6 messages, that is 6.');
});
it('should use \'other\' if value is undefined', () => {
var val = pipe.transform(void(0), interpolatedMapping);
expect(val).toEqual('There are messages, that is .');
it('should use "" if value is undefined', () => {
var val = pipe.transform(void(0), mapping);
expect(val).toEqual('');
});
it('should not support bad arguments',
@ -49,3 +62,7 @@ export function main() {
});
}
class TestLocalization extends NgLocalization {
getPluralCategory(value: number): string { return value > 1 && value < 6 ? 'many' : 'other'; }
}

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {I18nSelectPipe} from '@angular/common';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
@ -23,14 +31,14 @@ export function main() {
expect(val).toEqual('Invite her.');
});
it('should return other text if value is anything other than male or female', () => {
it('should return "" if value is anything other than male or female', () => {
var val = pipe.transform('Anything else', mapping);
expect(val).toEqual('Invite them.');
expect(val).toEqual('');
});
it('should use \'other\' if value is undefined', () => {
it('should use "" if value is undefined', () => {
var val = pipe.transform(void(0), mapping);
expect(val).toEqual('Invite them.');
expect(val).toEqual('');
});
it('should not support bad arguments',

View File

@ -1,10 +1,18 @@
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach, inject,} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder} from '@angular/compiler/testing';
import {Json, StringWrapper} from '../../src/facade/lang';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component} from '@angular/core';
import {JsonPipe} from '@angular/common';
import {Component} from '@angular/core';
import {TestComponentBuilder} from '@angular/core/testing';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing/matchers';
import {Json, StringWrapper} from '../../src/facade/lang';
export function main() {
describe('JsonPipe', () => {

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {LowerCasePipe} from '@angular/common';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';

View File

@ -1,7 +1,14 @@
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach,} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {DecimalPipe, PercentPipe, CurrencyPipe} from '@angular/common';
import {CurrencyPipe, DecimalPipe, PercentPipe} from '@angular/common';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
export function main() {
describe('Number pipes', () => {
@ -24,8 +31,19 @@ export function main() {
expect(pipe.transform(1.1234)).toEqual('1.123');
});
it('should not support other objects',
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
it('should support strings', () => {
expect(pipe.transform('12345')).toEqual('12,345');
expect(pipe.transform('123', '.2')).toEqual('123.00');
expect(pipe.transform('1', '3.')).toEqual('001');
expect(pipe.transform('1.1', '3.4-5')).toEqual('001.1000');
expect(pipe.transform('1.123456', '3.4-5')).toEqual('001.12346');
expect(pipe.transform('1.1234')).toEqual('1.123');
});
it('should not support other objects', () => {
expect(() => pipe.transform(new Object())).toThrowError();
expect(() => pipe.transform('123abc')).toThrowError();
});
});
});
@ -52,9 +70,9 @@ export function main() {
describe('transform', () => {
it('should return correct value for numbers', () => {
expect(pipe.transform(123)).toEqual('USD123');
expect(pipe.transform(12, 'EUR', false, '.2')).toEqual('EUR12.00');
expect(pipe.transform(5.123, 'USD', false, '.0-2')).toEqual('USD5.12');
expect(pipe.transform(123)).toEqual('USD123.00');
expect(pipe.transform(12, 'EUR', false, '.1')).toEqual('EUR12.0');
expect(pipe.transform(5.1234, 'USD', false, '.0-3')).toEqual('USD5.123');
});
it('should not support other objects',

View File

@ -1,8 +1,13 @@
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach, inject,} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ReplacePipe} from '@angular/common';
import {RegExpWrapper, StringJoiner} from '../../src/facade/lang';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
export function main() {
describe('ReplacePipe', () => {
@ -38,9 +43,9 @@ export function main() {
it('should return a new string with the pattern replaced', () => {
var result1 = pipe.transform(str, 'Douglas', 'Hugh');
var result2 = pipe.transform(str, RegExpWrapper.create('a'), '_');
var result2 = pipe.transform(str, /a/g, '_');
var result3 = pipe.transform(str, RegExpWrapper.create('a', 'i'), '_');
var result3 = pipe.transform(str, /a/gi, '_');
var f = ((x: any) => { return 'Adams!'; });

View File

@ -1,11 +1,17 @@
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach, inject,} from '@angular/core/testing/testing_internal';
import {} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing';
import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {Component} from '@angular/core';
import {SlicePipe} from '@angular/common';
import {Component} from '@angular/core';
import {TestComponentBuilder} from '@angular/core/testing';
import {AsyncTestCompleter, afterEach, beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
import {expect} from '@angular/platform-browser/testing/matchers';
export function main() {
describe('SlicePipe', () => {

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {UpperCasePipe} from '@angular/common';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';

View File

@ -1,14 +0,0 @@
library core.spies;
import 'package:angular2/common.dart';
import 'package:angular2/src/core/change_detection/change_detection.dart';
import 'package:angular2/testing_internal.dart';
@proxy
class SpyNgControl extends SpyObject implements NgControl {}
@proxy
class SpyValueAccessor extends SpyObject implements ControlValueAccessor {}
@proxy
class SpyChangeDetectorRef extends SpyObject implements ChangeDetectorRef {}

View File

@ -1,3 +1,11 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectorRef} from '@angular/core/src/change_detection/change_detector_ref';
import {SpyObject, proxy} from '@angular/core/testing/testing_internal';

View File

@ -1,2 +1,10 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export {SpyLocation} from './testing/location_mock';
export {MockLocationStrategy} from './testing/mock_location_strategy';
export {MockLocationStrategy} from './testing/mock_location_strategy';

Some files were not shown because too many files have changed in this diff Show More