Compare commits

...

746 Commits

Author SHA1 Message Date
6eac4b68bc build: bump to rc.1 in package.json 2016-05-03 15:28:45 -06:00
fcbfacb6d5 build: do not use tsickle to lower router-deprecated
if we do this, we can break existing code that is inheriting from RouterOutlet and expects the metadata
in the old location
2016-05-03 15:09:35 -06:00
b600915953 build: add licensing preamble to umd bundles 2016-05-03 13:59:30 -06:00
905f38acb8 build: fix source map paths for npm packages
the bundles have source mpas disabled for now because when we downlevel
the esm bundle to es5 tsc doesn't consider the original source map so
we end up with a source map pointing to the esm bundle instead which is
not useful.
2016-05-03 13:36:33 -06:00
38f4c5f155 chore(compiler): update README following package move 2016-05-03 13:26:59 -06:00
509f4ec611 fix(testing): Check for pending macrotasks in ComponentFixture.whenStable() and ComponentFixture.isStable()
Closes #8389
2016-05-03 11:50:35 -07:00
27a7b51d99 fix(docs): upgrade deprecated ngFor-Syntax 2016-05-03 11:49:33 -07:00
a033f8335b fix(compiler): use rootDirs compilerOption to affect genDir layout.
Also update package.json to something releasable.
2016-05-03 12:41:28 -06:00
b98c9e74e1 docs(router): add api docs 2016-05-03 11:35:07 -07:00
9f784dcc5a cleanup(router): fix e2e tests 2016-05-03 10:25:44 -07:00
b625f2471a feat(router): make RouterLink accept single values 2016-05-03 10:25:44 -07:00
3aa2606ff1 cleanup(router): make names consistent 2016-05-03 10:25:44 -07:00
89704e0f93 fix(router): add support for ../ 2016-05-03 10:25:44 -07:00
908a102a87 feat: security implementation in Angular 2.
Summary:
This adds basic security hooks to Angular 2.

* `SecurityContext` is a private API between core, compiler, and
  platform-browser. `SecurityContext` communicates what context a value is used
  in across template parser, compiler, and sanitization at runtime.
* `SanitizationService` is the bare bones interface to sanitize values for a
  particular context.
* `SchemaElementRegistry.securityContext(tagName, attributeOrPropertyName)`
  determines the security context for an attribute or property (it turns out
  attributes and properties match for the purposes of sanitization).

Based on these hooks:

* `DomSchemaElementRegistry` decides what sanitization applies in a particular
  context.
* `DomSanitizationService` implements `SanitizationService` and adds *Safe
  Value*s, i.e. the ability to mark a value as safe and not requiring further
  sanitization.
* `url_sanitizer` and `style_sanitizer` sanitize URLs and Styles, respectively
  (surprise!).

`DomSanitizationService` is the default implementation bound for browser
applications, in the three contexts (browser rendering, web worker rendering,
server side rendering).

BREAKING CHANGES:
*** SECURITY WARNING ***
Angular 2 Release Candidates do not implement proper contextual escaping yet.
Make sure to correctly escape all values that go into the DOM.
*** SECURITY WARNING ***

Reviewers: IgorMinar

Differential Revision: https://reviews.angular.io/D103
2016-05-03 09:21:43 -07:00
dd6e0cf1b5 fix(compiler): fix where pipes live
Impure pipes need to live on the view
that used them and need a new instance for
each call site.

Impure pipes need to live on the component view, cached across all child views,
and need a new pure proxy for each for
each call site that lives on the view
of the call site.

Fixes #8408

This bug was introduced not long ago by 152a117d5c
2016-05-03 09:00:23 -07:00
52a6ba7ed9 fix(compiler): use absolute paths for comparing module urls 2016-05-02 22:40:00 -06:00
43e0fa513b fix(compiler): don’t emit metadata for generated files 2016-05-02 22:40:00 -06:00
de978229b2 chore(compiler): Run compiler_cli tests in new CI.
Also update docs/peer deps, display errors from running jasmine, use the right location of cjs-jasmine
2016-05-02 22:39:32 -06:00
ba62fe974b refactor(static_reflector): remove unnecessary check. 2016-05-02 22:36:32 -06:00
3a40cb1a85 fix(compiler): calculate the right moduleUrl 2016-05-02 22:36:32 -06:00
883e0c48b1 docs(CHANGELOG): document 2.0.0-rc.0 2016-05-02 21:34:27 -06:00
18b6a55764 build: update publish scripts and package.json 2016-05-02 20:45:05 -06:00
00d3b6083c fix(compiler): support css stylesheets in offline compiler 2016-05-02 15:06:46 -07:00
c386fc8379 chore: make compiler_cli build again 2016-05-02 15:06:46 -07:00
43527172ed chore: don’t shadow tsconfig.json used for editors by build specific tsconfig.json 2016-05-02 15:06:46 -07:00
b88384eed8 build: add router-deprecated to the publishing scripts 2016-05-02 15:10:58 -06:00
107016ec12 chore: router move import changes 2016-05-02 13:27:03 -07:00
d930ad1816 chore: router move-only 2016-05-02 13:27:03 -07:00
072446aed3 feat(offline compiler): add metadata emit
Also add a configuration switch to disable the codegen, so we can
still use the metadata emit and tsickle pre-processing in the
build pipeline for angular itself.
2016-05-02 11:47:59 -07:00
2e1f3f003d build: adding basic e2e testing infrastructure 2016-05-02 08:15:10 -07:00
fdd8bd1a36 chore: use ng2tc for compiling and running tests on ci 2016-05-01 23:40:59 -07:00
7db911fdd4 chore: update to tsickle 0.1.2 2016-05-01 23:40:59 -07:00
b6fd81169b feat(core): support the decorator data that tsickle produces 2016-05-01 23:40:59 -07:00
3ae856ab8b build(tsc): Use angular2-template-compiler in place of tsc
This lets us down-level Decorators with tsickle and produce .metadata.json
files for users to reference when offline-compiling their app.
2016-05-01 23:40:59 -07:00
ce5b37239e chore: add lint job to travis 2016-05-01 22:59:41 -07:00
3e17c99f4e chore: clang-reformat 2016-05-01 22:59:41 -07:00
bb8976608d fix: karma timouts for saucelabs 2016-05-01 22:27:55 -07:00
cd52318f48 fix: parse browser detection lazily 2016-05-01 22:27:55 -07:00
2570b72158 fix: textSelection on FireFox 2016-05-01 22:27:55 -07:00
6e79de794c fix: function name shim test 2016-05-01 22:27:55 -07:00
c4be30d2e8 Revert "build(tsc): Use angular2-template-compiler in place of tsc"
This reverts commit 3d25294f706e0fd6224b20372be1e961959c0af8.
2016-05-01 20:51:00 -07:00
57240c85a5 build(tsc): Use angular2-template-compiler in place of tsc
This gives us tsickle pre-processing of Decorators, and produces
.metadata.json files for users to consume in their offline compilation.
2016-05-01 20:51:00 -07:00
a66cdb469f repackaging: all the repackaging changes squashed 2016-05-01 20:51:00 -07:00
505da6c0a8 repackaging: all the file moves 2016-05-01 20:51:00 -07:00
4fe0f1fa65 feat(router): set router-link-active when RouterLink is active
Closes #8376
2016-05-02 01:03:22 +00:00
ec4ca0eace feat(router): implements support for router-link-active 2016-05-02 01:03:22 +00:00
db95fd6ca9 build(offline compiler): package the compiler-cli for users
Closes #8341
2016-05-02 00:38:54 +00:00
ca13f1c024 fix(router): create a route tree when creating the router service
Closes #8365
2016-05-01 21:38:25 +00:00
277b1fc473 feat(router): add RouteTree and UrlTree as aliases to Tree<RouteSegment> and Tree<UrlSegment> 2016-05-01 21:38:25 +00:00
8836219b16 feat(router): add support for wildcards 2016-05-01 21:38:25 +00:00
6f5e3f9390 Update evaluator.spec.ts
Fix stray `fit` that skips tools tests
Closes #8373
2016-05-01 18:43:32 +00:00
a84c2d7fee fix(typescript): strip abstract keyword from properties in .d.ts
Fixes angular2/src/alt_router/metadata/metadata.d.ts

Closes #8339
2016-05-01 02:59:15 +00:00
f114d6c560 fix(compiler): fix cross view references and providers with useValue.
Before, we would create all fields in the generated views
with visibility `private`. This does not work if an embedded
view references a directive / element in a parent view.
In Dart, this was no problem so far as it does not have
a `private` modifier.

Before, `useValue` in a provider did not work when doing
offline compile, as so far the `MetadataResolver` was only
used for jit mode. Now, `useValue` supports any kind of value
that the static reflector can return. E.g. primitives,
arrays, string maps, …

Closes #8366
2016-05-01 02:30:33 +00:00
163d80adb7 fix(compiler_cli): make sure the generated code gets compiled via tic 2016-05-01 02:30:33 +00:00
9e05814212 chore: move StaticReflector into compiler_cli, part 2
Adjust tests and build to run the unit tests again
after the move.
Closes #8363
2016-04-30 20:53:54 +00:00
ab56be46e1 chore: move static_reflector into compiler_cli
Most of the bugs discovered so far in the offline compiler were related to the StaticReflector. As it was part of angular2 core, it was hard to update. Moving it into the compiler_cli allows to release more often until the compiler_cli gets more stable.

Note: Moving the unit test next to the sources is the simplest option for now in terms of build setup.

Note: This commit only does the move. The next commit updates the build to run it again.
2016-04-30 20:53:54 +00:00
6a0cbb8a57 refactor(core): type ComponentRef, ComponentFactory and ComponentFixture by the component type
BREAKING CHANGE:
- `ComponetRef`, `ComponentFactory`, `ComponentFixture` now all require a type
  parameter with the component type.
Closes #8361
2016-04-30 19:47:54 +00:00
4e2c68354e chore: update ts2dart to 0.9.10 2016-04-30 19:47:54 +00:00
62a0809e81 feat(router): listen to location changes
Closes #8362
2016-04-30 19:02:14 +00:00
76d6f5fa0d fix(router): canDeactivate should not change the url when returns false
Closes #8360
2016-04-30 17:50:28 +00:00
0f1b370117 feat(tests): add ROUTER_FAKE_PROVIDERS to angular2/alt_router/router_testing_providers
This change adds providers for fake router dependecies.
This allows TestComponentBuilder to create components with RouterLink and RouterOutlet directives
without the test writer needing to override them.
2016-04-30 09:42:15 -07:00
e589f9949b chore: align badges in README.md 2016-04-30 08:47:49 -07:00
0f774df811 fix(compiler): project using the right directive as component.
Closes #8344
2016-04-29 18:30:30 -07:00
351f24e8eb fix(core): return the ChangeDetectorRef of the component also for embedded views. 2016-04-29 18:30:30 -07:00
aecb60a604 refactor(core): use Function.bind for referring to event listeners instead of a closure. 2016-04-29 18:30:30 -07:00
4d691b61ee fix(core): check components if an event handler inside of an embedded view fires.
BREAKING CHANGE:
- ViewRef.changeDetectorRef was removed as using ChangeDetectorRefs
  for EmbeddedViewRefs does not make sense. Use ComponentRef.changeDetectorRef
  or inject ChangeDetectorRef instead.

Fixes #8242
2016-04-29 18:30:29 -07:00
11955f9b13 fix(compiler): support empty array and map literals.
This was broken after 152a117d5c

Fixes #8336
2016-04-29 18:30:29 -07:00
5ff31f0713 build(router): create alt_router bundle 2016-04-29 18:05:36 -07:00
deba804671 feat(router): add CanDeactivate 2016-04-29 18:05:06 -07:00
e5b87e55da feat(router): implement relative navigation 2016-04-29 18:04:55 -07:00
d097784d57 chore: adjust public API spec to API changes. 2016-04-29 17:34:32 -07:00
15f6b27ae0 refactor(compiler): support referenced OpaqueTokens correctly in offline compiler. 2016-04-29 16:53:51 -07:00
176e55927c refactor(compiler): support hash syntax for providers. 2016-04-29 16:53:50 -07:00
365be6a309 chore: clang-format after various changes. 2016-04-29 16:53:50 -07:00
713e6d4aff chore: adjust router to /*@ts2dart...*/ 2016-04-29 16:53:50 -07:00
a8e277b067 chore: remove const Provider() in favor of /* @ts2dart_Provider */ {provide:} 2016-04-29 16:53:50 -07:00
3aa322a9c6 chore: replace @CONST() with /*@ts2dart_const*/ 2016-04-29 16:53:50 -07:00
a02614beaa chore: replace CONST_EXPR with /*@ts2dart_const*/ 2016-04-29 16:53:49 -07:00
d2527b504a chore: upgrade to ts2dart@0.9.9 2016-04-29 16:53:49 -07:00
46cd868827 feat(di): support map literals as providers 2016-04-29 16:53:49 -07:00
b1a9e445b3 fix(perf): don’t use try/catch in production mode
The previous code that had `try/catch` statements in methods could not be optimized by Chrome. 

This change separates `AppView` (no `try/catch`) form `DebugAppView` (always `try/catch`). Our codegen will use `AppView` in production mode and `DebugAppView` in debug mode.

Closes #8338
2016-04-29 10:18:57 -07:00
5297c9d9cc refactor(core): deprecate DynamicComponentLoader and DebugNode.inject
BREAKING CHANGE:
- `DynamicComponentLoader` is deprecated. Use `ComponentResolver` and `ViewContainerRef` directly.
- `DebugNode.inject` is deprecated. use `DebugNode.injector.get` instead.
2016-04-29 01:37:58 -07:00
ee7caceec7 Revert "docs: deprecate DynamicComponentLoader and DebugNode.inject"
This reverts commit a0b5964a63.
2016-04-29 01:36:58 -07:00
a0b5964a63 docs: deprecate DynamicComponentLoader and DebugNode.inject 2016-04-29 01:34:06 -07:00
cacdead96d feat(core): introduce template context
BREAKING CHANGE:
- Before, a `EmbeddedViewRef` used to have methods for 
  setting variables. Now, a user has to pass in a context
  object that represents all variables when an `EmbeddedViewRef`
  should be created.
- `ViewContainerRef.createEmbeddedViewRef` now takes
   a context object as 2nd argument.
- `EmbeddedViewRef.setLocal` and `getLocal` have been removed.
  Use `EmbeddedViewRef.context` to access the context.
- `DebugNode.locals` has been removed. Use the new methods `DebugElement.references`
  to get the references that are present on this element,
  or `DebugElement.context` to get the context of the `EmbeddedViewRef` or the component to which the element belongs.

Closes #8321
2016-04-29 01:22:13 -07:00
96ae348648 chore(build): fix formatting and tests
Closes #8098
2016-04-28 23:59:06 -07:00
78946fe9fa feat(offline compiler): a replacement for tsc that compiles templates
see #7483.
2016-04-28 21:57:16 -07:00
33e53c9a59 chore(compiler): add dependency on tsickle
This tool lets us re-write TypeScript sources before entering the emit pipeline.
For example, we lower Decorators to the tree-shakable Annotation form.
2016-04-28 21:55:18 -07:00
c493d88405 chore(compiler): refactoring for offline compiler cli
- pass a baseUrl for asset resolution from static symbols
- fixes in StaticReflector to work with a path-aware host

see #7483
2016-04-28 21:54:02 -07:00
8bf6ef6544 fix(metadata): expose Providers in metadata
These worked in Dart because they were effectively exported even without the export keyword.
Without exporting these symbols, they are not produced in .metadata.json files, which leaves
dangling references from the Decorators that use them.
2016-04-28 21:31:28 -07:00
ca40ef5ac7 fix(codegen): event handler has boolean return type 2016-04-28 21:31:28 -07:00
7c0d4976b1 fix(8223): Preserve Provider expressions
Preserves constructor calls in addition to function calls.
Introduced a special case for forwardRef() similar to CONST_EXPR.
2016-04-28 21:31:28 -07:00
30de2db349 cleanup(router): make analyzer happy
Closes #8220
2016-04-29 02:45:57 +00:00
602641dffd feat(router): adds an example app using the new router 2016-04-29 02:45:57 +00:00
560cc14d97 feat(router): change location when navigating 2016-04-29 02:45:57 +00:00
de56dd5f30 feat(router): add RouterLink 2016-04-29 02:45:57 +00:00
fa5bfe4b64 feat(router): add link that support only absolute urls 2016-04-29 02:45:57 +00:00
446657bdd5 feat(router): update recognize to handle matrix parameters 2016-04-29 02:45:57 +00:00
79830f1c75 feat(router): add RouterUrlSerializer 2016-04-29 02:45:57 +00:00
6e1fed42b7 feat(router): add Router and RouterOutlet to support aux routes 2016-04-29 02:45:57 +00:00
d35c109cb9 feat(router): update recognize to support aux routes 2016-04-29 02:45:57 +00:00
fad3b6434c feat(router): update url parser to handle aux routes 2016-04-29 02:45:57 +00:00
073ec0a7eb chore(CHANGELOG): Fix breaking changes description
Adds more info and examples about how ngFor is affected by the change.
2016-04-28 19:03:54 -07:00
70b23ae2ca refactor(compiler): make static reflector work
Also adjust `RuntimeMetadataResolver` to
be able to use it. 

Also rename `RuntimeMetadataResolver` into `CompileMetadataResolver`.
Closes #8313
2016-04-28 23:06:17 +00:00
769835e53e feat(testing): Use NgZone in TestComponentBuilder.
Instantiating the test component within an NgZone will let us track async tasks in event handlers and change detection.

We can also do auto change detection when triggering events through dispatchEvent and not have to do fixture.detectChange() manually in the test.

New API:
ComponentFixture.autoDetectChanges() - This puts the fixture in auto detect mode that automatically calls detectChanges when the microtask queue is empty (Similar to how change detection is triggered in an actual application).

ComponentFixture.isStable() - This returns a boolean whether the fixture is currently stable or has some async tasks that need to be completed.

ComponentFixture.whenStable() - This returns a promise that is resolved when the fixture is stable after all async tasks are complete.

Closes #8301
2016-04-28 22:37:37 +00:00
ac55e1e27b fix(build): Resolve Dart analyzer issues with the Dart dev channel
Closes #8316
2016-04-28 20:35:56 +00:00
0700c8a252 docs(changelog): update change log to 2.0.0-beta.17. 2016-04-28 11:47:32 -07:00
c79e657fcd chore(release): bump version to 2.0.0-beta.17. 2016-04-28 11:39:20 -07:00
d9648887b8 fix(metadata): Do not attach module names to metadata.
The filename contains the module name as resolved by users, so the top-level module name is uneeded.
Module names on references are replaced by capturing the import syntax from the module.
This allows readers of the metadata to do the module resolution themselves.

Fixes #8225
Fixes #8082

Closes #8256
2016-04-28 01:58:13 +00:00
35cd0ded22 chore(testing): Refactor test methods to have a uniform interface.
Remove FunctionWithParamTokens.

All test wrappers async, fakeAsync and inject now return just a Function instead of FunctionWithParamTokens. This makes them directly consumable by the test framework. Also the test framework code does not have to handle a union of Function and FunctionWithParamTokens everywhere.

The Function returned by the above methods are considered asynchronous by the test framework if they return a Promise, synchronous otherwise.

Closes #8257
2016-04-28 01:16:25 +00:00
d2efac18ed feat(core): separate refs from vars.
Introduces `ref-` to give a name to an element or a directive (also works for `<template>` elements), and `let-` to introduce an input variable for a `<template>` element.

BREAKING CHANGE:
- `#...` now always means `ref-`.
- `<template #abc>` now defines a reference to the TemplateRef, instead of an input variable used inside of the template.
- `#...` inside of a *ngIf, … directives is deprecated.
  Use `let …` instead.
- `var-...` is deprecated. Replace with `let-...` for `<template>` elements and `ref-` for non `<template>` elements.

Closes #7158

Closes #8264
2016-04-28 01:13:40 +00:00
ff2ae7a2e1 fix(testing): allow test component builder to override directives from lists
When a component uses a list of directives, such as `ROUTER_DIRECTIVES`,
make `TestComponentBuilder#overrideDirective` work properly for members
of the list.

Closes #7397

Closes #8217
2016-04-28 00:56:45 +00:00
e1058a4d8a Revert "feat(compiler): ElementSchema now has explicit DOM schema information"
This reverts commit d327ac4b43.
2016-04-27 17:41:57 -07:00
d327ac4b43 feat(compiler): ElementSchema now has explicit DOM schema information
This makes the schema available for offline compile compiler as well.

Closes #8179
2016-04-27 22:57:28 +00:00
1ad2a02b11 fix(core): properly evaluate expressions with conditional and boolean operators
Fixes #8235
Fixes #8244

Closes #8282
2016-04-27 21:25:50 +00:00
1e8864c4a5 fix(compiler): Allow templates to access variables that are declared afterwards.
Fixes #8261
2016-04-27 11:22:44 -07:00
c209836fd0 fix(changelog): fix changelog script.
One charecter missing from
140a878a3d
2016-04-26 16:12:59 -07:00
7d1b6af073 style(global): group multiple imports from same module
Closes #7802

Closes #8209
2016-04-26 22:40:30 +00:00
140a878a3d chore(changelog): regenerate changelog for beta.16 including refactor
- the script explicitly takes input for the starting tag.
- the script only prepends changes.
2016-04-26 15:33:35 -07:00
b62bccf254 build(npm): update rxjs to 5.0.0-beta.6
Closes #6871
Closes #8047
2016-04-26 21:16:37 +00:00
39eb34739a chore(changelog): fix changelog with messages about testing zone deps
Closes #8253
2016-04-26 19:01:12 +00:00
969b55326c docs(changelog): update change log to beta.16 2016-04-25 22:08:32 -07:00
2c8371654a chore(release): bump version to beta.16 2016-04-25 21:48:58 -07:00
5a897cf299 feat(router): add Router and RouterOutlet
Closes #8173
2016-04-25 22:41:33 +00:00
ef67a0c57f feat(router): add router metadata 2016-04-25 22:41:33 +00:00
ef6163e652 feat(router): implement recognizer 2016-04-25 22:41:33 +00:00
f6985671dd feat(router): implement RouterUrlParser 2016-04-25 22:41:33 +00:00
90a1f7d5c4 feat(router): add UrlSegment, RouteSegment, and Tree 2016-04-25 22:41:33 +00:00
3e114227f8 refactor(core): support importUri in StaticReflector
Closes #8195
2016-04-25 22:14:29 +00:00
6103aa0a46 fix(release): Fix the package.json zone.js requirement to 0.6.12 2016-04-25 15:10:06 -07:00
b7c6feff28 chore(release): release the metadata collector
Closes #8197
2016-04-25 21:48:07 +00:00
b48d907697 docs(template-syntax): rename elvis operator
Closes #8196
2016-04-25 21:26:33 +00:00
676ddfa065 docs(cheatsheet): add Directive to cheatsheet
Closes #8170
2016-04-25 20:41:34 +00:00
c8d00dc191 fix(codegen): add explicit any to class fields
fixes #8204

Closes #8205
2016-04-25 20:21:18 +00:00
0b6865d6c6 chore: Remove AngularEntrypoint from TS
Closes #8158
2016-04-25 17:35:05 +00:00
67d05eb65f fix(compiler): use DI order for change detection order.
Closes #8198
2016-04-25 09:36:46 -07:00
152a117d5c fix(compiler): properly implement pure pipes and change pipe syntax
Pure pipes as well as arrays and maps are
implemented via proxy functions. This is
faster than the previous implementation
and also generates less code.

BREAKING CHANGE:
- pipes now take a variable number of arguments, and not an array that contains all arguments.
2016-04-25 09:04:22 -07:00
d6626309fd Revert "fix(compiler): only call pure pipes if their input changed."
This reverts commit 8db62151d2.
2016-04-25 07:53:49 -07:00
c3daccd83b fix(forms): ensure select model updates in firefox and ie
Closes #6573

Closes #8148
2016-04-22 21:23:20 +00:00
8db62151d2 fix(compiler): only call pure pipes if their input changed. 2016-04-21 16:20:19 -07:00
bab81a9831 feat(test): Implement fakeAsync using the FakeAsyncTestZoneSpec from zone.js.
Update the version of zone.js to @0.6.12 that contains the new FakeAsyncTestZoneSpec.

The new fakeAsync zone handles errors better and clearPendingTimers() is no longer required to be called after handling an error and is deprecated.

The fakeAsync test zone will now throw an error if an XHR is attemtped within the test since that cannot be controlled synchronously in the test(Need to be mocked out with a service implementation that doesn't involve XHRs).

This commit also allows fakeAsync to wrap inject to make it consistent with async test zone.

BREAKING CHANGE:

inject can no longer wrap fakeAsync while fakeAsync can wrap inject. So the order in existing tests with inject and fakeAsync has to be switched as follows:

Before:
```
inject([...], fakeAsync((...) => {...}))
```

After:
```
fakeAsync(inject([...], (...) => {...}))
```

Closes #8142
2016-04-21 22:11:00 +00:00
cc86fee1d1 fix(compiler): support string tokens with . inside. 2016-04-21 11:17:49 -07:00
386cc5dbb6 fix(transformers): support query.read
Closes #8172
2016-04-21 10:12:59 -07:00
2f7045720a fix(core): various minor compiler fixes
Closes #8162
2016-04-21 09:13:02 -07:00
9889c21aaa fix(metadata): emit metadata rooted at 'angular2'
fixes #8144

closes #8147
2016-04-20 17:14:53 -04:00
e69cb40de3 fix(forms): number input should report null when blank
Closes #6932

Closes #8141
2016-04-20 20:33:18 +00:00
12837e1c17 fix(forms): improve error message when ngFormModel is missing a form
Closes #8136

Closes #8143
2016-04-20 20:10:50 +00:00
9092ac79d4 refactor(core): support non reflective bootstrap.
This changes Angular so that it can be used without reflection (assuming a codegen for injectors).

BREAKIKNG CHANGE:
- Drops `APP_COMPONENT` provider. Instead, inject
  `ApplicationRef` and read its `componentTypes` property.
- long form bootstrap has changed into the following:
  ```
  var platform = createPlatform(ReflectiveInjector.resolveAndCreate(BROWSER_PROVIDERS));
  var appInjector =
    ReflectiveInjector.resolveAndCreate([BROWSER_APP_PROVIDERS, appProviders], platform.injector);
  coreLoadAndBootstrap(appInjector, MyApp);
  ```
2016-04-20 11:34:11 -07:00
0a7d10ba55 refactor(core): separate reflective injector from Injector interface
BREAKING CHANGE:
- Injector was renamed into `ReflectiveInjector`,
  as `Injector` is only an abstract class with one method on it
- `Injector.getOptional()` was changed into `Injector.get(token, notFoundValue)`
  to make implementing injectors simpler
- `ViewContainerRef.createComponent` now takes an `Injector`
  instead of `ResolvedProviders`. If a reflective injector
  should be used, create one before calling this method.
  (e.g. via `ReflectiveInjector.resolveAndCreate(…)`.
2016-04-20 11:28:13 -07:00
efbd446d18 refactor(core): add Query.read and remove DynamicComponentLoader.loadIntoLocation.
This adds the feature for `@ViewChild`/`@ViewChildren`/`@ContentChild`/`@ContentChildren` to define what to read from the queried element.

E.g. `@ViewChild(`someVar`, read: ViewContainerRef)` will locate the element with a variable `someVar` on it and return a `ViewContainerRef` for it.

Background: With this change, Angular knows exactly at which elements there will be `ViewConainerRef`s as the user has to ask explicitly of them. This simplifies codegen and will make converting Angular templates into server side templates simpler as well.

BREAKING CHANGE:
- `DynamicComponentLoader.loadIntoLocation` has been removed. Use `@ViewChild(‘myVar’, read: ViewContainerRef)` to get hold of a `ViewContainerRef` at an element with variable `myVar`.
- `DynamicComponentLoader.loadNextToLocation` now takes a `ViewContainerRef` instead of an `ElementRef`.
- `AppViewManager` is renamed into `ViewUtils` and is a mere private utility service.
2016-04-20 11:28:00 -07:00
c06b0a2371 refactor(codegen): produce .ngfactory.dart/ts files instead of .template.dart/ts files.
This is needed as we will soon store other
things into the generated files, not
only the templates.
2016-04-20 11:27:34 -07:00
0c600cf6e3 refactor(core): introduce ComponentFactory.
Each compile template now exposes a `<CompName>NgFactory` variable
with an instance of a `ComponentFactory`.
Calling `ComponentFactory.create` returns a `ComponentRef` that can
be used directly.

BREAKING CHANGE:
- `Compiler` is renamed to `ComponentResolver`,
  `Compiler.compileInHost` has been renamed to `ComponentResolver.resolveComponent`.
- `ComponentRef.dispose` is renamed to `ComponentRef.destroy`
- `ViewContainerRef.createHostView` is renamed to `ViewContainerRef.createComponent`
- `ComponentFixture_` has been removed, the class `ComponentFixture`
  can now be created directly as it is no more using private APIs.
2016-04-20 11:27:26 -07:00
41404057cf fix(build): ignore Dart warnings for external code. 2016-04-20 10:51:58 -07:00
f4e6994634 feat(NgTemplateOutlet): add NgTemplateOutlet directive
This commits adds a new NgTemplateOutlet directive that can be
used to create embeded views from a supplied TemplateRef.

Closes #7615

Closes #8021
2016-04-20 04:28:59 +00:00
b602bd8c83 refactor(Location): out of router and into platform/common
closes https://github.com/angular/angular/issues/4943

BREAKING CHANGE:

`Location` and other related providers have been moved out of `router` and into `platform/common`. `BrowserPlatformLocation` is not meant to be used directly however advanced configurations may use it via the following import change.

Before:

```
import {
  PlatformLocation,
  Location,
  LocationStrategy,
  HashLocationStrategy,
  PathLocationStrategy,
  APP_BASE_HREF}
from 'angular2/router';

import {BrowserPlatformLocation} from 'angular2/src/router/location/browser_platform_location';
```

After:

```
import {
  PlatformLocation,
  Location,
  LocationStrategy,
  HashLocationStrategy,
  PathLocationStrategy,
  APP_BASE_HREF}
from 'angular2/platform/common';

import {BrowserPlatformLocation} from 'angular2/src/platform/browser/location/browser_platform_location';
```

Closes #7962
2016-04-20 04:28:47 +00:00
30c43521d3 fix(http) : set response.ok based on given status code
Closes #8056
2016-04-20 04:28:27 +00:00
45f5df371d docs(markdown): add missing space between markdown ### and text, turn h1 into h3s, remove bold.
Closes #7996
2016-04-20 04:09:31 +00:00
43e31c5abb docs(): fix a typo: patform -> platform
Closes #8081
2016-04-18 19:53:19 -07:00
13c8b13343 Add BREAKING CHANGE to CHANGELOG for b.15
Dart apps that import angular2/bootstrap.dart ran in beta.14, but fail in beta.15.

Closes #8071
2016-04-18 19:53:19 -07:00
0fc9ec248e fix(upgrade): clean up scope when element is destroyed
Closes #8102
2016-04-19 01:06:14 +00:00
d094a85647 fix(angular_1_router): Removed arrow function from module template
Closes #8076
2016-04-19 00:44:17 +00:00
22c05b0834 fix(tests): remove payload size check 2016-04-18 17:08:55 -07:00
8490921fb3 feat(tests): manage asynchronous tests using zones
Instead of using injectAsync and returning a promise, use the `async` function
to wrap tests. This will run the test inside a zone which does not complete
the test until all asynchronous tasks have been completed.

`async` may be used with the `inject` function, or separately.

BREAKING CHANGE:

`injectAsync` is now deprecated. Instead, use the `async` function
to wrap any asynchronous tests.

Before:
```
it('should wait for returned promises', injectAsync([FancyService], (service) => {
  return service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
}));

it('should wait for returned promises', injectAsync([], () => {
  return somePromise.then(() => { expect(true).toEqual(true); });
}));
```

After:
```
it('should wait for returned promises', async(inject([FancyService], (service) => {
  service.getAsyncValue().then((value) => { expect(value).toEqual('async value'); });
})));

// Note that if there is no injection, we no longer need `inject` OR `injectAsync`.
it('should wait for returned promises', async(() => {
  somePromise.then() => { expect(true).toEqual(true); });
}));
```

Closes #7735
2016-04-18 15:59:07 -07:00
ecb9bb96f0 docs(): fix broken links
Closes #8028
2016-04-18 20:12:37 +00:00
75463cd8df chore(perf): return perf metrics from AngularProfiler
Closes #8075
2016-04-18 19:48:52 +00:00
c6244d1470 feat(i18n): add support for nested expansion forms
Closes #7977
2016-04-18 19:38:12 +00:00
22ae2d0976 cleanup(html_parser): cleanup to fix analyzer warnings 2016-04-18 19:38:12 +00:00
88b0a239c4 feat(i18n): support plural and gender special forms 2016-04-18 19:38:12 +00:00
7c9717bba8 feat(html_parser): support special forms used by i18n { exp, plural, =0 {} } 2016-04-18 19:38:11 +00:00
7f297666ca feat(html_lexer): support special forms used by i18n { exp, plural, =0 {} } 2016-04-18 19:38:11 +00:00
d99823e2fd docs(core): fix some grammar
Closes #8055
2016-04-18 19:34:17 +00:00
bb9fb21fac feat(i18n): add custom placeholder names
Closes #7799

Closes #8057
2016-04-18 19:14:15 +00:00
b64672b23c fix(dart) reverts protobuf to last working version
Closes #8125
2016-04-18 18:28:43 +00:00
930f58718b Revert "feat(i18n): add support for custom placeholder names"
This reverts commit 2abb414cfb.
2016-04-14 15:36:40 -07:00
2b34c88b69 refactor(view_compiler): codegen DI and Queries
BREAKING CHANGE:
- Renderer:
  * renderComponent method is removed form `Renderer`, only present on `RootRenderer`
  * Renderer.setDebugInfo is removed. Renderer.createElement / createText / createTemplateAnchor
    now take the DebugInfo directly.
- Query semantics:
  * Queries don't work with dynamically loaded components.
  * e.g. for router-outlet: loaded components can't be queries via @ViewQuery,
    but router-outlet emits an event `activate` now that emits the activated component
- Exception classes and the context inside changed (renamed fields)
- DebugElement.attributes is an Object and not a Map in JS any more
- ChangeDetectorGenConfig was renamed into CompilerConfig
- AppViewManager.createEmbeddedViewInContainer / AppViewManager.createHostViewInContainer
  are removed, use the methods in ViewContainerRef instead
- Change detection order changed:
  * 1. dirty check component inputs
  * 2. dirty check content children
  * 3. update render nodes

Closes #6301
Closes #6567
2016-04-13 14:43:48 -07:00
45f09ba686 docs(changelog): update changelog to beta.15 2016-04-13 14:39:17 -07:00
bb62905bef chore(release): bump version to beta.15 2016-04-13 14:39:17 -07:00
7bc9b19418 cleanup(tests): remove unused imports
Closes #6784
2016-04-13 13:24:04 -07:00
e9f7a00910 docs(metadata): Add more docs of ViewChild and ViewChildren
Closes #7174
2016-04-13 13:24:04 -07:00
a5d6b6db8b fix(WebWorker): Fix textarea value not being sent to the worker
Closes #7439
Closes #7828
2016-04-13 13:24:04 -07:00
fc496813e2 fix(7877): StaticReflector returns empty results instead of undefined.
Reflector always returns either an empty object or an empty list if no
metadata is recorded for the class. StaticReflector matches this
behavior.

Closes #7986
2016-04-13 13:23:54 -07:00
2abb414cfb feat(i18n): add support for custom placeholder names
Closes #7799
Closes #8010
2016-04-13 13:23:42 -07:00
0e56aaf189 fix: remove typescript references to d.ts files from benchpress and e2e tests
using "/// <reference" is incorrect because it makes our code non-portable. The correct solution is to provide
these typings as ambient typings as an additional entry point - which we already do.

Closes #8050
2016-04-13 13:23:27 -07:00
3412aba46e feat(typescript): update to 1.9 nightly.
To workaround https://github.com/Microsoft/TypeScript/issues/7573
we must remove the readonly keyword from generated .d.ts files.
This solution will not scale, but will probably buy enough time to require our users move to a 2.0 beta.

Closes #8003
2016-04-13 18:54:58 +00:00
347e71af7d chore(travis): enable the typescript@next build
Fixes #7050
2016-04-13 18:54:58 +00:00
d24df799d3 Revert "feat(iterable_differ): support immutable lists"
In Dart, ImmutableLists are just a projection of an underlying list.
I.e. if the underlying list changes, the ImmutableList also changes.
So we can't make optimizations based on checking whether a collection
is an ImmutableList.

This reverts commit a10c02cb41.

Closes #8023
2016-04-13 17:02:48 +00:00
01e6b8c7ed fix(build): ignore dart warnings The name … is shown, but not used
See https://github.com/angular/angular/issues/8044

Closes #8045
2016-04-13 09:49:33 -07:00
60727c4d2b revert(format): Revert "chore(format): update to latest formatter"
This reverts commit 03627aa84d.
2016-04-12 09:41:01 -07:00
03627aa84d chore(format): update to latest formatter
Closes #7958
2016-04-11 22:15:23 +00:00
83b8f59297 feat(transformers): special case Profiler 2016-04-11 14:32:22 -07:00
c6f454f51d docs: remove duplicate 'directives' from example
Closes #7963
2016-04-11 21:29:21 +00:00
ccff17599a feat(ngFor): Support convenience view local in ngFor
Closes #8013
2016-04-11 21:27:48 +00:00
fb2773b8f3 docs(router): fix wording of hashchange explanation
Closes #7776
2016-04-11 21:11:11 +00:00
5110121f6e docs(ViewQuery): fix typo in documentation
fix typo that confusingly refers to `@Query` rather than `@ViewQuery`.

Closes #7870
2016-04-11 21:04:08 +00:00
27cf897239 chore: upgrade zone.js to v0.6.10
Closes #7818
Closes #7721

Closes #7888
2016-04-11 21:03:59 +00:00
5d33a12af4 chore(gulpfile): turn off mangle for prod
Closes #7988
2016-04-11 20:50:14 +00:00
08b295603c fix(7987): Incremental build works with new trees
Closes #7989
2016-04-11 20:28:34 +00:00
3b60503d2b feat(transformers): changes transformers to collect information about providers and resolve identifiers during linking 2016-04-10 19:36:16 -07:00
3c2473bac6 Fixed typo in documentation
Closes #7943
2016-04-08 23:27:36 +00:00
f9426709ef chore(build): Fix errors reported using 1.9.
Closes #7954
2016-04-08 21:53:50 +00:00
e1e44a910e fix(select): set value individually from ngModel
Closes #7975

Closes #7978
2016-04-08 21:08:05 +00:00
f371c9066d build(broccoli): Clean-up TypeScript build
The TypeScript parser now only references files that are in broccoli trees.

Closes #7941
2016-04-08 19:30:39 +00:00
85c1927993 build(broccoli): AngularBuilder compiles with TypeScript 1.8+.
Beginning with 1.8, if a modules has both a .ts and .d.ts file, the .js
file is not written.

Closes #7947
2016-04-08 19:24:04 +00:00
a596b887ff feat(compiler): Add an implementation for XHR that uses a template cache to load template files.
Useful for avoiding doing an actual XHR during testing.
Part of the solution for #4051 (Other part is a Karma plugin that will create the template cache).

Closes #7940
2016-04-08 19:05:05 +00:00
6cbf99086e feat(gestures): allow override of Hammer default configuration
Closes #7924
2016-04-08 18:53:58 +00:00
26a3390549 refactor(dart/transform): Remove deprecated angular2/bootstrap
BREAKING CHANGE

Remove the deprecated angular2/bootstrap.ts &
angular2/bootstrap_static.ts libraries.

Browser entry points should import angular2/platform/browser which
supplies the `bootstrap` function.

Closes #7650
2016-04-08 18:28:35 +00:00
9a1959f77a build(tslint): re-enable linter and fix violations
fixes #7798

Closes #7800
2016-04-07 23:11:02 +00:00
226e662cf1 feat(parser): TemplateParser.tryParse() returns both the AST and errors
The language service (#7482) always needs the AST even if there are errors
in the template.

Closes #7858
2016-04-07 22:00:46 +00:00
7a1a1b80ed Roll forward to 0.1.24
Closes #7867
2016-04-07 21:58:48 +00:00
529988bc81 Fix DDC errors 2016-04-07 21:58:48 +00:00
c17dc1c057 fix(7837): MetadataCollector takes no parameters for the constructor.
MetadataCollector no longer requires a ts.LanguageService parameter
it didn't use.

Closes #7838
2016-04-07 21:38:07 +00:00
09a95a692e docs(cheatsheet/dart): fix imports
Closes #7872
2016-04-07 21:23:14 +00:00
247964af62 fix(upgrade): make upgradeAdapter upgrade angular 1 components correctly
With this fix, the $onInit function of an upgraded angular 1 component is called and input bindings (<) are created.

Closes #7951
2016-04-07 20:19:46 +00:00
5e2bc5c593 fix(RouterLink): ignore optional parameters when checking for active routes
fixes #6459
Closes #7834
2016-04-07 19:41:14 +00:00
28e657d857 fix(payload): increase payload size limit temporarily 2016-04-07 11:42:13 -07:00
06ad112998 docs(changelog): update change log to beta.14 2016-04-07 10:19:35 -07:00
cfa1d17afe chore(release): bump version to beta.14 2016-04-07 10:09:46 -07:00
3ca6df87b8 fix(select): update name from ng-value to ngValue
Closes #7939
2016-04-06 22:47:21 +00:00
e310bee9e2 feat(dart/transform): Avoid print in transformer code.
Replace direct uses of `print` in the transformer with explicit uses of
stderr.

Add a few @override annotations for clarification of other `print`
implementations.

Clarify error message on incorrect custom_annotations value.

Closes #7855
2016-04-06 22:31:08 +00:00
4902244cce fix(router): allow forward slashes in query parameters
Closes #7824
2016-04-06 22:01:12 +00:00
8db97b0b7a fix(forms): support both value and ng-value 2016-04-06 14:37:57 -07:00
9be04f8d38 fix(upgrade): leak when angular1 destroys element
Fixes #6401

Closes #7935
2016-04-06 19:58:10 +00:00
74e2bd7e3e fix(select): support objects as select values
Closes #4843

Closes #7842
2016-04-06 17:05:38 +00:00
52d3980d02 Revert "feat(transformers): changes transformers to collect information about providers and resolve identifiers during linking"
This reverts commit 4e9809bcb2.
2016-04-06 09:26:03 -07:00
4e9809bcb2 feat(transformers): changes transformers to collect information about providers and resolve identifiers during linking
Closes #7380
2016-04-04 22:59:43 +00:00
bd8a4215dd refactor(core): remove @Injectable as only classes that are instantiated via DI need it 2016-04-04 22:59:43 +00:00
d23b973e7a refactor(forms): extract Validators.required into a variable as transformers cannot resolve statics 2016-04-04 22:59:43 +00:00
0dbf959548 feat(static-reflector): Added StaticReflector
Added a static reflector that uses metadta produced during build
or, additionally, directly from typescript, to produce the metadata
used by Angular code generation compiler.
2016-04-01 14:45:43 -07:00
20812f446f docs(changelog): fix formatting 2016-03-30 18:10:41 -07:00
27a4d0ce11 docs(changelog): update change log to beta.13 2016-03-30 17:23:38 -07:00
9dec4c7485 chore(release): bump version to beta.13 2016-03-30 17:21:51 -07:00
90c87fa6ad fix(codegen): stringify using an opaque ID when toString contains parens.
Using toString results in 'function (_arg1, arg2) {' when using closure compiler for 6-to-5.

Closes #7825
2016-03-30 23:43:35 +00:00
291928feb1 chore(scripts): log out of npm 2016-03-30 16:20:21 -07:00
c9c52fb353 build(pubspec): Clean up pubspec files
Add a direct dependency on package:path.
Remove dependency on package:quiver
2016-03-29 14:30:00 -07:00
0bcfcde63d fix(Router): handling of special chars in dynamic segments
Closes #7804
2016-03-29 20:24:28 +00:00
1c20a62611 feat(dart): Add a dev-mode check for undeclared lifecycle interfaces
Add a check in ReflectionCapabilities#interfaces which determines if
the passed-in type implements a Lifecycle Interface but does not declare
that it does so.

See https://goo.gl/b07Kii for details.

Closes #6849
2016-03-29 10:55:06 -07:00
8430927e6b feat(i18n): update transformers to read a xmb file when provided and use I18nHtmlParser in this case
Closes #7790
2016-03-28 19:54:13 +00:00
d2ca7d81c8 feat(i18n): reexport I18nHtmlParser through the i18n barrel 2016-03-28 19:54:13 +00:00
756121acc1 feat(i18n): update I18nHtmlParser to accept parsed messages 2016-03-28 19:54:13 +00:00
d7e1175df0 feat(i18n): implement xmb deserialization 2016-03-28 19:54:12 +00:00
66cd84e0d5 refactor(i18n): rename serialize into serializeXmb 2016-03-28 19:54:12 +00:00
506f4ce1e5 feat(compiler): Resolvers now use DI to create reflector
Also introduced ReflectorReader when only read-only access to the reflector
is needed.

Closes #7762
2016-03-28 13:52:32 -05:00
a0387d2835 doc(Router): improve the example for routerOnActivate 2016-03-28 10:25:03 -07:00
9bdd5951d9 docs(forms): update the docs to reflect the current behavior
Closes #6504
2016-03-28 10:22:24 -07:00
111afcdff1 fix(build): MetadataCollector correctly collects property metadata
Fixes #7772

Closes #7773
2016-03-25 21:52:06 +00:00
85f3dc2fb5 chore(build): Produce .d.ts files for build tools
Closes #7763
2016-03-25 18:23:00 +00:00
430f367c2f fix(upgrade): make ngUpgrade work with testability API
Closes #7603
2016-03-25 17:27:45 +00:00
d272f96e23 feat(i18n): implement an i18n-aware html parser
Closes #7738
2016-03-24 20:36:19 +00:00
73a84a7098 refactor(i18n): remove utility functions into a separate file 2016-03-24 20:36:19 +00:00
17c8ec8a5d feat(html_parser): change HtmlElementAst to store both the start and the end positions 2016-03-24 20:36:19 +00:00
a1880c3576 feat(facade): add ListWrapper.flatten 2016-03-24 20:36:19 +00:00
91999e016e feat(facade): add RegExpWrapper.replaceAll to replace all matches using the provided function 2016-03-24 20:36:19 +00:00
aa966f5de2 feat(Compiler): Allow overriding the projection selector
fixes #6303

BREAKING CHANGE:

For static content projection, elements with *-directives are now matched against the element itself vs the template before.

    <p *ngIf="condition" foo></p>

Before:

    // Use the implicit template for projection
    <ng-content select="template"></ng-content>

After:

    // Use the actual element for projection
    <ng-content select="p[foo]"></ng-content>
Closes #7742
2016-03-24 20:09:34 +00:00
3e593b8221 chore(test.typings): instrument against examples folder
chore(typing_spec): delete unused typing_spec files

Closes #7743
2016-03-24 19:25:07 +00:00
440aca86a3 chore(examples): fix implied imports in examples for testing built typings 2016-03-24 19:25:07 +00:00
09f4d6f52d chore(refactor): Refactored metadata collector
Renamed MetadataExtractor to MetadataCollector
Reorganized to split src from tests

Closes #7492
2016-03-24 18:52:06 +00:00
3f57fa6e0e chore(build): Added tests for metadata extractor
Adds unit test to metadata extractor classes
Fixes issues found while testing
2016-03-24 18:52:06 +00:00
ae876d1317 feat(build): Persisting decorator metadata
This allows determing what the runtime metadata will be for a
class without having to loading and running the corresponding
.js file.
2016-03-24 18:52:06 +00:00
6de68e2f1f feat(compiler): assert that Component.style is an array
Part of #7481 (effort to improve error messages)

Closes #7559
2016-03-24 15:21:16 +00:00
49527ab495 fix(ngFor): give more instructive error when binding to non-iterable
Before, you'd get an error like:

```
EXCEPTION: Cannot find a differ supporting object ‘[object Object]’ in [users in UsersCmp@2:14]
```

Now, you get:

```
EXCEPTION: Cannot find a differ supporting object ‘[object Object]’ of type 'Object'. Did you mean to bind ngFor to an Array? in [users in UsersCmp@2:14]
```
2016-03-24 15:21:16 +00:00
0898bca939 chore: bump version to beta.12 w/ changelog 2016-03-23 15:56:38 -07:00
d940387beb chore: upgrade zone.js to v0.6.6
Closes #7730
Closes #7737
2016-03-23 20:48:23 +00:00
27c45b05cf Update ISSUE_TEMPLATE.md 2016-03-23 12:53:10 -07:00
90f09d551f Update ISSUE_TEMPLATE.md 2016-03-23 12:50:01 -07:00
3739588e97 chore: build cjs code prior to launching e2e tests
Closes #6783

Closes #7725
2016-03-22 22:09:33 +00:00
0730b753f2 chore(ddc): add e2e test infra + first test 2016-03-22 22:09:33 +00:00
cad693de0f refactor(NgZoneImpl): ensure zone spec is available
trace could be true (in dev mode) while there is no long stack trace spec
Closes #7702
2016-03-22 18:46:12 +00:00
bf911fc992 chore: upgrade zone.js@0.6.5
Closes #7700
2016-03-22 08:21:10 -07:00
fb6d791ce9 test(angular1_router): check that link generation works with baseHref
Closes #7489
2016-03-22 02:19:09 +00:00
0f8efce799 fix(angular1_router): support link generation with custom hashPrefixes 2016-03-22 02:19:09 +00:00
69c1405196 fix(angular_1_router): ng-link is generating wrong hrefs
At the moment ng-link is generating html5mode URLs for `href`s.
Instead it should check whether or not html5mode is enabled and create
the `href`s accordingly. The renaming in the `getLink` function is
aligning it to `RouterLink`'s `_updateLink`.

Closes #7423
2016-03-22 02:19:09 +00:00
980491b08f chore(angular1_router): tighten up the build regex replacement 2016-03-22 02:19:09 +00:00
72e24663ad refactor(dart/transform): Migrates tests to use package:test
Pt 4 of migrating from package:guinness + package:unittest =>
package:test.

This PR migrates DeferredRewriter & DirectiveMetadataLinker unit tests.

Closes #7703
2016-03-22 02:13:16 +00:00
363ed5140e docs(bundles/overview.md): fix typo
Closes #7677
2016-03-22 01:53:35 +00:00
b0f585ab08 build(npm): bump Angular version in our shrinkwrap files 2016-03-22 01:53:35 +00:00
8b67b07580 fix(package.json): remove es6-promise from the peerDependency list
As of zone.js@0.6* we no longer require an es6-promise polyfill. The polyfill is only needed on browsers that don't
have native Promise support.
2016-03-22 01:53:35 +00:00
5c330ea492 chore(publish): run router publish with additional memory
Closes #7408
2016-03-22 00:20:08 +00:00
06eaaf0ac5 chore(angular1_router): bump version to v0.2.0 2016-03-22 00:20:08 +00:00
9820271243 chore(script): publish angular 1 router to latest tag in npm 2016-03-22 00:20:08 +00:00
b6507e37ef feat(dart/transform): Use angular2/platform/browser as bootstrap lib
Update the Angular 2 transformer to recognize
`package:angular2/platform/browser.dart` as the library which exports
the `bootstrap` function.

Update playground, examples, benchmarks, & tests to import bootstrap from
platform/browser.

Closes #7647
2016-03-21 00:58:17 +00:00
c194f6695d chore: bump version to beta.11 w/ changelog 2016-03-18 14:42:31 -07:00
967ae3e1b8 fix(common): remove @internal annotation on SwitchView
Closes #7657
2016-03-18 13:16:50 -07:00
a5e6eaaebc chore: upgrade es6-shim to v0.35.0
Closes #7653
2016-03-18 13:16:15 -07:00
d4e9b55fb6 fix: make sure that Zone does not show up in angular2.d.ts
Closes #7655
2016-03-18 19:41:30 +00:00
048bd280dd chore: re-enable all tests (accidental ddescribe checkin) 2016-03-18 19:41:30 +00:00
8326ab3240 feat(i18n): add a simple dart script extracting all i18n messages from a package
Closes #7620
2016-03-17 16:45:16 -07:00
a7fe983be2 feat(i18n): create i18n barrel 2016-03-17 16:45:15 -07:00
e1f8e54e34 feat(i18n): implement xmb serializer 2016-03-17 16:45:15 -07:00
2b165944ea refactor(i18n): move message and id into a separate file 2016-03-17 16:45:15 -07:00
ea11b3f1f8 docs(changelog): update change log to beta.10 2016-03-17 15:06:28 -07:00
3bd87147ab chore(release): bump version to beta.10 2016-03-17 15:06:27 -07:00
2f581ffc88 fix(router): RouterOutlet loads component twice in a race condition
Closes #7497

Closes #7545
2016-03-16 22:34:54 +00:00
d61aaac400 chore(): remove all angular2_material code. 2016-03-16 13:37:37 -07:00
310620fd12 chore: upgrade to new Zone.js API v0.6.2
BREAKING CHANGE

Removed deprecated API from NgZone
- `NgZone.overrideOnTurnStart`
- `NgZone.overrideOnTurnDone`
- `NgZone.overrideOnEventDone`
- `NgZone.overrideOnErrorHandler`

Rename NgZone API
- `NgZone.onTurnStart` => `NgZone.onUnstable`
- `NgZone.onTurnDone` => `NgZone.onMicrotaskEmpty`
- `NgZone.onEventDone` => `NgZone.onStable`

Closes #7345
2016-03-16 18:05:09 +00:00
f9fb72fb0e chore(core): remove @View annotation
Closes #7495
2016-03-14 23:26:20 +00:00
095db673c5 feat(i18n): implement a simple version of message extractor
Closes #7454
2016-03-14 21:50:00 +00:00
70d18b5b53 feat(compiler): change html parser to preserve comments 2016-03-14 21:50:00 +00:00
f1796d67f4 feat(facade): add .values to StringMapWrapper 2016-03-14 21:50:00 +00:00
cb38d72ff4 feat(shadow_css): support /deep/ and >>>
Fixes #7562

Closes #7563
2016-03-11 22:14:26 +00:00
b72bab49aa feat(core): introduce a CSS lexer/parser 2016-03-11 13:54:01 -08:00
201475e8d8 cleanup(testing): clean up public api spec
Change the old public api spec to check only the exported top-level symbols. This will make sure that Dart and JS do not diverge. The new public api spec verifies the TS api.

Closes #7447
2016-03-11 19:24:29 +00:00
c25b9fcf97 docs(core): update <content> to <ng-content> 2016-03-11 11:19:52 -08:00
8755a8e188 docs(): fix typo 2016-03-11 11:18:59 -08:00
127fbfd5a6 Revert "feat(core): introduce a CSS lexer/parser"
This reverts commit 293fa5505b.

The rebased commit broke CI: https://travis-ci.org/angular/angular/jobs/115388814
2016-03-11 11:14:58 -08:00
f33dda79e9 chore(build): disable broken FirefoxBeta on SauceLabs
See #7560.
2016-03-11 10:57:44 -08:00
293fa5505b feat(core): introduce a CSS lexer/parser 2016-03-11 10:42:29 -08:00
df1f78e302 feat(i18n): add ngPlural directive 2016-03-10 09:55:21 -08:00
43bb31c6c6 refactor(dart/transform): Use targeted transformers
TL;DR: Modify pubspec.yaml files to use the recommended "targeted"
transformers. The unified "simple" angular2 transformer still works as
always, but we want to encourage use of the targeted transformers
whereever possible.

See [the wiki](https://github.com/angular/angular/wiki/Advanced-Transformer-Configuration)
for details about targeted transformers.

See #1872
2016-03-10 09:30:47 -08:00
169869a195 test(matchers): add support for toMatchPattern in tests 2016-03-09 21:31:15 -08:00
b691da26af chore(facade): add enum index lookup support 2016-03-09 21:30:03 -08:00
8e3e45097a fix(router): handle URL that does not match a route
Closes #7349
Closes #7203
2016-03-09 20:48:52 -08:00
aa43d2f87b docs(changelog): update change log to beta 9 2016-03-09 16:37:30 -08:00
128acbb6eb fix(change_detection): fix a memory leak 2016-03-09 16:24:51 -08:00
5824866a83 fix(closure): don't throw from top-level
workaround for http://b/27151095
2016-03-09 16:22:35 -08:00
0d58b137a7 fix(router/instruction): ensure toLinkUrl includes extra params
Closes #7367
2016-03-09 16:21:43 -08:00
b5c769e1e4 chore(release): bump version to beta.9 2016-03-09 14:38:23 -08:00
7f22bd62ab test(angular_1_router): apply annotations to controller constructors
Until Angular 1.5.1 is released, the `$routeConfig` and `$routerCanActivate`
annotations for components must live on the controller constructor.

In Angular 1.5.1, it will automatically copy these annotations across from
the component definition file.

Closes #7319
2016-03-09 21:50:24 +00:00
83f0e7c975 test(angular_1_router): fix router_spec tests
These tests were registering new components after the application had
been bootstrapped, which is not a valid use case for synchronous routes
in Angular 1.

In particular it was registering the "root" component, which caused the
`$rootRouter` to blow up, when it was instantiated, pointing to a root
component that did not yet exist.
2016-03-09 21:50:24 +00:00
adef68b4d6 refactor(angular_1_router): remove directiveIntrospector
The directiveIntrospector was a bit of a hack to allow the router to
read the `$routeConfig` annocation and `$routerCanActivate` hook from
directives when they were registered.

It turns out that if we put these properties on the component controller's
constructor function (i.e. as static class methods) then we can simply
use the `$injector` to access it as required.

Currently, people put the properties directly on their component definition
objects. In Angular 1.5.1, we will copy these properties onto the controller
constructor to maintain a simple migration path. But going forward it may be
better to encourage people to add the properties directly to the controller
constructor.
2016-03-09 21:50:24 +00:00
14f0e9ada8 chore: fix DDC errors / warnings
Closes #7195
2016-03-08 22:17:32 +00:00
ef9e40e82b refactor(dart/transform): Migrates tests to use package:test
Pt 3 of migrating from package:guinness + package:unittest => package:test.

This PR migrates DirectiveProcessor & InlinerForTest unit tests.

Closes #7475
2016-03-08 01:39:23 +00:00
41e38e4330 fix hammer_gestures infinite loop 2016-03-08 01:37:40 +00:00
2c7c3e3c69 feat(TAG_DEFINITIONS): include <meta> and <base>
needed to parse index.html as a component template
Closes #7455
2016-03-08 01:03:20 +00:00
756f5d884f refactor(dart/transform): AnnotationMatcher tests
These were previously not being run.

Bring them up to modern usage, move them to package:test, and include
them in transform.server.spec.dart.

Closes #7463
2016-03-08 00:47:35 +00:00
45fd6f0a41 feat(transformers): change 'Missing Identifier' to be an error
Closes #7403
2016-03-08 00:08:36 +00:00
75ae4a9159 ci(publish-build-artifacts.sh): skip all the work for builds other than upstream/master
Closes #7413
2016-03-05 19:54:22 +00:00
37d18d0112 ci(travis): publish artifacts only from the upstream/master jobs 2016-03-05 19:54:22 +00:00
773fe8f8c5 ci(travis): simplify job status reporting 2016-03-05 19:54:22 +00:00
4da2b19ea0 docs(CONTRIBUTING.md): clarify the difference between build and ci commit message scopes 2016-03-05 19:54:22 +00:00
9f3547e35d ci(travis): fix typo in webhooks config 2016-03-05 19:54:22 +00:00
5a79358727 ci(travis): fix indentation in of the .travis.yaml 2016-03-05 19:54:22 +00:00
85bfbc13c1 ci(travis): clean up matrix environmental variables
remove all unnecessary ones.
2016-03-05 19:54:22 +00:00
1a01af9e68 ci(travis): clean up, reorganize and document before_install and install scripts
Functionally this should be a noop change.
2016-03-05 19:54:22 +00:00
dd95e901df ci(travis): remove bogus environmental variable 2016-03-05 19:54:22 +00:00
9782d8c32e ci(travis): better document before_cache script 2016-03-05 19:54:22 +00:00
80764c6f71 ci(travis): use gcc v4.8 to compile npm native modules on Node v4 and v5 2016-03-05 19:54:22 +00:00
d9e78e4fa8 build(analytics): allow build analytics to take previous exit code as the first argument 2016-03-05 19:54:22 +00:00
10fedd0dfc ci(analytics): correctly report CI job errors as errors 2016-03-05 19:54:22 +00:00
315e73c47c ci(analytics): report Travis ID without the build number prefix
We need to track latency of individual jobs over time, but don't care to know what's the build ID that these jobs are associted with.
2016-03-05 19:54:22 +00:00
912717ff31 ci(analytics): fix TRAVIS_PULL_REQUEST reporting
process.env.TRAVIS_PULL_REQUEST contains a string and not a boolean value, so we need
to compare it to a string literal rather than do boolean arithmetics.
2016-03-05 19:54:22 +00:00
b857fd1eeb Revert "feat(transformers): collect provider information"
This reverts commit 81beb1c788.

Broke Google3.
2016-03-04 13:51:26 -08:00
6dce4f49c2 feat(router): Added method to get current instruction
This method delegates to the root router to get the current complete instruction.
2016-03-04 02:10:58 -08:00
15e16148f4 feat(dart/transform): Create standalone transformers for phases
Create transformers that allow specifying transformer actions on
specific libraries.

* angular2/transform/codegen: Generates all necessary code.
* angular2/transform/reflection_rewriter: Replaces `bootstrap` calls in
  application entry points to remove transitive dart:mirrors import,
  resulting in smaller code size & faster execution.
* angular2/transform/deferred_rewriter: Rewrites deferred imports and
  `loadLibrary` calls to initialize Angular2 and preserve deferred
  operation.

Proper configuration of these three transformers can replace the single
angular2 transformer, resulting in significant performance gains for
builds of large angular2 apps.

Update angular2 itself to declare the codegen transformer, since it has
neither deferred imports nor application entry points.

Remove the undocumented & unused quick_transformer.
2016-03-04 09:52:44 +00:00
ae49085481 fix(angular_1_router): Renamed require statements after TypeScript files are transpiled
The require function was causing failures when bundled using Browserify and SystemJS

Closes #7049
2016-03-04 09:31:24 +00:00
11e8aa26f6 feat(angular1_router): Add ng-link-active class to active ng-link
Closes #6882
2016-03-04 09:30:58 +00:00
81beb1c788 feat(transformers): collect provider information 2016-03-04 01:19:25 -08:00
6402d61f69 chore: fix up ngClass for types/export missing public API
Closes #7202
2016-03-04 08:03:55 +00:00
5a59e44765 chore(test): migrate Dart tests to package:test
Instead of running with karma and the karma-dart shim, run dart
tests directly using the new package:test runner. This migrates
away from package:unittest.

Fixes a couple tests, mostly associated with depending on absolute
URLs or editing the test providers after an injector had already
been created.

Remove karma-dart and associated files. Change gupfiles to run tests
via `pub run test` instead.
2016-03-04 02:27:44 +00:00
7455b907d1 Revert "feat(dart): Add a dev-mode check for undeclared lifecycle interfaces"
This reverts commit a3d7629134.

Needs co-ordination with google3 changes.
2016-03-03 18:00:18 -08:00
579b890446 chore(dart) Update dev dependency on code_tranformers
Closes https://github.com/angular/angular/issues/6665
2016-03-03 23:12:02 +00:00
19a08f3a43 feat(compiler): Added spans to HTML parser errors
Allows using the HTML parser in contexts errors are reported in a development tool such as an editor.
2016-03-03 22:51:57 +00:00
a3d7629134 feat(dart): Add a dev-mode check for undeclared lifecycle interfaces
Add a check in `ReflectionCapabilities#interfaces` which determines if
the passed-in type implements a Lifecycle Interface but does not declare
that it does so.

See https://goo.gl/b07Kii for details.

Closes #6849
2016-03-03 22:45:50 +00:00
bc9644e86e chore: add github issue / pr template 2016-03-03 14:06:11 -08:00
a10c02cb41 feat(iterable_differ): support immutable lists
Closes #7127
2016-03-03 18:29:01 +00:00
9936e347ff chore(build): Remove circular dependency in Angular 2 ES5 output.
Remove couple of circular dependency between modules in Angular 2 ES5 output caused by exception_handler.ts and router_providers.ts.

Fix the build/checkCircularDependency gulp task to call madge properly to detect the circular deps.

Closes #7287
2016-03-03 17:42:33 +00:00
7d44b8230e fix(router): support outlets within dynamic components
Fixes internal b/27294172
2016-03-03 06:49:29 -08:00
75343eb340 feat(router): add regex matchers
@petebacondarwin deserves credit for most of this commit.

This allows you to specify a regex and serializer function instead
of the path DSL in your route declaration.

```
@RouteConfig([
  { regex: '[a-z]+.[0-9]+',
    serializer: (params) => `{params.a}.params.b}`,
    component: MyComponent }
])
class Component {}
```

Closes #7325
Closes #7126
2016-03-02 16:08:19 -08:00
2548ce86db fix(angular1_router): rename router component binding to $router
The current router is passed to the current component via a binding.
To indicate that this is an angular provided object, this commit
renames the binding to `$router`.

BREAKING CHANGE:

The recently added binding of the current router to the current component
has been renamed from `router` to `$router`.

So now the recommended set up for your bindings in your routed component
is:

```js
{
  ...
  bindings: {
    $router: '<'
  }
}
```
2016-03-02 16:08:19 -08:00
5586c29492 fix(angular1_router): support templateUrl components 2016-03-02 16:08:19 -08:00
1174473e9c fix(angular1_router): rename router component binding to $router
The current router is passed to the current component via a binding.
To indicate that this is an angular provided object, this commit
renames the binding to `$router`.

BREAKING CHANGE:

The recently added binding of the current router to the current component
has been renamed from `router` to `$router`.

So now the recommended set up for your bindings in your routed component
is:

```js
{
  ...
  bindings: {
    $router: '<'
  }
}
```
2016-03-02 16:08:19 -08:00
1d49b3e36b fix(build): Use fixed version of Chromium Canary that will be updated manually instead of automatically using the latest Chrome canary 2016-03-02 15:35:07 -08:00
2830df4190 docs(changelog): update change log to beta 8 2016-03-02 11:32:38 -08:00
143cf89b5f chore(release): bump version to beta. 2016-03-02 11:31:25 -08:00
69c1694900 fix(WebWorker): Make MessageBus EventEmitter synchronous 2016-03-01 23:23:17 +00:00
01fe7f5fac fix(WebWorker): Fix PostMessageBusSink and Source undefined error.
Closes #7156
2016-03-01 14:40:09 -08:00
9aedef208f fix(test): fix a broken test 2016-03-01 14:38:55 -08:00
39b6e0efba feat(transformers): collect information for CompileDiDependencyMetadata 2016-03-01 13:28:36 -08:00
f60fa14767 feat(core): drop ChangeDetectionStrategy.OnPushObserve
BREAKING CHANGE:

`OnPushObserve` was an experimental
feature for Dart and had
conceptual performance problems,
as setting up observables is slow.
Use `OnPush` instead.
2016-03-01 13:28:10 -08:00
d900f5c075 chore(tests): lengthen timeout for templateUrl test
This was flaking on Travis occasionally because the TestComponentBuilder
is actually doing an XHR, and it was slow on the Edge browser.

Closes #7293
2016-03-01 21:01:56 +00:00
391a9edabb chore(build): use Chromium in Travis for JS tests 2016-03-01 11:24:44 -08:00
28a78117eb refactor(dart/transform): Migrates tests to use package:test
Our transformer unit tests currently use package:guinness, which uses
package:unittest under the covers. package:unittest has been updated and
renamed package:test, so for simplicity migrate test to use package:test
syntax.
2016-03-01 19:20:06 +00:00
eeb594c010 fix(dart/payload): Fix runtime error in hello_world payload app
The hello_world app used to measure Dart payload size was broken by a
change in
7ae23adaff.

This breakage does not materially affect the size of the generated code,
(before fix: 298819, after fix: 298825), and since it was a runtime
error it was not noticed & not a problem.

Update the app to work again.

Closes #7358
2016-03-01 18:51:12 +00:00
0bb10d6bb6 feat(transformers): makes the map of resolved identifiers configurable
Closes #7359
2016-03-01 17:57:19 +00:00
59629a0801 feat(i18n): added i18nPlural and i18nSelect pipes
Closes #7268
2016-03-01 16:40:48 +00:00
b5e6319fa9 feat(core): add more debug APIs to inspect the application form a browser
Adds `window.getAllAngularRootElements()`
Adds `ng.coreTokens.ApplicationRef`
Adds `ng.coreTokens.Ngzone`

Closes #7045
Closes #7161
2016-03-01 16:01:28 +00:00
c9a3df970b feat(di): drop support for injecting types with generics in Dart
BREAKING CHANGE:
In Dart we used to support injecting types with generics. As this feature is hard to implement with the upcoming codegen we are dropping it.

Merge cl/115454020 in G3 with this change.
Closes #7262
2016-03-01 05:43:49 +00:00
f72f137261 ci(dart): Uncomment dart.dev build and make it required
Workaround for https://github.com/dart-lang/dartdoc/issues/1099: remove
the `--input=.` parameter to `dartdoc`.

Closes #6823, #6410

Closes #6958
2016-03-01 01:21:27 +00:00
ee3c580e88 fix(transformers): replace an error with a warning when cannot resolve a symbol 2016-02-29 16:03:13 -08:00
05c185a7b1 fix(transformers): record reflection info about abstract classes
Closes #7347
2016-02-29 22:57:22 +00:00
b47f80ec76 fix(Router): Query strings are copied for HashLocationStrategy
b/27210802 P1

Closes #7298
2016-02-29 18:44:56 +00:00
ebd438ff5e fix(change_detection): allow to destroy OnPush components inside of a host event.
Closes #7192
2016-02-29 18:44:13 +00:00
331b9c1317 fix(transformers): special case types some built-in types, so they can be resolved 2016-02-29 10:34:34 -08:00
4a93f58b8b fix(web_worker): wait for bindings in kitchen sink spec 2016-02-26 10:34:32 -08:00
ebe531bf92 feat(transformers): collect data needed for the template compiler
Closes #7299
2016-02-26 17:56:40 +00:00
1779caf5f8 fix(core): support ngFor that has an ngIf as last node
Fixes #6304
Closes #6878
2016-02-25 23:42:17 +00:00
6ef2121e6a feat(pipes): add ReplacePipe for string manipulation
add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.

feat(pipes): add ReplacePipe for string manipulation

add commonly used pipe that is missing  from framework.
2016-02-25 22:56:13 +00:00
38cb526f60 feat(forms/validators): pattern validator
Adding static pattern validation method to Validators

Adding a directive for the pattern validator

Applying clang-format rules to modified files

Updating public api spec for new pattern validator

Adding pattern validator to public api guard tool

For #5411

Closes #5561
2016-02-25 22:39:15 +00:00
f6a8d04c32 fix(web_workers): make waitForElementText function more stable 2016-02-25 14:28:20 -08:00
4b3b5d7c53 cleanup(build): fix jsserve not to throw 2016-02-25 13:39:02 -08:00
abff302e52 chore(tests): fix broken test from using the wrong xit
Also, run clang-format.
2016-02-25 10:50:59 -08:00
e1f6679c75 chore: make incremental dart tests work again 2016-02-25 10:26:11 -08:00
aaafdf03ce test(testing): add a test to ensure fakeAsync works with angular2/testing 2016-02-25 10:22:18 -08:00
ee298baa1b test(router): disable a flaky test 2016-02-25 10:21:53 -08:00
d1abada5b7 build(travis): do not cache npm modules 2016-02-24 17:56:55 -08:00
ab36ea097b fix(differ): clean up stale identity change refs
Closes #7193
2016-02-24 17:56:55 -08:00
8bb66a5eb3 chore: noImplicitAny fixes 2016-02-24 15:29:00 -08:00
cfc1e56dd8 refact(angular1_router): make the $$router binding one-time
This binding is never going to change so we can make it a one-time binding

Closes #6978
2016-02-24 21:15:34 +00:00
a1c3be21ec fix(angular1_router): rename $route service to $rootRouter
The singleton service that represents the top level router was called
`$router` but this is confusing since there are actually lots of routers,
which depend upon where you are in the DOM. This is similar to the situation
with scopes.

This commit clarifies this singleton by renaming it to `$rootRouter`.

BREAKING CHANGE:

The `$router` injectable service has been renamed to `$rootRouter`
2016-02-24 21:15:34 +00:00
edad8e3f56 fix(angular1_router): rename router component binding to $router
The current router is passed to the current component via a binding.
To indicate that this is an angular provided object, this commit
renames the binding to `$router`.

BREAKING CHANGE:

The recently added binding of the current router to the current component
has been renamed from `router` to `$router`.

So now the recommended set up for your bindings in your routed component
is:

```js
{
  ...
  bindings: {
    $router: '<'
  }
}
```
2016-02-24 21:15:34 +00:00
d4a4d81173 fix(angular1_router): support templateUrl components 2016-02-24 21:15:34 +00:00
e7470d557d feat(core): Add QueryList.forEach to public api. 2016-02-19 19:23:46 -05:00
b634a25ae0 feat(core): Add QueryList#forEach 2016-02-19 19:23:46 -05:00
c1a0af514f feat(test): add withProviders for per test providers
Closes #5128
2016-02-19 19:23:46 -05:00
c6afea61f1 fix(DomRenderer): correctly handle namespaced attributes 2016-02-19 19:23:46 -05:00
ce10fe92b2 chore(travis): remove problematic chromebeta target for now 2016-02-19 10:43:59 -08:00
b81b1fb81c revert: fix(change_detection): allow to destroy OnPush components inside of a host event
This reverts commit 280b86ec55.
2016-02-19 10:34:03 -08:00
280b86ec55 fix(change_detection): allow to destroy OnPush components inside of a host event. 2016-02-18 17:54:24 -08:00
2f5a2ba671 docs(changelog): update changelog to beta.7 2016-02-18 13:28:10 -08:00
c45ec6f1be chore(release): bump version to beta.7 2016-02-18 13:28:08 -08:00
530470e0ce chore(travis): add an integration hook for the angular hubot daemon 2016-02-17 16:38:42 -08:00
ce72ccf9e8 build(npm): bump zone.js version to 0.15.5 2016-02-17 16:28:50 -08:00
46d9c87ddc build(package): bump rxjs to 5.0.0-beta.2
Closes #7001
2016-02-17 16:28:50 -08:00
d736c31fea test(material): disable problematic e2e test
LGTM from Victor and Jeff in person :)
2016-02-17 16:18:33 -08:00
a7e9bc97f6 ci(typescript): add typescript_next build
Install typescript@next before build.js and test.typings.
Restore the regular version before travis caches node_modules/.

Fixes #6368
2016-02-16 17:29:29 -08:00
265703b950 fix(typing): Remove re-export of the Promise built-in type.
Instead, ts2dart can add the 'dart:async' import whenever
Promise is used.

Fixes #6468
2016-02-12 20:45:41 -08:00
ae275fa4e4 chore(ts2dart): update ts2dart to 0.7.24 2016-02-12 20:45:35 -08:00
3478d5d450 fix(angular_1_router): Added DI string tokens
Closes #4269

Closes #7031
2016-02-12 21:15:34 +00:00
e72dc16dbe docs(changelog): update changelog to beta.6 2016-02-11 16:03:00 -08:00
40a043275d chore(release): bump version to beta.6 2016-02-11 15:59:34 -08:00
f161b5cc28 chore(zone.js): update to 0.5.14 2016-02-11 14:39:41 -08:00
117d57e121 Revert "chore(zone.js) : update to 0.5.14"
This reverts commit 3dcce706fd.
2016-02-11 14:38:06 -08:00
3dcce706fd chore(zone.js) : update to 0.5.14 2016-02-11 14:15:59 -08:00
efb89b83e1 Revert "fix(DomRenderer): correctly handle namespaced attributes"
This reverts commit 61cf499b0b.
2016-02-11 13:44:16 -08:00
3d96c2337f Revert "feat(svg): Provide support for SVG foreignObject by adding xhtml namespace"
This reverts commit eb688f2c8e.
2016-02-11 13:39:02 -08:00
19cfb4eb12 fix(build): publish typings directory to our npm snapshot branch 2016-02-11 11:35:43 -08:00
3d715a2f7b fix(typings): publish es6 typings rather than postinstall.
Despite local testing, multiple users failed to run the postinstall to install typings.
Instead, we can distribute the typings we installed locally.

This is an alternative to #7003.
This also reverts rxjs to beta.1 since we have errors using beta.2, being addressed
in #7001.

Fixes #7000
2016-02-11 11:04:42 -08:00
c7261c295c docs(changelog): update change log to beta.5 2016-02-10 16:31:01 -08:00
1a26f8edd6 chore(release): bump version to beta.5 2016-02-10 16:30:18 -08:00
fc887774da fix(release): need to depend on latest rxjs and zone.js
The version in our package.json gets copied to the one we publish, and users need the latest of these.
2016-02-10 16:29:58 -08:00
7cbf88a691 docs(changelog): update change log to beta.4 2016-02-10 16:04:17 -08:00
1cb1c139cf chore(release): bump version to beta.4 2016-02-10 16:04:17 -08:00
1fd924f7d5 refactor(dart/transform): Simplify deferred rewriting
Simplify the DeferredRewriting and move package:quiver to a dev
dependency.

Closes #6994
2016-02-10 23:43:57 +00:00
eb688f2c8e feat(svg): Provide support for SVG foreignObject by adding xhtml namespace
Closes #6192
2016-02-10 23:23:34 +00:00
61cf499b0b fix(DomRenderer): correctly handle namespaced attributes
Closes #6363
2016-02-10 22:34:13 +00:00
f1f5b45361 feat(typings): install es6-shim typings to a location users can reference.
This makes the upgrade to beta.4 as simple as adding one reference tag, only when --target=es5
Implements option 3 from https://docs.google.com/document/d/1vgepQPkuHS4P3rzANQpoMIDIXe0Rl9Z2QyTtb8dpMoI/edit
2016-02-10 14:13:27 -08:00
50548fb565 fix(forms): use strict runtimeType checks instead of instanceof
Currently, validators extending built-in validators are treated as built-in.
This can result in an error when both a real built-in validator and a custom one are applied to the same element.

Closes #6981
2016-02-10 09:23:59 -08:00
8f47aa3530 fix(forms): add RadioButtonValueAccessor to the list of default value accessors 2016-02-09 15:28:08 -08:00
df7885c9f5 fix(router): Added route data to normalized async route
Closes #6802
2016-02-09 22:08:45 +00:00
0f10624b08 fix(ngFor): update view locals if identity changes
Closes #6923
2016-02-09 22:06:06 +00:00
6f1ef33e32 fix(router): fix url path for star segment in path recognizer
Url path of star segments should equal the original path.

If you register the route `/app/*location` and invoke a url like `/app/foo/bar`
the PathRecognizer should return a url path equal to the invoked url.

Before this patch, everything after `foo` was ignored, which resulted in a
redirect to `/app/foo` which was probably not intended (at least in the angular
1.5 component router).

Closes #6976
2016-02-09 21:45:06 +00:00
231773ea76 fix(compiler): use event names for matching directives
Closes #6870
2016-02-09 13:16:08 -08:00
e725542703 fix(forms): add support for radio buttons
Closes #6877
2016-02-09 19:47:50 +00:00
2337469753 style(angular1_router): license year updated
Closes #6219
2016-02-08 17:21:00 -08:00
55122cd57a fix(angular1-router): add missing wrapper methods
Closes #6763
Closes #6861
Closes #6861
2016-02-08 17:19:50 -08:00
7e0f02f96e fix(upgrade): fix infinite $rootScope.$digest()
Fixes #6385
Closes #6386
2016-02-08 17:18:52 -08:00
e7ad03cba6 fix(core): add detail to dehydrated detector exception
- at least I know what component is causing the error with this. without it the exception is so generic that it's not useful.

Closes #6939
2016-02-08 17:17:37 -08:00
74be3d3fde fix(core): mute mode printing in console in prod mode
Closes #6873
2016-02-08 17:16:19 -08:00
a15ca23469 refactor(mock): update variable names in directive_resolver_mock.ts
Closes #5056
2016-02-08 17:11:43 -08:00
de77700da0 fix(di): throw if a token uses more than 20 dependencies.
Fixes #6690
Closes #6869
2016-02-08 16:21:57 -08:00
e73fee7156 fix(router): fixed the location wrapper for angular1
In angular2 `Location.path()` returns the complete path including query string. In angular1 the query parameters are missing. Similar to this `Location.go` does accept two parameters (path *and query*).

Closes #6943
2016-02-08 16:18:26 -08:00
72ab35bceb test(angular1_router): test that location handles query strings
See 6698
2016-02-08 16:18:13 -08:00
0f22dce036 feat(angular1_router): allow component to bind to router 2016-02-08 16:18:13 -08:00
c6036435f0 fix(router): don't prepend / unnecessarily to Location paths
Closes #6729
Closes #5502
2016-02-08 16:18:13 -08:00
d86be245b8 fix(angular1-router): add support for using the component helper
In Angular 1.5 there is a new helper method for creating component directives.
See https://docs.angularjs.org/guide/component for more information about components.

These kind of directives only match the `E` element form and the previously component
router only created HTML that matched directives that matched the `A` attribute form.

This commit changes the `<ng-outlet>` directive so that it generates custom HTML
elements rather divs with custom attributes to trigger the relevant component to
appear in the DOM.

Going forward, Angular 1.5 users are encouraged to create their router components
using the following style:

```
myModule.componnet('component-name', {
  // component definition object
});
```

Closes angular/angular.js#13860
Closes #6076
Closes #5278

BREAKING CHANGE:

The component router now creates custom element HTML rather than custom attribute
HTML, in order to create a new component. So rather than

```html
<div custom-component></div>
```

it now creates

```html
<custom-component></custom-component>
```

If you defined you router components using the `directive()` helper and
specified the `restrict` properties such that element matching was not allowed,
e.g. `restrict: 'A'` then these components will no longer be instantiated
by the component router and the outlet will be empty.

The fix is to include `E` in the `restrict` property.

`restrict: 'EA'`

Note that this does not affect directives that did not specify the `restrict`
property as the default for this property is already `EA`.
2016-02-08 16:18:13 -08:00
a26053d3ff docs(cheatsheet): fix Dart cheatsheet
Also deletes an extraneous period from the JS cheatsheet.

Closes #5936
2016-02-08 15:58:22 -08:00
24d5b665e1 docs(HostBindingMetadata): Removed brackets from host bindings in HostBindingsMetadata example
Closes #6941
2016-02-08 15:55:49 -08:00
aa98fad338 docs: fix typo in 01_templates.md
Replace `an` with `a`

Closes #6842
2016-02-08 15:52:30 -08:00
9cb6dbbbab docs: fixed typo in documentation
Closes #6842
2016-02-08 15:30:15 -08:00
e21718faa9 docs(router): Updated inconsistencies in router docs
Closes #6805
2016-02-08 22:31:04 +00:00
b0f7d59e64 revert: chore: update the version of ts2dart
This reverts commit 22929a1671.

This commits makes our build red without the other commit that was already reverted.

More info at: https://github.com/angular/angular/pull/6825#issuecomment-181592303
2016-02-08 14:13:00 -08:00
b86829f492 revert: feat(transformers): collect information about di dependencies and providers
This reverts commit 86c40f8474.

Reason: new issues were discovered during the g3sync. @vsavkin is working on fixing them.
2016-02-08 12:15:03 -08:00
22929a1671 chore: update the version of ts2dart
Closes #6804
2016-02-05 21:56:33 +00:00
86c40f8474 feat(transformers): collect information about di dependencies and providers 2016-02-05 21:56:33 +00:00
16b521794c fix(build): don't try to copy .d.ts files into the npm distro
Fixes #6921
2016-02-05 11:53:15 -08:00
2a70f4e4c7 fix(typings): Don't expose typing dependencies to users.
This resolves Duplicate Identifier issues seen by many users,
at the expense of more typings installation required in some
cases.

Removes the quickstart hack of placing all needed dependencies
typings files in our distribution. Removes dependencies on
nodejs from angular2/core.

Fixes #5973
Fixes #5807
Fixes #6266

Angular now depends on es6-promise and es6-collections
(and a handful of manual typings) rather than all of es6-shim.

Fixes #5242

We previously had an undocumented breaking change, this is now
documented in this commit.

Fixes #6817

BREAKING CHANGE:

Transitive typings are no longer included in the distribution.
You may need to install typings in your project using
http://github.com/typings/typings

Users now must rely on getting typings from:
- one of the peerDependencies, such as rxjs, which exposes
  typings via the moduleResolution=node mechanism.
  (see https://github.com/Microsoft/TypeScript/wiki/Typings-for-npm-packages)
  This happens automatically.
- Using --target ES5 now requires manual installation of
  es6-promise and es6-collections typings.
- Using some angular APIs may introduce a dependency on eg. nodejs
  or jasmine, and those typings need manual installation as well.

Closes #6267
2016-02-04 22:42:40 +00:00
2f31c4c1c5 chore(typings): use mainline DefinitelyTyped repo rather than a fork.
The upstream Jasmine typings don't define a type for the global
object with Jasmine methods polluting it, so just use any.

Also zone.js has a different name upstream.
2016-02-04 22:42:40 +00:00
1435763383 chore(deps): update ts2dart and zone.js 2016-02-04 22:42:40 +00:00
05238df89b docs(changelog): add missing breaking change for beta.3 2016-02-03 11:43:17 -08:00
772d60d9fe docs(changelog): changelog for beta.3 2016-02-03 10:36:06 -08:00
24086bf0bb chore(release): bump version to beta.3 2016-02-03 10:36:06 -08:00
9b0e10e9a7 fix(compiler): fix interpolation regexp
- Fix the interpolation regexp to match newline characters (i.e. `\n` and `\r`)

Closes #6056
2016-02-03 15:21:55 +00:00
995a9e0cf8 fix(router): fix incorrect url param value coercion of 1 to true
seriliazeParams is coercing a value of 1 to true, which causes the value to be completey dropped.
Change the test from double equals to triple equals to prevent this from happening.

Closes #5346

Closes #6286
2016-02-03 15:00:24 +00:00
b55f1764b5 fix(Headers): serializable toJSON
fixes #6073

Closes #6714
2016-02-03 14:03:01 +00:00
5e9daed2e8 docs(http.ts): Fix MockBackend examples using backend.connections observer
Properly format observer examples.
2016-02-03 05:58:40 -08:00
aa8c5aa2e2 docs(http): fix example usage of MockBackend 2016-02-03 05:57:08 -08:00
f2c7946cca chore(http): make all typings explicit 2016-02-03 05:31:40 -08:00
da1fcfd820 fix(WebWorkers): Fix flaky WebWorker test
Closes #6851
2016-02-03 05:30:11 -08:00
dbeff6f548 style(ReflectionCapabilities) _zipTypesAndAnnotations, not _zipTypesAndAnnotaions
I was stepping through the Reflector and came across this little guy.

Closes #6535
2016-02-03 03:57:06 +00:00
26e60d658a fix(async): handle synchronous initial value in async pipe
Closes #5996
2016-02-03 03:56:52 +00:00
c2ceb7fba4 fix(Validators): fix Validators.required marking number zero as invalid
Closes #6617
2016-02-03 03:34:42 +00:00
4bfe49cd42 docs(core): update QueryList's onChange to changes.subscribe 2016-02-02 19:23:03 -08:00
cee2318110 feat(ngFor): add custom trackBy function support
Make it possible to track items in iterables in custom ways (e.g. by ID or index), rather than simply by identity.

Closes #6779
2016-02-03 01:03:31 +00:00
cfef76f683 refactor(dart/transform): Error in name convert funcs on unexpected input
Issue raised in PR #6745.
Previously, the transformer name conversion functions could return the
input string on unexpected input, which is almost certainly an error.

`throw` in this case instead, so we know early that something has likely
gone wrong.

Closes #6753
2016-02-02 23:46:27 +00:00
f56df65d48 perf(dart/transform): Only process deferred libs when necessary
Previously, every .dart file in a package was processed to ensure proper
initialization of deferred loaded libraries.

Update the transformer to avoid processing libraries which we know do
not import any deferred libraries.

Closes #6745
2016-02-02 23:06:36 +00:00
3a40cd79f0 build(router): make the build.js script portable to g3 2016-02-02 13:58:51 -08:00
6acc99729c build(router): refactor angular1 router build script 2016-02-02 13:58:51 -08:00
99e6500a2d feat(upgrade): support bindToController with binding definitions
Since angular 1.4 we can also pass controller bindings directly to bindToController, making this syntax more convenient

Closes #4784
2016-02-02 13:27:22 -08:00
5c782d6ba8 Typo: Hash_consing wiki link wrong Markdown syntax 2016-02-02 11:53:30 -08:00
4e43d6f769 docs(http): Added base request options for test example 2016-02-02 11:51:42 -08:00
3529ee9973 docs(cheatsheet): change as to name in routing section 2016-02-02 11:43:29 -08:00
29aa6a6c1c change event to use camel case 2016-02-02 11:42:26 -08:00
7918f3c1fc docs(changelog): fix header for 2.0.0-beta.0 2016-02-02 11:39:23 -08:00
2f4e176054 docs(developer): add linting instructions 2016-02-02 11:34:00 -08:00
d4565fdaf3 Update CHANGELOG.md
Fixed phrasing on breaking changes. It's just one breaking change so just requires one bullet point to explain the before/after.
2016-02-02 11:24:35 -08:00
2a302aa73a fix(docs): rxjs/add/operators/map -> rxjs/add/operator/map (no 's').
Was it with 's' before?
2016-02-02 11:22:10 -08:00
31b819e9c2 test: fix transformer tests 2016-02-02 10:21:40 -08:00
27daeaff5e fix(karma): fix running karma via gulp
As described below, the karma server showdown process can crash, if the done() function, provided
by gulp is referenced directly instead of wrapped in a closure function
http://stackoverflow.com/questions/26614738/issue-running-karma-task-from-gulp

Reformat the gulpfile.js

Squashing the two commits
2016-02-02 06:22:53 -08:00
3e9b532409 fix(dart/transform): Handle edge cases in ReflectionRemover
Handle some cases which would previously result in broken code.

- Importing bootstrap.dart deferred
- Using combinators when importing bootstrap.dart
- Importing bootstrap.dart with a prefix

Closes #6749
2016-02-01 15:17:44 -08:00
c5aa6d17ef docs: Fix small formatting issue in changeling
Closes #6660
2016-02-01 15:16:35 -08:00
e480b0798e docs: Kebab-case does not work. Change to camelCase.
Closes #6630
2016-02-01 15:15:46 -08:00
8a645d5e44 chore(zone.js): update to 0.5.11
Closes #6751
2016-02-01 21:53:42 +00:00
321193889f fix(zone): correct incorrect calls to zone 2016-02-01 21:53:42 +00:00
566d3ede04 test(dart/transform): Update unit tests to expect code in <file>.template.dart
Closes #6711
2016-02-01 21:21:38 +00:00
8c36aa866a feat(dart/transform): Generate all code into <file>.template.dart
Previously, we generated the code to initialize the reflector into the
<file>.ng_deps.dart and the compiled template and change detector code
into <file>.template.dart.

Update the transformer to generate all code into <file>.template.dart to
avoid the additional HTTP requests necessary when debugging
applications in Dartium.
2016-02-01 21:21:37 +00:00
ed2dbf2db7 ci(dart): comment out dart.dev build
See #6823
2016-02-01 12:53:27 -08:00
36a0e04604 fix(circle): pre-dependencies npm install npm
Fixes #6777
2016-02-01 11:26:25 -08:00
8867afdaab fix(build): Revert "build(dart): Make Dart dev build required"
This reverts commit a199772508.
2016-02-01 11:17:57 -08:00
a199772508 build(dart): Make Dart dev build required
Previously, we allowed the Dart dev build to fail presubmit tests.
Make it a required build from now on.

Closes #6410
2016-02-01 07:12:40 -08:00
b008f542fa chore(changelog): improve breaking change description for beta.2 2016-01-30 19:45:17 -08:00
a78dcfa5f3 chore(tests): fix broken linker integration test and fix DebugNode export
Fixes two small issues introduced with pr #6555
2016-01-29 14:29:49 -08:00
e1bf3d33f8 feat(debug): replace DebugElement with new Debug DOM
Now, using `ng.probe(element)` in the browser console returns
a DebugElement when in dev mode.

`ComponentFixture#debugElement` also returns a new DebugElement.

Breaking Change:

This is a breaking change for unit tests. The API for the DebugElement
has changed. Now, there is a DebugElement or DebugNode for every node
in the DOM, not only nodes with an ElementRef. `componentViewChildren` is
removed, and `childNodes` is a list of ElementNodes corresponding to every
child in the DOM. `query` no longer takes a scope parameter, since
the entire rendered DOM is included in the `childNodes`.

Before:

```
componentFixture.debugElement.componentViewChildren[0];
```

After
```
// Depending on the DOM structure of your component, the
// index may have changed or the first component child
// may be a sub-child.
componentFixture.debugElement.children[0];
```

Before:

```
debugElement.query(By.css('div'), Scope.all());
```

After:

```
debugElement.query(By.css('div'));
```

Before:

```
componentFixture.debugElement.elementRef;
```

After:

```
componentFixture.elementRef;
```
2016-01-29 11:28:10 -08:00
ae7d2ab515 fix(bundle): add angular2/platform/testing/browser to SystemJS testing bundle 2016-01-29 13:58:06 +01:00
c6adbf602c fix(query): don’t cross component boundaries
Closes #6759
2016-01-28 23:38:40 +00:00
1f7a41c963 fix(query): update view queries that query directives in embedded views
Fixes #6747
2016-01-28 14:40:53 -08:00
f4f614f3a9 docs(changelog): update change log to beta.2 2016-01-28 12:01:18 -08:00
94139c351f chore(release): bump version to beta.2 2016-01-28 12:01:18 -08:00
fc5b128b43 chore(ci): deflake test and turn on saucelabs_required
Fixes #6725

Closes #6733
2016-01-28 03:18:08 +00:00
68a799af2e tools: implement public api spec
Closes #6309
2016-01-27 21:19:05 +00:00
16d9c60a0e chore(circleci): use a github token when running tsd
Also increase the heap size limit as a workaround for
https://github.com/angular/angular/issues/5229

Fixes #6602
2016-01-27 13:16:57 -08:00
c0b5e7a672 chore(ci): turn off saucelabs_required
Reenable once #6723 fixed.
2016-01-27 11:52:32 -08:00
6932b29acb chore(ci): bump up the error count for dart DDC. 2016-01-27 11:19:56 -08:00
c2a38c05aa fix(WebWorkers): Add support for transitionend events.
Closes #6649
2016-01-26 21:09:01 -08:00
8bea667a0b feat(WebWorker): Add Router Support for WebWorker Apps
Closes #3563.
2016-01-26 21:07:12 -08:00
800c8f196f chore(ddc): make DDC build non-experimental 2016-01-26 21:04:34 -08:00
42231f5719 feat(change_detection): allow all legal programs in the dev mode
BEFORE:

The following would throw in the dev mode because `f` would return a new array when called by checkNoChanges.

@Component({
  template: `
    {{f()}}
  `
})
class A {
  f() { return [1]; }
}

AFTER:

The checkNoChanges function compares only primitives types for equality, and deeply compares iterables. Other objects cannot cause checkNoChanges to throw. This means that the dev mode would never fail given a legal program, but may allow some illegal programs.
2016-01-26 21:01:19 -08:00
db87baeb98 fix(ddc): router, compiler, web worker fixes for DDC
Also enable DDC checks across all non-web worker playground apps. We are
now down to 2 DDC errors across all of them. The remaining two need to be
fixed in package:analyzer, not in angular.

BREAKING CHANGE:

- there's a chance of breakage as router's Instruction constructor
  signature changed.

Closes #6693
2016-01-27 02:30:20 +00:00
c4c43f5a77 docs(contributing.md): add docs for "ci" commit type/scope 2016-01-26 14:55:42 -08:00
0ae77753f3 fix(core): always remove DOM listeners and stream subscriptions
This is needed to prevent memory leaks. The DOM
listeners don’t need to be removed for simple examples,
but a big internal app shows memory leaks because of them.

BREAKING CHANGE:
- `Renderer.listen` now has to return a function that
  removes the event listener.
2016-01-26 07:37:31 -08:00
5f0baaac73 fix(dart/transform): Ensure template codegen is completed sync
Previously, template codegen was done asynchronously, which could result
in reflector state being overwritten and leading to compile errors.

Update the codegen to run synchronously to ensure this does not happen.

Closes #6603
2016-01-26 04:18:11 +00:00
b5b6ece65a chore(ddc): reduce DDC warning cap 260->180 as we fixed a bunch
Closes #6625
2016-01-26 03:58:22 +00:00
4282297c24 fix(ddc): type fixes necessary to bring DDC severe count to 0 2016-01-26 03:58:22 +00:00
9c96b8affc chore: track size of a "Hello world" app built with SystemJS
Closes #6621
2016-01-26 02:54:03 +00:00
132829e5e2 chore(core): deactivate the tests that use Dart isolates
These are broken with Dart 1.13.2 stable, and will soon be obsolete (see #6270).
2016-01-25 17:20:06 -08:00
4a414420e9 fix(bundles): testing bundle should include browser platform
Closes #6626
2016-01-22 06:12:58 +00:00
fb6335ab60 build(gulp): fail hard w/ legacy node version and provide clear upgrade instructions
Closes #6213
2016-01-22 03:25:34 +00:00
89bd008445 docs(DEVELOPER.md): update framework developer instructions 2016-01-22 03:25:34 +00:00
caafb41eb5 build(node): upgrade to node 5.4.1 2016-01-22 03:25:34 +00:00
31b81a7439 build(npm): update to karma-browserstack-launcher@0.1.9 2016-01-22 03:25:34 +00:00
f7b1973358 build(npm): bump Angular's version number in shrinkwrap files to 2.0.0-beta.1 2016-01-22 03:25:34 +00:00
32f01da49a build(npm): update to karma@0.13.17
Mark says that karma-runner/karma#1768 is resolved in 0.13.17
2016-01-22 03:25:34 +00:00
59684c97b0 build(npm): update to minimatch@3.0.0 2016-01-22 03:25:34 +00:00
a32a0a3a97 build(npm): update to semver@5.1.0 2016-01-22 03:25:33 +00:00
96f5b0929d build(npm): lock karma at 0.13.15 due to karma-runner/karma#1768 2016-01-22 03:25:33 +00:00
8e6cf7fca8 build(npm): update to yargs@3.31.0 2016-01-22 03:25:33 +00:00
fdbe8741c9 build(npm): update to proxy-middleware@0.15.0 2016-01-22 03:25:33 +00:00
775fb2c340 build(npm): remove googleapis
it was previously used by benchpress (see d02c0accbb) but that's no longer the case.

I also removed a bunch of extranous dependencies that should never have been part of node_modules (npm bug?)
2016-01-22 03:25:33 +00:00
b60f594798 build(npm): update to gulp-connect@2.3.1 2016-01-22 03:25:33 +00:00
cc49790bdb build(npm): update gulp-connect's dependencies 2016-01-22 03:25:33 +00:00
a4bc19c530 build(npm): lock broccoli-slow-trees to the 1.x.x range 2016-01-22 03:25:33 +00:00
f7985dbdb7 build(npm): update to lodash@3.10.1 2016-01-22 03:25:33 +00:00
0bdcb5c1e0 build(npm): remove del devDependency - use fs-extra instead 2016-01-22 03:25:33 +00:00
a0d25db4a5 build(npm): add tools/npm/reshrinkwrap script and update docs 2016-01-22 03:25:33 +00:00
625474c4e2 build(npm): update to mock-fs@3.6.0 2016-01-22 03:25:33 +00:00
1cd2a6328a build(npm): update to fs-extra@0.26.3 2016-01-22 03:25:33 +00:00
d6bafe4fe3 build(npm): update to minimist@1.2.0 2016-01-22 03:25:33 +00:00
6a2ef15355 build(npm): update to jasmine@2.4.1 2016-01-22 03:25:33 +00:00
a8ca560503 build(npm): upgrade to broccoli@0.16.9 2016-01-22 03:25:33 +00:00
ad361808ec build(npm): upgrade to broccoli-funnel@1.0.1 2016-01-22 03:25:33 +00:00
c47639f2b1 build(npm): upgrade to protractor@3.0.0 2016-01-22 03:25:33 +00:00
ba90a85f7b build(npm): downgrade to karma@0.13.15 due to RangeError bug
Ref https://github.com/karma-runner/karma/issues/1768
2016-01-22 03:25:33 +00:00
d3b569557f build(npm): upgrade to karma-sauce-launcher@0.3.0 2016-01-22 03:25:33 +00:00
c9090ffa31 build(npm): revert clang-format upgrade
there are too many reformatting changes require that would add noise to the upgrade commit
2016-01-22 03:25:33 +00:00
341bf39d23 build(npm): update all npm dependencies + reshrinkwrap 2016-01-22 03:25:32 +00:00
3778ac26aa build(tools): npm/copy-npm-shrinkwrap should gracefully handle situation when shrinkwrap file is missing
This situation occurs during mas update of all dependencies, so we should not throw errors when this happens.
2016-01-22 03:25:32 +00:00
6cfc6f5bb2 build(npm): upgrade to npm v3
Closes #3193
2016-01-22 03:25:32 +00:00
47a3b4d56b feat(dart/transform): Promote missing Directive warning to error
Closes #6519

Closes #6568
2016-01-22 00:46:56 +00:00
c72ed991ad fix(testing): remove test zone for now and rely on returned promises
Adds tests for public Dart and TS frameworks to make sure that
components with templateUrl can be created by the TestComponentBuilder.

Closes #6359

Closes #6601
2016-01-22 00:28:48 +00:00
78bfdf78ea feat(dart/transform): DirectiveProcessor: do not process generated files
Prevent `DirectiveProcessor` from processing files which were generated
by the Angular2 Dart transformer.

Closes #6517
2016-01-22 00:21:27 +00:00
a24ee6add4 fix(HtmlLexer): fix for unicode chars
fixes #6036
Closes #6061
2016-01-21 23:45:41 +00:00
df3074fdfe feat(core/application_ref): Allow asyncronous app initializers.
closes #5929.

Closes #6063
2016-01-21 01:45:24 +00:00
f7424d5aeb chore: track size of a "Hello world" app built with WebPack
Closes #6434
2016-01-21 01:28:35 +00:00
a593ffa6f3 fix(transformer): record HostBinding annotations applied to getters
Closes #6283
2016-01-21 01:02:56 +00:00
761c6d0df7 fix(perf): faster looseIdentical implementation
Remove String type check in looseIdentical in JS-mode. It is not necessary as dart2js already compiles `identical` to `===` which compares string contents. Inline call sites.

This improves change detection of plain fields by 40%. On a large internal app the improvement is 5%.

Closes #6364
2016-01-21 01:01:36 +00:00
3e65d1458e fix(Dart): make some playground samples run with Dart Dev Compiler
Resolve all invalid field override errors, workaround current
reflection limitations in Dart Dev Compiler. todo, hello_world and
key_events samples now work with Dart Dev Compiler.

BREAKING CHANGE: remove TemplateRef.elementRef setter

Closes #6441
2016-01-21 00:41:42 +00:00
a4b5cb8376 build(node): split test and src compilation units 2016-01-19 21:15:16 -08:00
c785a1e474 fix(ddc): use dynamic types in reflection typedefs
Closes #6437
2016-01-19 21:49:11 +00:00
3adc472f06 chore(build): fix race condition for the !bundles.js.docs task 2016-01-19 11:40:30 -08:00
e7081b8b7c chore: don't track size of non-bundle files 2016-01-19 11:32:40 -08:00
9b3a548f6f docs(template_parser.ts): typo 2016-01-19 10:58:04 -08:00
90b3502bb8 ci(circle config): add a circle CI config
This only runs the JS build (no tests) as an easy place to start.

Green build on my branch: https://circleci.com/gh/alexeagle/angular/5

Note, we are just experimenting with Circle at this point...

Closes #6520
2016-01-16 00:17:15 +00:00
e19b31db29 refactor(test): Remove unnecessary noSuchMethod
Remove trivial implementations in many spy objects which just calls the
parent's `noSuchMethod`.

Closes #6410

Closes #6491
2016-01-15 22:53:09 +00:00
bd015f14e8 build(dartanalyzer): Ignore TODOs during build
The newest version of the analyzer emits hints when it encounters TODOs
in code, which is breaking the Dart dev version of our build.

Ignore TODOs for the purpose of build health.

See #6410
2016-01-15 22:53:09 +00:00
ca7ba12fc6 chore(travis): update name of sync branch to be ignored
Closes #6518
2016-01-15 22:26:40 +00:00
ae05ec69c4 Update overview.md
Closes #6478
2016-01-15 17:44:30 +00:00
92dc3b91d8 doc(*): change package.json license field to MIT
Align the package.json license with the LICENSE file from the repo
Closes #6432
2016-01-15 17:42:43 +00:00
8bd697b316 docs(DEVELOPER): fix saucelabs gulp task name
Task is test.unit.js.sauce, not test.unit.js.saucelabs.

Closes #6435
2016-01-15 17:23:14 +00:00
eda4c3eb4c fix(template_compiler): Fix erroneous cycle detection
Before, the check for cycles was wrong and lead to false positives.

Fixes #6404

Closes #6474
2016-01-14 23:08:30 +00:00
4d0c2ed1f6 test(dart/transform): Update dependencies & fix Dart tests
Widen version dependencies for `package:angular`, `package:code_transformers`,
and `package:observe`.

`package:guinness` uses `package:unittest` while
the newest versions of `package:code_transformers` use `package:test`.
This causes our end-to-end Dart transformer tests (which use testing
code in `package:code_transformers`) to be skipped.

To fix this:
- Move e2e tests to run in a separate file
- Run `gulp test.server.dart` tests serially

Closes #5922

Closes #5935
2016-01-14 00:29:03 +00:00
eda6a5d52a refactor(WebWorker): Rename WORKER_RENDER_APP to WORKER_RENDER_APPLICATION
BREAKING CHANGE

WORKER_RENDER_APP is now deprecated. Use WORKER_RENDER_APPLICATION instead
WORKER_RENDER_APP_COMMON has been replaced by WORKER_RENDER_APPLICATION_COMMON

closes #6184

Closes #6378
2016-01-14 00:07:13 +00:00
c1c54ed0f2 refactor(dart/transform): Avoid using package:code_transformers
Replace uses of `package:code_transformers`, which is only used to
convert from uri to `AssetId`, with calls to the utility methods in
`src/transform/common/url_resolver.dart`.

Closes #5931
2016-01-13 22:24:42 +00:00
6b73d09ba1 chore(build): make experimental Dart build useful
Previously we grepped all hand-written Dart code and ran analyzer in strong mode against it.

Now we run it against transformed playground apps, which:

1. does not analyze unnecessary code (we primarily care about stuff that runs in the browser)
2. analyzes generated code, which does run in the browser and which we failed to analyze in the previous version of the build

Closes #6436
2016-01-13 21:09:55 +00:00
ac85cbb28a fix(web_workers): support @AngularEntrypoint in web workers
And enable transformers on all playground apps

Closes #6013
2016-01-13 17:55:01 +00:00
b0cebdba6b feat(test): allow tests to specify the platform and application providers used
With providers split into bundles, the test injector is now able to
use providers for a given bundle. Suggested provider lists for tests are
available in `angular2/platform/testing/<platform>`.

Change the providers for a test suite using `setBaseTestProviders`. This
should be done once at the start of the test suite, before any test cases
run.

BREAKING CHANGE: Tests are now required to use `setBaseTestProviders`
to set up. Assuming your tests are run on a browser, setup would change
as follows.

Before:

```js
// Somewhere in test setup
import {BrowserDomAdapter} from 'angular2/src/platform/browser/browser_adapter';
BrowserDomAdapter.makeCurrent
```

After:

```js
// Somewhere in the test setup
import {setBaseTestProviders} from 'angular2/testing';
import {
  TEST_BROWSER_PLATFORM_PROVIDERS,
  TEST_BROWSER_APPLICATION_PROVIDERS
} from 'angular2/platform/testing/browser';

setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS,
                     TEST_BROWSER_APPLICATION_PROVIDERS);
```

Closes #5351, Closes #5585

Closes #5975
2016-01-13 02:11:06 +00:00
933a9112da fix(ChangeDetection): chain expressions evaluate to the last expression (codegen)
fixes #4782
Closes #5892
2016-01-12 17:10:42 +00:00
8c37b7e8f2 fix(directive): throw if output the same event more than once
Close: #4798
2016-01-11 16:48:57 -08:00
c8e909f8c9 docs(cheatsheet): fix pipe name in an example
Closes #6399
2016-01-12 00:12:00 +00:00
69ae3634c7 feat(testability): Expose function frameworkStabilizers
Closes #5485
2016-01-11 23:10:51 +00:00
95248f46a1 build(npm): update to ts2dart@0.7.19
Closes #6254
2016-01-09 01:44:01 +00:00
b3c7df1783 docs(cheatsheet): fix bootstrap ts namespace
Fix https://github.com/angular/angular.io/issues/615
Closes #6159
2016-01-09 01:01:17 +00:00
c56679e8e1 Update change from Apache to MIT license 2016-01-08 13:41:58 -08:00
041c599511 docs(changelog): update change log to beta.1 2016-01-08 12:12:38 -08:00
6343f71be5 chore(release): 2.0.0-beta.1 - catamorphic-involution 2016-01-08 11:56:37 -08:00
89f32f808f perf(dart/transform): Avoid unnecessary reads for files with no view
In the `TemplateCompiler` phase, avoid reading in the `.ng_meta.json` files of
imported libraries when we can determine that the file we are processing
does not define any `View`s.

Closes #6183
2016-01-06 08:56:39 -08:00
7ae23adaff feat(core): speed up view creation via code gen for view factories.
BREAKING CHANGE:
- Platform pipes can only contain types and arrays of types,
  but no bindings any more.
- When using transformers, platform pipes need to be specified explicitly
  in the pubspec.yaml via the new config option
  `platform_pipes`.
- `Compiler.compileInHost` now returns a `HostViewFactoryRef`
- Component view is not yet created when component constructor is called.
  -> use `onInit` lifecycle callback to access the view of a component
- `ViewRef#setLocal` has been moved to new type `EmbeddedViewRef`
- `internalView` is gone, use `EmbeddedViewRef.rootNodes` to access
  the root nodes of an embedded view
- `renderer.setElementProperty`, `..setElementStyle`, `..setElementAttribute` now
  take a native element instead of an ElementRef
- `Renderer` interface now operates on plain native nodes,
  instead of `RenderElementRef`s or `RenderViewRef`s

Closes #5993
2016-01-05 08:56:46 -08:00
a08f50badd chore(build): allow to run examples and benchmarks without bundles
The bundles will only be used if the flag `--useBundles` is passed to `gulp build.js`.
2016-01-05 08:27:24 -08:00
0b6e75a85e chore(ci): cleanup artifact upload
This is no longer needed for g3sync.

Closes #6232
2016-01-04 23:02:04 +00:00
4291758079 build(sauce/bs): make some browsers required in CI
Closes #5795
2016-01-04 22:30:48 +00:00
b44d36cf95 fix(forms): fix SelectControlValueAccessor not to call onChange twice
Closes #5969
2016-01-04 20:33:13 +00:00
a038bb9ae3 fix(router): preserve specificity for redirects
Previously when comparing which of multiple possible routes to choose in
an ambiguous case, we looked at the specificity of the target of redirect
matches rather than the original match. This meant that if a redirect
used a whilecard, but redirected to a target that was a static path,
we'd cound the static path's specificity instead of the wildcard.

This change stores the specificity of the redirect on the RedirectInstruction.

Closes #5933
2016-01-04 20:06:21 +00:00
9d28147acb fix(benchpress): fix flake
memory was not allocated to be high enough, resulting in partial results to be
clipped, and therefore failing the assertions

Closes #6161
2016-01-04 19:25:32 +00:00
d116861c8e fix(CHANGELOG): typo
fixes #6075
Closes #6078
2015-12-28 17:14:10 +00:00
9a70f1a1d9 fix(TemplateParser): do not match on attrs that are bindings
Closes #5914
2015-12-24 14:44:16 +00:00
8516473340 build(broccoli-typescript): check for map files before deleting them
fixes #5610
Closes #6065
2015-12-23 02:59:11 +00:00
cab69f689f docs(cheatsheet): fix typo in <template> syntax description
Closes #6051
2015-12-23 02:57:47 +00:00
822e83ebb0 chore(docs): update the merge process docs
use caretaker rather than "on-duty"

Closes #6058
2015-12-23 02:32:02 +00:00
b2bc50dbd1 fix(router): correctly sort route matches with children by specificity
This changes the way we calculate specificity. Instead of using a number,
we use a string, so that combining specificity across parent-child instructions
becomes a matter of concatenating them

Fixes #5848

Closes #6011
2015-12-21 10:38:13 +00:00
e748adda2e refactor(testing): move common testing logic into test_injector
Before, all test framework wrappers (internal for dart and js/ts,
angular2_test for dart and testing for js/ts) had similar logic to
keep track of current global test injector and test provider list.
This change wraps that logic into one class managed by the test
injector.

Closes #5920
2015-12-18 08:23:29 +00:00
630d93150a fix(core): IE only supports parentNode
Closes #5994
2015-12-18 01:48:09 +00:00
76f1f9f1e3 chore(build): tighten up code size check now that regression is fixed
Our code size SLA is 100kb gzipped and 300kb minified. Our target is 10kb gzipped.

We are currently under 90kb gzipped. Let's keep it that way while looking for ways to improve the situation further. We're not <300kb minified yet, so we should be stricter here too.

Closes #5896
2015-12-18 01:06:25 +00:00
c47d85b038 fix(code size): revert previous devMode change to restore size targets
This commit reverts a8d9dbf that introduced a code size regression (16kb gzipped, 63kb minified) in Dart.

Effect on the hello world app:

gzipped: 105kb -> 89kb
minified: 370kb -> 317kb

BREAKING CHANGE:
- This is very unlikely to be breaking, but I'm still marking just in case. The only change to the user should be that dev mode is driven by Dart's checked mode, like it was in the past.
2015-12-18 01:06:25 +00:00
197cf09689 feat(core): improve NoAnnotationError message
Closes #4866

Closes #5927
2015-12-17 23:37:54 +00:00
e67ebb7f70 feat(core): improve stringify for dart to handle closures 2015-12-17 23:37:54 +00:00
3524946581 fix(docs): fix an import in TOOLS_DART.md
Closes #5923
2015-12-17 23:30:44 +00:00
9276dad42c docs: fix some typos in comments and strings
Couple of typos fixed:
- occuring -> occurring
- imlement -> implement
- idenitifer -> identifer
etc...

Closes #5943
2015-12-17 22:57:43 +00:00
2a2f9a9a19 feat(router): support links with just auxiliary routes
Closes #5930
2015-12-16 19:50:19 +00:00
909e70bd61 Update README.md 2015-12-15 12:38:48 -08:00
8ac9719832 Update README.md 2015-12-15 12:38:13 -08:00
3eff7c6f59 docs(changelog): fix typo in "somnambulant" 2015-12-15 11:58:20 -08:00
17fbbfba91 docs(readme): remove angular 1 js & dart links
they are confusing now that we are in beta.
2015-12-15 11:36:07 -08:00
b232dded77 chore(readme): update README: no longer alpha 2015-12-15 11:25:14 -08:00
f50affaf9c chore(release): cut 2.0.0-beta.0 - sonambulent-inauguration 2015-12-15 10:54:10 -08:00
463754bf16 docs(changelog): release notes for 2.0.0-beta.0 sonambulent-inauguration 2015-12-15 10:54:10 -08:00
a45b27e7f9 chore(release): cut 2.0.0-alpha.54 2015-12-15 09:57:05 -08:00
af3ea16acb docs(changelog): add release notes for alpha.55 2015-12-15 09:57:05 -08:00
fc75220d63 fix(router): export ROUTER_LINK_DSL_PROVIDER and hide MockPopStateEvent 2015-12-15 09:45:00 -08:00
00822c3415 chore(publish): add Rx bundles to code.angularjs.org publish step
Closes #5904
Closes #5909
2015-12-15 17:12:42 +00:00
3dca9d522a feat(core): enable dev mode by default
BREAKING CHANGE

Before

Previously Angular would run in dev prod mode by default, and you could enable the dev mode by calling enableDevMode.

After

Now, Angular runs in the dev mode by default, and you can enable the prod mode by calling enableProdMode.
2015-12-15 08:34:44 -08:00
de996ec50b build(publish.sh): uncomment prepare steps for existing tmp repo
I tested these steps manually and they seem to work well.
2015-12-15 03:31:47 -08:00
059e09c3be chore(release): cut alpha.54 - rxjs bundle separation 2015-12-15 03:04:28 -08:00
d5e4686e7e docs(changelog): add alpha.54 release notes 2015-12-15 03:04:28 -08:00
d55655f5a3 fix(bundles): rename the testing.js bundle
BREAKING CHANGE:

System.register testing bundle was renamed:
`testing.js` -> `testing.dev.js`

Closes #5899
Closes #5776
2015-12-15 02:52:25 -08:00
61b9468596 fix(bundles): rename UMD bundles
BREAKING CHANGE:

UMD bundles were renamed:
* `angular2.umd.js` -> `angular2-all.umd.js`
* `angular2-testing.umd.js` -> `angular2-all-testing.umd.js`

Closes #5898
2015-12-15 10:24:32 +00:00
c6f52e3282 docs(cheatsheet): fix the ES5 snippets for services 2015-12-15 01:27:19 -08:00
42ccff859c build(gulp): remove obsolete insertRXLicense bundle transform 2015-12-15 01:11:10 -08:00
29600c0c87 docs(bundles): update RxJS info in bundles/overview.md post-#5893 2015-12-15 01:07:16 -08:00
5b63b6764f fix(docs,benchmarks): remove invalid </input> closing tags
Closing #5752
2015-12-15 00:45:31 -08:00
2835265916 docs(cheatsheet) adding JS specific syntax to cheatsheet
Closes #5861
2015-12-14 23:19:12 -08:00
e950dd6a2a refactor(bundles): make rxjs an external dependency in umd bundle
Closes #5886
Closes #5893
2015-12-14 22:08:22 -08:00
321ed7d099 chore(package): update rxjs to beta.0 2015-12-14 22:08:16 -08:00
42b74f524a chore(bundles): use RxJS bundles 2015-12-14 22:08:16 -08:00
77b7caeceb fix(bundles): don't include RxJS in System.register bundles
BREAKING CHANGE:

RxJS used to be bundled with Angular 2 code and this is not the case
any more. RxJS needs to be loaded explicitly.
2015-12-14 22:08:16 -08:00
b803ecf7e7 refactor(testing): reenable injectAsync checking for return value
Before #5375, injectAsync would check the return value and fail
if it was not a promise, to help users remember that they need to
return a promise from an async test. #5375 removed that with the
introduction of the testing zone.

This un-deprecates `injectAsync` until we can resolve
https://github.com/angular/angular/issues/5515.

To be clear, this means that `inject` and `injectAsync` are now
identical except that `injectAsync` will fail if the test
does not return a promise, and `inject` will fail if the test
returns any value.

Closes #5721
2015-12-15 05:51:54 +00:00
d3a79db48d build(publish.sh): do not error when tmp/code.angularjs.org already exists
I'm not sure what's the best way to update the shallow repo and I'm in a state where there is nothing to be
updated so I'll revisit the proper fix the next time I'm doing a release unless someone beats me to it.

Closes #5872
2015-12-15 05:45:10 +00:00
e891baeea4 chore: remove unused decorator
Closes #5880
2015-12-15 05:20:35 +00:00
2aaef81b1b Revert "refactor(testing): move common testing logic into test_injector"
This reverts commit b88a6d983f.
2015-12-14 20:27:31 -08:00
3191fd1440 cleanup(linker): Remove vestigial ComponentUrlMapper.
Closes #5849
2015-12-15 03:04:49 +00:00
80a5e47e61 docs(*): Document a lot more symbols that are missing comments in our generated docs. 2015-12-15 03:04:48 +00:00
5a04ffec3e refactor(Directive): drop moduleId
moduleId is only used by components to resolve urls.
Directives have no templates and do not need moduleId.
Closes #5873
2015-12-15 01:20:56 +00:00
1c779d8b9e docs(bundles): document existing bundles and their usage
Closes #5777

Closes #5878
2015-12-15 01:18:44 +00:00
a79fe057f9 fix(changelog): fix rxjs operator import paths
Closes #5864
2015-12-15 01:15:57 +00:00
b88a6d983f refactor(testing): move common testing logic into test_injector
Before, all test framework wrappers (internal for dart and js/ts,
angular2_test for dart and testing for js/ts) had similar logic to
keep track of current global test injector and test provider list.
This change wraps that logic into one class managed by the test
injector.

Closes #5819
2015-12-15 01:14:48 +00:00
19396d14cc docs(contributing.md): improve submit issue instructions
Closes #5889
2015-12-15 00:45:29 +00:00
2983558e5e fix(bundles): remove polyfills from angular2.js bundle
BREAKING CHANGE:

Previously `angular2.js`, `angular2.min.js` and `angular2.dev.js` bundles
would have zone.js and reflect-metadata pre-appended. New bundles don't
contain zone.js nor reflect-metadata - those external dependencies can
be easily loaded into a browser using `angular2-polyfills.js`

Closes #5881
2015-12-14 21:34:56 +00:00
0f8e40bb42 chore(zone.js) : update to 0.5.10
Closes #5845
2015-12-14 21:23:18 +00:00
006a96dd20 refactor(WebWorker): Make WebWorker bootstrap synchronous
BREAKING CHANGE

From the app thread, in both TypeScript and Dart, you bootstrap the app
using `application` instead of `asyncApplication`.
Before:
```TypeScript
platform([WORKER_APP_PLATFORM])
.asyncApplication(setupWebWorker, optionalProviders?)
.then((ref) => ref.bootstrap(RootComponent));
```
Now:
```TypeScript
platform([WORKER_APP_PLATFORM])
.application([WORKER_APP_APPLICATION])
.bootstrap(RootComponent);
```

closes #5857

Closes #5862
2015-12-14 21:04:46 +00:00
4deaf0bdd3 chore(bundles): align content of System.register and UMD bundles
Closes #5856
2015-12-14 20:48:29 +00:00
9917d7f8af chore(bundles): properly clean the dist/build folder
The `dist/build` folder is created as part of the bundling
process but it was never cleaned up in the `clean` task.

Closes #5832
2015-12-14 20:48:19 +00:00
1607ef8782 refactor(HtmlLexer): process carriage returns in one pass
Closes #5867
2015-12-14 20:17:06 +00:00
539c5633bf chore(bundles): add http and router mocks to angular2-testing
Closes #5830
2015-12-14 19:04:03 +00:00
f83f4ace2d chore(changelog): fix formatting for alpha.53
Closes #5866
2015-12-14 18:34:51 +00:00
283962f810 fix(bundles): remove ngUpgrade from the angular2.js bundle
Closes #5739

BREAKING CHANGE:

`ngUpgrade` related symbols are no longer part of the `angular2.js`
bundle. `ngUpgrade` has a dedicated `upgrade.js` bundle now.

Closes #5854
2015-12-14 17:55:05 +00:00
892f9e19bc chore(release): cut alpha.53 - no more angular2/angular2 2015-12-12 17:59:35 -08:00
cacfb214b6 docs(changelog): changelog for alpha.53 2015-12-12 17:59:35 -08:00
4e5cd1e558 chore: update ts2dart to 0.7.18
Closes #5853
2015-12-12 19:28:13 +00:00
43f42d9c6e feat(facade): do not reexport Observable from angular2/core
BREAKING CHANGE

Before import {Observable} from 'angular2/core'

After import {Observable} from 'rxjs/Observable';
2015-12-12 19:28:13 +00:00
a885f37dfa fix(web_workers): remove unnecessary setup module and AppRootUrl
Since AppRootUrl is removed, the logic for extending and emitting
the root url as part of the setup seems unnecessary.

BREAKING CHANGES:

The setupWebWorker function exported from 
angular2/platform/worker_app  no longer returns a promise of providers, 
but instead synchronously returns providers.

Related to #5815
Closes #5820
2015-12-12 00:58:56 +00:00
ed2c25eb2f fix(compiler): remove AppRootUrl
Related to #5815

This should not break anything because AppRootUrl wasn't actually
being used by the compiler anymore.
2015-12-12 00:58:56 +00:00
b1b0593ddf docs(core): replace angular2/angular2 with the right barrel import.
Related to #5710
Closes #5847
2015-12-11 15:30:25 -08:00
200dc00dbb fix(angular2): remove angular2.ts module
Closes #5815
Closes #5844

BREAKING CHANGE:

`angular2/angular2` was removed. Use the correct import from one of the barrels. E.g. `angular2/core`, `angular2/platform/browser`,  `angular2/common`, …

Note: This only applies to JavaScript, Dart is not changed.
2015-12-11 14:21:33 -08:00
20c6eebb29 fix(angular2): don't export compiler bits as public API
Closes #5815
Closes #5797

BREAKING CHANGE:

The following symbols are not exported from angular2/angular2 any more:
`UrlResolver`, `AppRootUrl`, `getUrlScheme`, `DEFAULT_PACKAGE_URL_PROVIDER`.
Use imports from `angular2/compiler` instead.
2015-12-11 14:04:01 -08:00
8c69497d8e fix(bundles): don't use angular2/angular2 in config of System.register bundles
Related #5710
2015-12-11 14:04:01 -08:00
44c648fc04 Revert "fix(animate): ensure transition properties are removed once the animation is over"
This reverts commit b8e69a21a9.
2015-12-11 13:13:11 -08:00
979162d324 fix(public_spec): check exports of barrels instead of angular2/angular2
This changes the public api spec to check each public barrel individually
to make sure its API has not changed. The previous API spec has been
preserved but split into respective barrels.

The compiler barrel has been added to the spec, along with all of its
public exports. Previously, angular2/angular2 was only exporting a
handful of symbols from compiler, so there are now many more symbols
being tested in the spec for compiler than previously.

Part of #5710
Closes #5841
Supercedes #5821
2015-12-11 13:05:52 -08:00
2934b82113 chore(tools): remove unused performance import
Closes #5840
2015-12-11 20:32:17 +00:00
92ddc62bed fix(styles): Escape \r characters in compiled text
Closes #5772

Closes #5835
2015-12-11 19:48:43 +00:00
0cb32c2fef feat(Headers): implement toJSON 2015-12-11 19:40:56 +00:00
2ca5e38a78 fix(upgrade): allow directives with empty template 2015-12-11 11:39:45 -08:00
b8e69a21a9 fix(animate): ensure transition properties are removed once the animation is over 2015-12-11 11:38:24 -08:00
3fd898e91f docs(cheatsheet): copyedit
Fixed a few little things. I'll probably have more changes to make later, once I understand everything better.

Also added a missing syntax line.

Closes #5806
2015-12-11 18:41:57 +00:00
a66cc50168 refactor(testing): limit imports of barrel-private APIs
Closes #5603
2015-12-11 18:39:56 +00:00
eb296756fb refactor(benchmarks): remove imports from 'angular2/angular2'
Closes #5799
2015-12-11 18:33:03 +00:00
f1a9a537cb test(core): remove imports from 'angular2/angular2'
Closes #5829
2015-12-11 18:02:23 +00:00
080469f8e6 fix(HtmlParser): allow ng-content elements regardless the namespace
relates to #5547
Closes #5745
2015-12-11 01:36:48 +00:00
7c13372721 fix(TemplateParser): match element and attributes regardless the namespace 2015-12-11 01:36:48 +00:00
778677ba75 docs(core): Myriad of documentation changes including lots of new example code. 2015-12-10 15:23:57 -08:00
f0d876a873 chore(tests): disable flaky firefox test
Tracking issue is #5611
Closes #5817
2015-12-10 22:54:26 +00:00
e9e2a4152e docs: fix variable name, change to camelCase
closes #5801
2015-12-10 14:35:28 -08:00
398f024b24 fix(async): support BehaviorSubjects in async pipe 2015-12-10 21:49:40 +00:00
4a17e6906c fix(async): improve Rx support in ObservableWrapper 2015-12-10 21:49:40 +00:00
8d3e5596dc refactor(playground): remove imports from 'angular2/angular2'
Part of #5710

Closes #5798
2015-12-10 21:46:51 +00:00
df6d2d1e23 refactor(examples): remove imports from 'angular2/angular2'
Closes #5803
2015-12-10 21:45:58 +00:00
d26c338aa0 refactor(material): remove imports from 'angular2/angular2'
Closes #5800
2015-12-10 21:19:38 +00:00
edcb34dc9f fix(dom_renderer): moveNodeAfterSiblings should not detach the reference node
Fixes #5077
Closes #5759
2015-12-10 20:14:27 +00:00
693d9dce5d fix(parse5): support comment nodes with getText and setText
In the browser, calling element.textContent causes child comment
nodes to be ignored, while getting textContent directly on a
comment node will return the comment. This change makes
parse5Adapter consistent with this behavior by adding a 2nd
argument to getText telling if it's being called recursively.

Closes #5805
2015-12-10 19:18:14 +00:00
194dc7da78 feat(renderer): use a comment instead of an element when stamping out template>` elements
Originally authored by @tbosch, this reverts the revert commit
e274ff8a69.

Closes #4805
2015-12-10 19:18:14 +00:00
79399e1c51 feat(dom_renderer): add setBindingDebugInfo method
This is used for setting property binding values as attributes
on elements when running in dev mode. This implementation will
also serialize binding information to template placeholder
comment nodes.

Closes #5227
2015-12-10 19:18:14 +00:00
fe1dd77d94 feat(benchpress): add receivedData + requestCount to PerflogMetric
Closes #5750
2015-12-10 18:51:47 +00:00
24dcd267b8 refactor(gulpfile.js): cleanup obsolete file reference
Closes #5738
2015-12-10 18:16:50 +00:00
cf3ce171a5 docs(kebab-case.md): more fixes and CSS migration instructions
Closes #5773
2015-12-10 04:18:17 -08:00
06d076a6f2 docs(kebab-case): fix typo on property
Closes #5783
2015-12-10 03:42:43 -08:00
3190c5941a fix(changelog): fix ngFor on template
Closes #5785
2015-12-10 03:41:00 -08:00
30e25acb9f fix(core): workaround for typescript@1.7.3 breakage #5784
I don't understand why I need to declare the type-here, but it resolves the issue.

Looks like a bug in tsc.

Fixes #5784
2015-12-10 03:30:16 -08:00
4975cb92ae docs(changelog): add link back to A2 package.json
Closes #5779
2015-12-10 02:28:41 -08:00
c8d6ad2718 chore(release): cut alpha.52 - the new beginning 2015-12-10 00:48:32 -08:00
cde6726e25 docs(changelog): add changelog for alpha.52 2015-12-10 00:48:32 -08:00
b3d10af89a docs(kebab-case.md): fix indentation, add links and other small changes 2015-12-10 00:48:32 -08:00
4724cc664e docs(kebab-case.md): add link to the design doc 2015-12-10 00:18:08 -08:00
4e16feaf72 docs(changelog): add breaking change note about peerDependencies
Closes #5747
2015-12-09 22:10:12 -08:00
9e44dd85ad feat(camelCase Angular): legacy template transformer 2015-12-09 19:59:40 -08:00
da9b46a071 feat: camelCase Angular (kebab-case removal)
BREAKING CHANGE:

Angular is now fully camel case.

Before:

    <p *ng-if="cond">
    <my-cmp [my-prop]="exp">
    <my-cmp (my-event)="action()">
    <my-cmp [(my-prop)]="prop">
    <input #my-input>
    <template ng-for #my-item [ng-for-of]=items #my-index="index">

After

    <p *ngIf="cond">
    <my-cmp [myProp]="exp">
    <my-cmp (myEvent)="action()">
    <my-cmp [(myProp)]="prop">
    <input #myInput>`,
    <template ngFor="#my-item" [ngForOf]=items #myIndex="index">

The full details are found in [angular2/docs/migration/kebab-case.md](https://github.com/angular/angular/blob/master/modules/angular2/docs/migration/kebab-case.md)
2015-12-09 19:59:40 -08:00
b386d1134a doc(camelCase Angular): migration guide 2015-12-09 19:59:40 -08:00
1e740581ee build(npm_publish.sh): run gulp via node --max-old-space-size=1900 to workaround #5229 2015-12-09 19:51:10 -08:00
f1741b10f2 docs(changelog): release notes for 2.0.0-alpha.51 2015-12-09 19:28:52 -08:00
7bce1477ef chore(release): cut alpha.52 - the last release of Angular as we know it 2015-12-09 19:20:20 -08:00
01ba94ba56 build(npm): update to ts2dart@0.7.17
resolves regression in 0.7.16

Closes #5758
2015-12-10 01:32:45 +00:00
51cb7586e0 build(npm): update to typescript@1.7.3 + fix broccoli-typescript + fix src 2015-12-10 01:32:44 +00:00
796eee1e6f build(npm): update to gulp-typescript@2.10.0 2015-12-10 01:32:44 +00:00
c39828f0f2 build(npm): bump ts2dart to 0.7.16 2015-12-10 01:32:44 +00:00
28860d35b2 feat(core): provide support for relative assets for components
Assets defined for `templateUrl` and `styleUrls` can now be loaded
in relative to where the component file is placed so long as the
`moduleId` is set within the component annotation.

Closes #5634
2015-12-09 16:28:49 -08:00
5f0ce30ee6 revert: feat(core): provide support for relative assets for components 2015-12-09 16:26:42 -08:00
f4d937ad8d docs(cheatsheet): add Dart-specific syntax & headings
Closes #5756
2015-12-09 23:05:23 +00:00
db096a5e22 feat(core): provide support for relative assets for components
Assets defined for `templateUrl` and `styleUrls` can now be loaded
in relative to where the component file is placed so long as the
`moduleId` is set within the component annotation.

Closes #5634

Closes #5634
2015-12-09 22:04:00 +00:00
bf484b19b3 chore(changelog): fix formatting for alpha.49
Closes #5732
2015-12-09 21:30:30 +00:00
56a254e6a5 chore: enforce import checks for the 'upgrade' barrel
Closes #5741
2015-12-09 21:04:41 +00:00
793098bcce refactor(upgrade): remove imports from angular2/angular2
Related #5739
2015-12-09 21:04:41 +00:00
d6d759d722 feat(bundles): add angular-testing UMD bundle
Closes #5581

Closes #5734
2015-12-09 19:36:18 +00:00
61e8b60506 docs(Observable): add documentation for Observable and operators
Closes #5642
Closes #5684
2015-12-09 19:32:30 +00:00
2f0744b089 docs(cheatsheet): update to new syntax
See https://github.com/angular/angular.io/pull/459

Closes #5733
2015-12-09 19:04:08 +00:00
ca73852746 docs(AngularEntrypoint): add missing backticks 2015-12-09 19:04:08 +00:00
72444c40a7 typo fix: registerPrimaryOutlet description
Closes #5648
2015-12-08 19:55:35 -08:00
214148d58a chore(release): update package.json and changelog to alpha.50 2015-12-08 19:07:43 -08:00
cc8f1f9552 feat(testing): package angular2_testing to prepare it for publishing
Closes #5682
2015-12-09 03:01:21 +00:00
cbf788869d fix(http): use any for res.json() return
fixes #5636

Closes #5646
2015-12-09 03:00:22 +00:00
c1ae49d91e fix(testing): remove Symbol dummy shim
Closes #5067

Closes #5719
2015-12-09 02:57:19 +00:00
4432cf5438 chore(package): update rxjs dependency to alpha.14
Closes #5722

Closes #5723
2015-12-08 18:54:43 -08:00
869a392357 fix(package) add missing comma in ngHttp package.json
Closes #5727
2015-12-08 18:51:19 -08:00
1808 changed files with 86644 additions and 88357 deletions

16
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,16 @@
**IMPORTANT**: This repository's issues are reserved for feature requests and bug reports. Do not submit support requests here, see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question.
**Steps to reproduce and a minimal demo of the problem**
_Use https://plnkr.co or similar -- try this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5_
_What steps should we try in your demo to see the problem?_
**Current behavior**
**Expected/desired behavior**
**Other information**

24
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,24 @@
* **Please check if the PR fulfills these requirements**
- [ ] The commit message follows our guidelines: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit-message-format
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
* **What kind of change does this PR introduce?** (Bug fix, feature, docs update, ...)
* **What is the current behavior?** (You can also link to an open issue here)
* **What is the new behavior (if this is a feature change)?**
* **Does this PR introduce a breaking change?** (What changes might users need to make in their application due to this PR?)
* **Other information**:

9
.gitignore vendored
View File

@ -21,7 +21,13 @@ tmp
*.js.deps
*.js.map
# Files created by the template compiler
**/*.ngfactory.ts
**/*.css.ts
**/*.css.shim.ts
# Or type definitions we mirror from github
# (NB: these lines are removed in publish-build-artifacts.sh)
**/typings/**/*.d.ts
**/typings/tsd.cached.json
@ -48,3 +54,6 @@ npm-debug.log
# built dart payload tests
/modules_dart/payload/**/build
# rollup-test output
/modules/rollup-test/dist/

2
.nvmrc
View File

@ -1 +1 @@
4.2.1
5.4.1

View File

@ -1,132 +1,192 @@
language: node_js
sudo: false
node_js:
- '4.2.1'
- '5.4.1'
addons:
# firefox: "38.0"
apt:
sources:
# needed to install g++ that is used by npms's native modules
- ubuntu-toolchain-r-test
packages:
- g++-4.8
branches:
except:
- g3sync
- g3_v2_0
cache:
directories:
- node_modules
- $HOME/.pub-cache
- ./node_modules
- ./.chrome/chromium
# - $HOME/.pub-cache
#before_cache:
# # Undo the pollution of the typescript_next build before the cache is primed for future use
# - if [[ "$MODE" == "typescript_next" ]]; then npm install typescript; fi
env:
global:
- KARMA_BROWSERS=DartiumWithWebPlatform
- E2E_BROWSERS=Dartium
- LOGS_DIR=/tmp/angular-build/logs
- SAUCE_USERNAME=angular-ci
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
- BROWSER_STACK_USERNAME=angularteam1
- BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
- ARCH=linux-x64
- DART_DEV_VERSION=latest
- DART_STABLE_VERSION=latest
# Token for tsd to increase github rate limit
# See https://github.com/DefinitelyTyped/tsd#tsdrc
# This does not use http://docs.travis-ci.com/user/environment-variables/#Secure-Variables
# because those are not visible for pull requests, and those should also be reliable.
# This SSO token belongs to github account angular-github-ratelimit-token which has no access
# (password is in Valentine)
- TSDRC='{"token":"ef474500309daea53d5991b3079159a29520a40b"}'
# GITHUB_TOKEN_ANGULAR
- secure: "fq/U7VDMWO8O8SnAQkdbkoSe2X92PVqg4d044HmRYVmcf6YbO48+xeGJ8yOk0pCBwl3ISO4Q2ot0x546kxfiYBuHkZetlngZxZCtQiFT9kyId8ZKcYdXaIW9OVdw3Gh3tQyUwDucfkVhqcs52D6NZjyE2aWZ4/d1V4kWRO/LMgo="
# - KARMA_JS_BROWSERS=ChromeNoSandbox
# - E2E_BROWSERS=ChromeOnTravis
# - LOGS_DIR=/tmp/angular-build/logs
# - ARCH=linux-x64
matrix:
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
- MODE=dart DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
- MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=browserstack DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=js DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=router DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=build_only DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
- MODE=lint DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
- MODE=payload DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
- CI_MODE=js
- CI_MODE=lint
- CI_MODE=e2e
- CI_MODE=saucelabs_required
- CI_MODE=browserstack_required
matrix:
allow_failures:
- env: "MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
- env: "MODE=browserstack DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
- env: "MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
# TODO(alxhub): remove when dartdoc #1039 is in dev channel
- env: "MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
#matrix:
# allow_failures:
# - env: "MODE=saucelabs_optional"
# - env: "MODE=browserstack_optional"
addons:
firefox: "38.0"
before_install:
- node tools/analytics/build-analytics start ci job
- node tools/analytics/build-analytics start ci before_install
- echo ${TSDRC} > .tsdrc
- export DISPLAY=:99.0
- export GIT_SHA=$(git rev-parse HEAD)
- ./scripts/ci/init_android.sh
- ./scripts/ci/install_dart.sh ${DART_CHANNEL} ${DART_VERSION} ${ARCH}
- sh -e /etc/init.d/xvfb start
- if [[ -e SKIP_TRAVIS_TESTS ]]; then { cat SKIP_TRAVIS_TESTS ; exit 0; } fi
- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_BRANCH}" = "master" ] && SAUCE_USERNAME="angular2-ci" && SAUCE_ACCESS_KEY="693ebc16208a-0b5b-1614-8d66-a2662f4e" || true'
- node tools/analytics/build-analytics success ci before_install
install:
- node tools/analytics/build-analytics start ci install
# Check the size of caches
- du -sh ./node_modules || true
# Install npm dependecies
- npm install
- node tools/analytics/build-analytics success ci install
- ./scripts/ci-lite/install.sh
before_script:
- node tools/analytics/build-analytics start ci before_script
- mkdir -p $LOGS_DIR
- ./scripts/ci/presubmit-queue-setup.sh
- node tools/analytics/build-analytics success ci before_script
script:
- node tools/analytics/build-analytics start ci script
- ./scripts/ci/build_and_test.sh ${MODE}
- node tools/analytics/build-analytics success ci script
- ./scripts/ci-lite/build.sh && ./scripts/ci-lite/test.sh
after_script:
- node tools/analytics/build-analytics start ci after_script
- ./scripts/ci/print-logs.sh
- ./scripts/ci/after-script.sh
- ./scripts/publish/publish-build-artifacts.sh
- node tools/analytics/build-analytics success ci after_script
- if [[ $TRAVIS_TEST_RESULT -eq 0 ]]; then node tools/analytics/build-analytics success ci job; else node tools/analytics/build-analytics error ci job; fi
- ./scripts/ci-lite/cleanup.sh
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/1ef62e23078036f9cee4
# trigger Buildtime Trend Service to parse Travis CI log
- https://buildtimetrend.herokuapp.com/travis
on_success: always # options: [always|never|change] default: always
on_failure: always # options: [always|never|change] default: always
on_start: false # default: false
slack:
secure: EP4MzZ8JMyNQJ4S3cd5LEPWSMjC7ZRdzt3veelDiOeorJ6GwZfCDHncR+4BahDzQAuqyE/yNpZqaLbwRWloDi15qIUsm09vgl/1IyNky1Sqc6lEknhzIXpWSalo4/T9ZP8w870EoDvM/UO+LCV99R3wS8Nm9o99eLoWVb2HIUu0=
deploy:
- provider: gcs
# This is for project angular-github-babysitter
access_key_id: GOOGIOQTDBEOPBUAWFZQ
secret_access_key:
secure: "MEDggllZ5fw4wI9CEUi8WR6jKsKXqdRF/DLxSNC2JpzM5RlVeBm0uqjntYT1Cf1dASvQ2/+vZCUikL/3A48NcoEYRHXGmxu8D6t/SvleQD8Xv434xFOdsa2QqP/HiCtqCLOI5jJz1JVoB5nNyKKZ33ogTUL1LV1TfcrAioyizW8="
# this bucket has a lifecycle to delete after 90 days:
# $ echo '{"rule": [{"action": {"type": "Delete"}, "condition": {"age": 90}}]}' > lifecycle.json
# $ gsutil lifecycle set lifecycle.json gs://angular2-snapshots
bucket: angular2-snapshots
# don't delete generated files
skip_cleanup: true
# serve to public at https://storage.googleapis.com/angular2-snapshots/SHA/dist.tgz
acl: public-read
# upload the .tgz archive created in scripts/ci/build_and_test.sh
local-dir: deploy
# create a "subdirectory" for each commit
upload-dir: $TRAVIS_COMMIT
on:
repo: angular/angular
condition: "$MODE = build_only"
#branches:
# except:
# - g3_v2_0
#
#cache:
# directories:
# - $HOME/.pub-cache
# - $HOME/.chrome/chromium
#
#before_cache:
# # Undo the pollution of the typescript_next build before the cache is primed for future use
# - if [[ "$MODE" == "typescript_next" ]]; then npm install typescript; fi
#
#env:
# global:
# # Use newer verison of GCC to that is required to compile native npm modules for Node v4+ on Ubuntu Precise
# # more info: https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Node.js-v4-(or-io.js-v3)-compiler-requirements
# - CXX=g++-4.8
# - KARMA_DART_BROWSERS=DartiumWithWebPlatform
# # No sandbox mode is needed for Chromium in Travis, it crashes otherwise: https://sites.google.com/a/chromium.org/chromedriver/help/chrome-doesn-t-start
# - KARMA_JS_BROWSERS=ChromeNoSandbox
# - E2E_BROWSERS=ChromeOnTravis
# - LOGS_DIR=/tmp/angular-build/logs
# - SAUCE_USERNAME=angular-ci
# - SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
# - BROWSER_STACK_USERNAME=angularteam1
# - BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
# - ARCH=linux-x64
# - DART_DEV_VERSION=latest
# - DART_STABLE_VERSION=latest
# - DART_CHANNEL=stable
# - DART_VERSION=$DART_STABLE_VERSION
# # Token for tsd to increase github rate limit
# # See https://github.com/DefinitelyTyped/tsd#tsdrc
# # This does not use http://docs.travis-ci.com/user/environment-variables/#Secure-Variables
# # because those are not visible for pull requests, and those should also be reliable.
# # This SSO token belongs to github account angular-github-ratelimit-token which has no access
# # (password is in Valentine)
# - TSDRC='{"token":"ef474500309daea53d5991b3079159a29520a40b"}'
# # GITHUB_TOKEN_ANGULAR
# - secure: "fq/U7VDMWO8O8SnAQkdbkoSe2X92PVqg4d044HmRYVmcf6YbO48+xeGJ8yOk0pCBwl3ISO4Q2ot0x546kxfiYBuHkZetlngZxZCtQiFT9kyId8ZKcYdXaIW9OVdw3Gh3tQyUwDucfkVhqcs52D6NZjyE2aWZ4/d1V4kWRO/LMgo="
# matrix:
# # Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
# - MODE=dart
# - MODE=dart DART_CHANNEL=dev
# - MODE=saucelabs_required
# - MODE=browserstack_required
# - MODE=saucelabs_optional
# - MODE=browserstack_optional
# - MODE=dart_ddc
# - MODE=js
# - MODE=router
# - MODE=build_only
# - MODE=typescript_next
# - MODE=lint
#
#matrix:
# allow_failures:
# - env: "MODE=saucelabs_optional"
# - env: "MODE=browserstack_optional"
#
#addons:
# firefox: "38.0"
# apt:
# sources:
# - ubuntu-toolchain-r-test
# packages:
# - g++-4.8
#
#before_install:
# - node tools/analytics/build-analytics start ci job
# - node tools/analytics/build-analytics start ci before_install
# - echo ${TSDRC} > .tsdrc
# - export CHROME_BIN=$HOME/.chrome/chromium/chrome-linux/chrome
# - export DISPLAY=:99.0
# - export GIT_SHA=$(git rev-parse HEAD)
# - ./scripts/ci/init_android.sh
# - sh -e /etc/init.d/xvfb start
# # Use a separate SauseLabs account for upstream/master builds in order for Sauce to create a badge representing the status of just upstream/master
# - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_BRANCH}" = "master" ] && SAUCE_USERNAME="angular2-ci" && SAUCE_ACCESS_KEY="693ebc16208a-0b5b-1614-8d66-a2662f4e" || true'
# - node tools/analytics/build-analytics success ci before_install
#
#install:
# - node tools/analytics/build-analytics start ci install
# # Install version of npm that we are locked against
# - npm install -g npm@3.5.3
# # Install version of Chromium that we are locked against
# - ./scripts/ci/install_chromium.sh
# # Install version of Dart based on the matrix build variables
# - ./scripts/ci/install_dart.sh ${DART_CHANNEL} ${DART_VERSION} ${ARCH}
# # Print the size of caches to ease debugging
# - du -sh ./node_modules || true
# # Install npm dependecies
# # check-node-modules will exit(1) if we don't need to install
# # we need to manually kick off the postinstall script if check-node-modules exit(0)s
# - node tools/npm/check-node-modules --purge && npm install || npm run postinstall
# - node tools/analytics/build-analytics success ci install
#
#before_script:
# - node tools/analytics/build-analytics start ci before_script
# - mkdir -p $LOGS_DIR
# - ./scripts/ci/presubmit-queue-setup.sh
# - node tools/analytics/build-analytics success ci before_script
#
#script:
# - node tools/analytics/build-analytics start ci script
# - ./scripts/ci/build_and_test.sh ${MODE}
# - node tools/analytics/build-analytics success ci script
#
#after_script:
# - node tools/analytics/build-analytics start ci after_script
# - ./scripts/ci/print-logs.sh
# - ./scripts/ci/after-script.sh
# - ./scripts/publish/publish-build-artifacts.sh
# - node tools/analytics/build-analytics success ci after_script
# - tools/analytics/build-analytics $TRAVIS_TEST_RESULT ci job
#
#notifications:
# webhooks:
# urls:
# - https://webhooks.gitter.im/e/1ef62e23078036f9cee4
# # trigger Buildtime Trend Service to parse Travis CI log
# - https://buildtimetrend.herokuapp.com/travis
# - http://104.197.9.155:8484/hubot/travis/activity
# on_success: always # options: [always|never|change] default: always
# on_failure: always # options: [always|never|change] default: always
# on_start: never # default: never
# slack:
# secure: EP4MzZ8JMyNQJ4S3cd5LEPWSMjC7ZRdzt3veelDiOeorJ6GwZfCDHncR+4BahDzQAuqyE/yNpZqaLbwRWloDi15qIUsm09vgl/1IyNky1Sqc6lEknhzIXpWSalo4/T9ZP8w870EoDvM/UO+LCV99R3wS8Nm9o99eLoWVb2HIUu0=

File diff suppressed because it is too large Load Diff

View File

@ -11,8 +11,11 @@ Someone with committer access will do the rest.
We have automated the process for merging pull requests into master. Our goal is to minimize the disruption for
Angular committers and also prevent breakages on master.
When a PR is ready to merge, a project member in the CoreTeamMember list (see below) can add the special label,
`PR: merge`.
When a PR has `pr_state: LGTM` and is ready to merge, you should add the `pr_action: merge` label.
Currently (late 2015), we need to ensure that each PR will cleanly merge into the Google-internal version control,
so the caretaker reviews the changes manually.
After this review, the caretaker adds `zomg_admin: do_merge` which is restricted to admins only.
A robot running as [mary-poppins](https://github.com/mary-poppins)
is notified that the label was added by an authorized person,
and will create a new branch in the angular project, using the convention `presubmit-{username}-pr-{number}`.
@ -26,6 +29,6 @@ Finally, after merge `mary-poppins` removes the presubmit branch.
## Administration
The list of users who can trigger a merge by adding the label is stored in our appengine app datastore.
The list of users who can trigger a merge by adding the `zomg_admin: do_merge` label is stored in our appengine app datastore.
Edit the contents of the [CoreTeamMember Table](
https://console.developers.google.com/project/angular2-automation/datastore/query?queryType=KindQuery&namespace=&kind=CoreTeamMember)

View File

@ -48,14 +48,18 @@ features, by not reporting duplicate issues. Providing the following informatio
chances of your issue being dealt with quickly:
* **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
* **Motivation for or Use Case** - explain why this is a bug for you
* **Angular Version** - what version of Angular is affected (e.g. 2.0.0-alpha.53)
* **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
* **Browsers and Operating System** - is this a problem with all browsers?
* **Reproduce the Error** - provide a live example (using [Plunker][plunker],
[JSFiddle][jsfiddle] or [Runnable][runnable]) or a unambiguous set of steps.
[JSFiddle][jsfiddle] or [Runnable][runnable]) or a unambiguous set of steps
* **Related Issues** - has a similar issue been reported before?
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
causing the problem (line of code or commit)
You can file new issues by providing the above information [here](https://github.com/angular/angular/issues/new).
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
Before you submit your Pull Request (PR) consider the following guidelines:
@ -176,7 +180,8 @@ Must be one of the following:
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **perf**: A code change that improves performance
* **test**: Adding missing tests or correcting existing tests
* **build** Changes that affect the build system, CI configuration or external dependencies (example scopes: gulp, broccoli, npm)
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
* **chore**: Other changes that don't modify `src` or `test` files
### Scope

View File

@ -9,7 +9,7 @@ JS and Dart versions. It also explains the basic mechanics of using `git`, `node
* [Installing NPM Modules and Dart Packages](#installing-npm-modules-and-dart-packages)
* [Build commands](#build-commands)
* [Running Tests Locally](#running-tests-locally)
* [Formatting](#clang-format)
* [Code Style](#code-style)
* [Project Information](#project-information)
* [CI using Travis](#ci-using-travis)
* [Transforming Dart code](#transforming-dart-code)
@ -23,7 +23,16 @@ if you'd like to contribute to Angular.
Before you can build and test Angular, you must install and configure the
following products on your development machine:
* [Dart](https://www.dartlang.org) (version ` >=1.12.0 <2.0.0`), specifically the Dart-SDK and
* [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or
[Windows](http://windows.github.com)); [GitHub's Guide to Installing
Git](https://help.github.com/articles/set-up-git) is a good source of information.
* [Node.js](http://nodejs.org), (version `>=5.4.1 <6`) which is used to run a development web server,
run tests, and generate distributable files. We also use Node's Package Manager, `npm`
(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). One of the **simplest** ways to get both is to install the **Dart Editor bundle**,
which includes the editor, SDK and Dartium. See the [Dart tools](https://www.dartlang.org/tools)
@ -33,19 +42,6 @@ following products on your development machine:
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).`
* [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or
[Windows](http://windows.github.com)); [GitHub's Guide to Installing
Git](https://help.github.com/articles/set-up-git) is a good source of information.
* [Node.js](http://nodejs.org), (version `>=4.2.1 <5`) which is used to run a development web server,
run tests, and generate distributable files. We also use Node's Package Manager, `npm`
(version `>=2.14.7 <3.0`), which comes with Node. Depending on your system, you can install Node either from
source or as a pre-packaged bundle.
* [Chrome Canary](https://www.google.com/chrome/browser/canary.html), a version of Chrome with
bleeding edge functionality, built especially for developers (and early adopters).
* [Bower](http://bower.io/).
## Getting the Sources
@ -200,15 +196,15 @@ Then, in another terminal:
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.(saucelabs|browserstack) --browsers=option1,option2,..,optionN`
- 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.saucelabs --browsers=Safari8,ie11 //run in Sauce Labs with Safari 8 and IE11
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.saucelabs --browsers=IOS,safari8,android5.1 //run in Sauce Labs with iOS 7, iOS 8, iOs 9, Safari 8 and Android 5.1
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
@ -231,7 +227,9 @@ Angular specific command line options when running protractor:
Angular specific command line options when running protractor (e.g. force gc, ...):
`$(npm bin)/protractor protractor-{js|dart2js}-conf.js --ng-help`
## Formatting with <a name="clang-format">clang-format</a>
## 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
@ -277,6 +275,14 @@ to some whitespace difference.
* `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
```shell
$ gulp lint
```
## Generating the API documentation
The following gulp task will generate the API docs in the `dist/angular.io/partials/api/angular2`:

215
LICENSE
View File

@ -1,202 +1,21 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
The MIT License
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Copyright (c) 2014-2016 Google, Inc. http://angular.io
1. Definitions.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,31 +1,24 @@
[![Build Status](https://travis-ci.org/angular/angular.svg?branch=master)](https://travis-ci.org/angular/angular)
[![Build Status](https://travis-ci.org/angular/angular.svg?branch=master)](https://travis-ci.org/angular/angular)
[![Join the chat at https://gitter.im/angular/angular](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Issue Stats](http://issuestats.com/github/angular/angular/badge/pr)](http://issuestats.com/github/angular/angular)
[![Issue Stats](http://issuestats.com/github/angular/angular/badge/issue)](http://issuestats.com/github/angular/angular)
[![npm version](https://badge.fury.io/js/angular2.svg)](http://badge.fury.io/js/angular2)
[![Downloads](http://img.shields.io/npm/dm/angular2.svg)](https://npmjs.org/package/angular2)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/angular2-ci.svg)](https://saucelabs.com/u/angular2-ci)
Angular
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.
Angular 2 is currently in **Developer Preview**. We recommend using Angular 1.X for production
applications:
* [AngularJS][ngJS]: [angular/angular.js](http://github.com/angular/angular.js).
* [AngularDart][ngDart]: [angular/angular.dart](http://github.com/angular/angular.dart).
Angular 2 is currently in **Beta**.
## Quickstart
[Get started in 5 minutes][quickstart].
## Setup & Install Angular 2
Follow the instructions given on the [Angular download page][download].
## Want to help?
@ -36,8 +29,7 @@ guidelines for [contributing][contributing] and then check out one of our issues
[contributing]: http://github.com/angular/angular/blob/master/CONTRIBUTING.md
[dart]: http://www.dartlang.org
[dartium]: http://www.dartlang.org/tools/dartium
[download]: http://angular.io/download/
[quickstart]: https://angular.io/docs/js/latest/quickstart.html
[quickstart]: https://angular.io/docs/ts/latest/quickstart.html
[ng2]: http://angular.io
[ngDart]: http://angulardart.org
[ngJS]: http://angularjs.org

View File

@ -21,7 +21,7 @@ By default the debugging tools are disabled.
Enable the debugging tools as follows:
```dart
import 'package:angular2/tools.dart';
import 'package:angular2/platform/browser.dart';
main() async {
var appRef = await bootstrap(Application);

View File

@ -117,7 +117,7 @@ speed things up is to use plain class fields in your expressions and avoid any
kinds of computation. Example:
```typescript
@View({
@Component({
template: '<button [enabled]="isEnabled">{{title}}</button>'
})
class FancyButton {

View File

@ -1,3 +1,33 @@
// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL) and BrowserStack (BS).
// If the target is set to null, then the browser is not run anywhere during CI.
// If a category becomes empty (e.g. BS and required), then the corresponding job must be commented out in Travis configuration.
var CIconfiguration = {
'Chrome': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
'Firefox': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
// FirefoxBeta should be required:true
// https://github.com/angular/angular/issues/7560
'FirefoxBeta': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: false}},
'ChromeDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
'FirefoxDev': { unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
'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: true}, 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}},
'Android4.4': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Android5': { unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
'Safari7': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'Safari8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'Safari9': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
'iOS7': { unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
'iOS8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
// TODO(mlaval): iOS9 deactivated as not reliable, reactivate after https://github.com/angular/angular/issues/5408
'iOS9': { unitTest: {target: null, required: false}, e2e: {target: null, required: true}},
'WindowsPhone': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
};
var customLaunchers = {
'DartiumWithWebPlatform': {
base: 'Dartium',
@ -8,7 +38,7 @@ var customLaunchers = {
'SL_CHROME': {
base: 'SauceLabs',
browserName: 'chrome',
version: '46'
version: '50'
},
'SL_CHROMEBETA': {
base: 'SauceLabs',
@ -23,7 +53,7 @@ var customLaunchers = {
'SL_FIREFOX': {
base: 'SauceLabs',
browserName: 'firefox',
version: '42'
version: '45'
},
'SL_FIREFOXBETA': {
base: 'SauceLabs',
@ -47,7 +77,7 @@ var customLaunchers = {
platform: 'OS X 10.10',
version: '8'
},
'SL_SAFARI9.0': {
'SL_SAFARI9': {
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.11',
@ -119,7 +149,7 @@ var customLaunchers = {
platform: 'Linux',
version: '4.4'
},
'SL_ANDROID5.1': {
'SL_ANDROID5': {
base: 'SauceLabs',
browserName: 'android',
platform: 'Linux',
@ -239,21 +269,18 @@ var customLaunchers = {
}
};
// iOS9 deactivated as not reliable in both providers
// TODO(mlaval): reactivate after https://github.com/angular/angular/issues/5408
var sauceAliases = {
'ALL': Object.keys(customLaunchers).filter(function(item) {return customLaunchers[item].base == 'SauceLabs';}),
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9.0'],
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5.1', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5.1'],
'DESKTOP': ['SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'],
'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9.0'],
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
'CI': ['SL_CHROME',' SL_FIREFOX', 'SL_CHROMEDEV', 'SL_FIREFOXBETA', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE',
'SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5.1']
'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true),
'CI_OPTIONAL': buildConfiguration('unitTest', 'SL', false)
};
var browserstackAliases = {
@ -264,16 +291,23 @@ var browserstackAliases = {
'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9'],
'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
'CI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9', 'BS_IOS7', 'BS_IOS8', 'BS_WINDOWSPHONE']
'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
};
module.exports = {
customLaunchers: customLaunchers,
sauceAliases: sauceAliases,
browserstackAliases: browserstackAliases
}
};
if (process.env.TRAVIS) {
process.env.SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY.split('').reverse().join('');
process.env.BROWSER_STACK_ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY.split('').reverse().join('');
function buildConfiguration(type, target, required) {
return Object.keys(CIconfiguration)
.filter((item) => {
var conf = CIconfiguration[item][type];
return conf.required === required && conf.target === target;
})
.map((item) => {
return target + '_' + item.toUpperCase();
});
}

112
build.sh Executable file
View File

@ -0,0 +1,112 @@
#!/usr/bin/env bash
set -e -o pipefail
cd `dirname $0`
TSCONFIG=./modules/tsconfig.json
echo "====== (all)COMPILING: \$(npm bin)/ng2tc -p ${TSCONFIG} ====="
rm -rf ./dist/all/
mkdir ./dist/all/
# prepare all files for e2e tests
cp -r ./modules/playground ./dist/all/
cp -r ./modules/playground/favicon.ico ./dist/
#rsync -aP ./modules/playground/* ./dist/all/playground/
mkdir ./dist/all/playground/vendor
cd ./dist/all/playground/vendor
ln -s ../../../../node_modules/es6-shim/es6-shim.js .
ln -s ../../../../node_modules/zone.js/dist/zone.js .
ln -s ../../../../node_modules/zone.js/dist/long-stack-trace-zone.js .
ln -s ../../../../node_modules/systemjs/dist/system.src.js .
ln -s ../../../../node_modules/base64-js/lib/b64.js .
ln -s ../../../../node_modules/reflect-metadata/Reflect.js .
ln -s ../../../../node_modules/rxjs/bundles/Rx.js .
ln -s ../../../../node_modules/angular/angular.js .
cd -
# compile ts code
$(npm bin)/ng2tc -p ${TSCONFIG}
rm -rf ./dist/packages-dist
for PACKAGE in \
core \
compiler \
common \
platform-browser \
platform-browser-dynamic \
platform-server \
http \
router \
router-deprecated \
upgrade
do
SRCDIR=./modules/@angular/${PACKAGE}
DESTDIR=./dist/packages-dist/${PACKAGE}
UMDES6PATH=${DESTDIR}/esm/${PACKAGE}.umd.js
UMDES5PATH=${DESTDIR}/${PACKAGE}.umd.js
if [[ ${PACKAGE} == "router-deprecated" ]]; then
echo "====== COMPILING: \$(npm bin)/tsc -p ${SRCDIR}/tsconfig-es5.json ====="
$(npm bin)/tsc -p ${SRCDIR}/tsconfig-es5.json
else
echo "====== COMPILING: \$(npm bin)/ng2tc -p ${SRCDIR}/tsconfig-es5.json ====="
$(npm bin)/ng2tc -p ${SRCDIR}/tsconfig-es5.json
fi
cp ${SRCDIR}/package.json ${DESTDIR}/
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'
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'
fi
if [[ ${PACKAGE} == "router-deprecated" ]]; then
echo "====== (esm)COMPILING: \$(npm bin)/tsc -p ${SRCDIR}/tsconfig-es2015.json ====="
$(npm bin)/tsc -p ${SRCDIR}/tsconfig-es2015.json
else
echo "====== (esm)COMPILING: \$(npm bin)/ng2tc -p ${SRCDIR}/tsconfig-es2015.json ====="
$(npm bin)/ng2tc -p ${SRCDIR}/tsconfig-es2015.json
fi
echo "====== BUNDLING: ${SRCDIR} ====="
(
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"
# workaround for https://github.com/rollup/rollup/issues/626
if [[ ${TRAVIS} ]]; then
sed -i "s/ class exports\./ class /g" ${DESTDIR}/esm/${PACKAGE}.umd.js
else
sed -i '' "s/ class exports\./ class /g" ${DESTDIR}/esm/${PACKAGE}.umd.js
fi
$(npm bin)/tsc \
--out ${UMDES5PATH} \
--target es5 \
--allowJs \
${UMDES6PATH} \
modules/\@angular/manual_typings/globals.d.ts \
modules/\@angular/typings/es6-collections/es6-collections.d.ts \
modules/\@angular/typings/es6-promise/es6-promise.d.ts
rm ${UMDES6PATH}
cat ./modules/@angular/license-banner.txt > ${UMDES5PATH}.tmp
cat ${UMDES5PATH} >> ${UMDES5PATH}.tmp
mv ${UMDES5PATH}.tmp ${UMDES5PATH}
done

21
circle.yml Normal file
View File

@ -0,0 +1,21 @@
machine:
node:
version: 5.4.1
dependencies:
pre:
- npm install -g npm
override:
- npm install:
environment:
# Token for tsd to increase github rate limit
# See https://github.com/DefinitelyTyped/tsd#tsdrc
# This is not hidden using https://circleci.com/docs/fork-pr-builds#details
# because those are not visible for pull requests, and those should also be reliable.
# This SSO token belongs to github account angular-github-ratelimit-token which has no access
# (password is in Valentine)
TSD_GITHUB_TOKEN: ef474500309daea53d5991b3079159a29520a40b
test:
override:
- npm run build

File diff suppressed because it is too large Load Diff

View File

@ -1,86 +0,0 @@
// This module provides a customFileHandler for karma
// that serves files with urls like /packages_<timestamp>/...
// with maximum cache.
// We are using these urls when we spawn isolates
// so that the isolates don't reload files every time.
var common = require('karma/lib/middleware/common');
var fs = require('fs');
var DART_EVAL_PATH_RE = /.*\/packages_\d+\/(.*)$/;
module.exports = createFactory;
function createFactory(proxyPaths) {
return {
'framework:dart-evalcache': ['factory', dartEvalCacheFactory]
};
function dartEvalCacheFactory(emitter, logger, customFileHandlers) {
var filesPromise = new common.PromiseContainer();
emitter.on('file_list_modified', function(files) {
filesPromise.set(Promise.resolve(files));
});
var serveFile = common.createServeFile(fs);
var log = logger.create('dart-evalcache');
customFileHandlers.push({
urlRegex: DART_EVAL_PATH_RE,
handler: handler
});
// See source_files handler
function handler(request, response, fa, fb, basePath) {
return filesPromise.then(function(files) {
try {
var requestedFilePath = mapUrlToFile(request.url, proxyPaths, basePath, log);
// TODO(vojta): change served to be a map rather then an array
var file = findByPath(files.served, requestedFilePath);
if (file) {
serveFile(file.contentPath || file.path, response, function() {
common.setHeavyCacheHeaders(response);
}, file.content);
} else {
response.writeHead(404);
response.end('Not found');
}
} catch (e) {
log.error(e.stack);
response.writeHead(500);
response.end('Error', e.stack);
}
});
}
};
}
function mapUrlToFile(url, proxyPaths, basePath, log) {
var originalUrl = url;
url = url.indexOf('?') > -1 ? url.substring(0, url.indexOf('?')) : url;
var match = DART_EVAL_PATH_RE.exec(url);
var packagePath = match[1];
var result = null;
var lastProxyFromLength = 0;
Object.keys(proxyPaths).forEach(function(proxyFrom) {
if (startsWith(packagePath, proxyFrom) && proxyFrom.length > lastProxyFromLength) {
lastProxyFromLength = proxyFrom.length;
result = proxyPaths[proxyFrom] + packagePath.substring(proxyFrom.length);
}
});
return basePath + '/' + result;
}
function startsWith(string, subString) {
return string.length >= subString.length && string.slice(0, subString.length) === subString;
}
function findByPath(files, path) {
for (var i = 0; i < files.length; i++) {
if (files[i].path === path) {
return files[i];
}
}
return null;
}

View File

@ -1,82 +0,0 @@
var browserProvidersConf = require('./browser-providers.conf.js');
var packageSources = {
// Dependencies installed with `pub install`.
'unittest': 'packages/unittest',
'guinness': 'packages/guinness',
'matcher': 'packages/matcher',
'stack_trace': 'packages/stack_trace',
'collection': 'packages/collection',
'path': 'packages/path',
'observe': 'packages/observe',
'quiver': 'packages/quiver',
'intl': 'packages/intl',
'smoke': 'packages/smoke',
'logging': 'packages/logging',
'utf': 'packages/utf',
// Local dependencies, transpiled from the source.
'angular2': 'dist/dart/angular2/lib',
'angular2/test/': 'dist/dart/angular2/test/',
'http': 'dist/dart/http/lib',
'angular2_material': 'dist/dart/angular2_material/lib',
'benchpress': 'dist/dart/benchpress/lib',
'examples': 'dist/dart/examples/lib'
};
var proxyPaths = {};
Object.keys(packageSources).map(function(packageName) {
var filePath = packageSources[packageName];
proxyPaths['/packages/'+packageName] = '/base/'+filePath;
});
// Karma configuration
// Generated on Thu Sep 25 2014 11:52:02 GMT-0700 (PDT)
module.exports = function(config) {
config.set({
frameworks: ['dart-unittest', 'dart-evalcache'],
files: [
// Init and configure guiness.
{pattern: 'test-init.dart', included: true},
// Unit test files needs to be included.
{pattern: 'dist/dart/**/*_spec.dart', included: true, watched: false},
// Karma-dart via the dart-unittest framework generates
// `__adapter_unittest.dart` that imports these files.
{pattern: 'dist/dart/**', included: false, watched: false},
// Dependencies, installed with `pub install`.
{pattern: 'packages/**/*.dart', included: false, watched: false},
// Init and configure guiness.
{pattern: 'test-main.dart', included: true},
{pattern: 'modules/**/test/**/static_assets/**', included: false, watched: false},
],
exclude: [
'dist/dart/**/packages/**',
'modules/angular1_router/**'
],
karmaDartImports: {
guinness: 'package:guinness/guinness_html.dart'
},
// Map packages to the correct urls where Karma serves them.
proxies: proxyPaths,
customLaunchers: browserProvidersConf.customLaunchers,
browsers: ['DartiumWithWebPlatform'],
port: 9877,
plugins: [
require('karma-dart'),
require('karma-chrome-launcher'),
require('karma-sauce-launcher'),
require('./karma-dart-evalcache')(packageSources)
]
});
};

View File

@ -11,28 +11,37 @@ module.exports = function(config) {
files: [
// Sources and specs.
// Loaded through the System loader, in `test-main.js`.
{pattern: 'dist/js/dev/es5/**', included: false, watched: false},
{pattern: 'dist/all/@angular/**/*.js', included: false, watched: true},
{pattern: 'dist/all/angular2/**/*.js', included: false, watched: true},
'node_modules/es6-shim/es6-shim.js',
// include Angular v1 for upgrade module testing
'node_modules/angular/angular.min.js',
// zone-microtask must be included first as it contains a Promise monkey patch
'node_modules/zone.js/dist/zone-microtask.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/zone.js/dist/jasmine-patch.js',
'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/fake-async-test.js',
// Including systemjs because it defines `__eval`, which produces correct stack traces.
'modules/angular2/src/testing/shims_for_IE.js',
'shims_for_IE.js',
'node_modules/systemjs/dist/system.src.js',
{pattern: 'node_modules/rxjs/**', included: false, watched: false, served: true},
'node_modules/reflect-metadata/Reflect.js',
'tools/build/file2modulename.js',
'test-main.js',
{pattern: 'modules/**/test/**/static_assets/**', included: false, watched: false}
{pattern: 'dist/all/empty.*', included: false, watched: false},
{pattern: 'modules/@angular/platform-browser/test/static_assets/**', included: false, watched: false},
{pattern: 'modules/@angular/platform-browser-dynamic/test/browser/static_assets/**', included: false, watched: false}
],
exclude: ['dist/js/dev/es5/**/e2e_test/**', 'dist/js/dev/es5/angular2/examples/**', 'dist/angular1_router.js'],
exclude: [
'dist/all/@angular/**/e2e_test/**',
'dist/all/@angular/examples/**',
'dist/all/angular1_router.js',
'dist/all/@angular/platform-browser/testing/e2e_util.js'
],
customLaunchers: browserProvidersConf.customLaunchers,
@ -53,6 +62,7 @@ module.exports = function(config) {
reporters: ['internal-angular'],
sauceLabs: {
testName: 'Angular2',
retryLimit: 3,
startConnect: false,
recordVideo: false,
recordScreenshots: false,
@ -67,19 +77,23 @@ module.exports = function(config) {
browserStack: {
project: 'Angular2',
startTunnel: false,
retryLimit: 1,
retryLimit: 3,
timeout: 600,
pollingTimeout: 10000
},
browsers: ['Chrome'],
port: 9876
port: 9876,
captureTimeout: 60000,
browserDisconnectTimeout : 60000,
browserDisconnectTolerance : 3,
browserNoActivityTimeout : 60000,
});
if (process.env.TRAVIS) {
var buildId = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
if (process.env.MODE === 'saucelabs') {
if (process.env.CI_MODE.startsWith('saucelabs')) {
config.sauceLabs.build = buildId;
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
@ -89,7 +103,7 @@ module.exports = function(config) {
config.transports = ['polling'];
}
if (process.env.MODE === 'browserstack') {
if (process.env.CI_MODE.startsWith('browserstack')) {
config.browserStack.build = buildId;
config.browserStack.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
}

View File

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

View File

@ -0,0 +1,5 @@
export * from './src/pipes';
export * from './src/directives';
export * from './src/forms';
export * from './src/common_directives';
export * from './src/location';

View File

@ -0,0 +1,13 @@
{
"name": "@angular/common",
"version": "$$ANGULAR_VERSION$$",
"description": "",
"main": "index.js",
"jsnext:main": "esm/index.js",
"typings": "index.d.ts",
"author": "angular",
"license": "MIT",
"peerDependencies": {
"@angular/core": "$$ANGULAR_VERSION$$"
}
}

View File

@ -0,0 +1,17 @@
export default {
entry: '../../../dist/packages-dist/common/esm/index.js',
dest: '../../../dist/packages-dist/common/esm/common.umd.js',
format: 'umd',
moduleName: 'ng.common',
globals: {
'@angular/core': 'ng.core',
'rxjs/Subject': 'Rx',
'rxjs/observable/PromiseObservable': 'Rx', // this is wrong, but this stuff has changed in rxjs b.6 so we need to fix it when we update.
'rxjs/operator/toPromise': 'Rx.Observable.prototype',
'rxjs/Observable': 'Rx'
},
plugins: [
// nodeResolve({ jsnext: true, main: true }),
]
}

View File

@ -1,5 +1,4 @@
import {CONST_EXPR, Type} from 'angular2/src/facade/lang';
import {Type} from '@angular/core';
import {FORM_DIRECTIVES} from './forms';
import {CORE_DIRECTIVES} from './directives';
@ -9,7 +8,7 @@ import {CORE_DIRECTIVES} from './directives';
* NgModel).
*
* This collection can be used to quickly enumerate all the built-in directives in the `directives`
* property of the `@Component` or `@View` decorators.
* property of the `@Component` decorator.
*
* ### Example
*
@ -17,7 +16,7 @@ import {CORE_DIRECTIVES} from './directives';
*
* ```typescript
* import {NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault, NgModel, NgForm} from
* 'angular2/angular2';
* '@angular/common';
* import {OtherDirective} from './myDirectives';
*
* @Component({
@ -33,7 +32,7 @@ import {CORE_DIRECTIVES} from './directives';
* one could import all the common directives at once:
*
* ```typescript
* import {COMMON_DIRECTIVES} from 'angular2/angular2';
* import {COMMON_DIRECTIVES} from '@angular/common';
* import {OtherDirective} from './myDirectives';
*
* @Component({
@ -46,4 +45,4 @@ import {CORE_DIRECTIVES} from './directives';
* }
* ```
*/
export const COMMON_DIRECTIVES: Type[][] = CONST_EXPR([CORE_DIRECTIVES, FORM_DIRECTIVES]);
export const COMMON_DIRECTIVES: Type[][] = /*@ts2dart_const*/[CORE_DIRECTIVES, FORM_DIRECTIVES];

View File

@ -6,7 +6,9 @@
export {NgClass} from './directives/ng_class';
export {NgFor} from './directives/ng_for';
export {NgIf} from './directives/ng_if';
export {NgTemplateOutlet} from './directives/ng_template_outlet';
export {NgStyle} from './directives/ng_style';
export {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
export {NgPlural, NgPluralCase, NgLocalization} from './directives/ng_plural';
export * from './directives/observable_list_diff';
export {CORE_DIRECTIVES} from './directives/core_directives';
export {CORE_DIRECTIVES} from './directives/core_directives';

View File

@ -1,23 +1,25 @@
import {CONST_EXPR, Type} from 'angular2/src/facade/lang';
import {Type} from '../../src/facade/lang';
import {NgClass} from './ng_class';
import {NgFor} from './ng_for';
import {NgIf} from './ng_if';
import {NgTemplateOutlet} from './ng_template_outlet';
import {NgStyle} from './ng_style';
import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './ng_switch';
import {NgPlural, NgPluralCase} from './ng_plural';
/**
* A collection of Angular core directives that are likely to be used in each and every Angular
* application.
*
* This collection can be used to quickly enumerate all the built-in directives in the `directives`
* property of the `@View` annotation.
* property of the `@Component` annotation.
*
* ### Example ([live demo](http://plnkr.co/edit/yakGwpCdUkg0qfzX5m8g?p=preview))
*
* Instead of writing:
*
* ```typescript
* import {NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault} from 'angular2/angular2';
* import {NgClass, NgIf, NgFor, NgSwitch, NgSwitchWhen, NgSwitchDefault} from '@angular/common';
* import {OtherDirective} from './myDirectives';
*
* @Component({
@ -32,7 +34,7 @@ import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './ng_switch';
* one could import all the core directives at once:
*
* ```typescript
* import {CORE_DIRECTIVES} from 'angular2/angular2';
* import {CORE_DIRECTIVES} from '@angular/common';
* import {OtherDirective} from './myDirectives';
*
* @Component({
@ -45,5 +47,15 @@ import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './ng_switch';
* }
* ```
*/
export const CORE_DIRECTIVES: Type[] =
CONST_EXPR([NgClass, NgFor, NgIf, NgStyle, NgSwitch, NgSwitchWhen, NgSwitchDefault]);
export const CORE_DIRECTIVES: Type[] = /*@ts2dart_const*/[
NgClass,
NgFor,
NgIf,
NgTemplateOutlet,
NgStyle,
NgSwitch,
NgSwitchWhen,
NgSwitchDefault,
NgPlural,
NgPluralCase
];

View File

@ -1,16 +1,18 @@
import {isPresent, isString, StringWrapper, isBlank, isArray} from 'angular2/src/facade/lang';
import {
DoCheck,
OnDestroy,
Directive,
ElementRef,
IterableDiffer,
IterableDiffers,
KeyValueDiffer,
KeyValueDiffers,
Renderer
} from 'angular2/core';
import {StringMapWrapper, isListLikeIterable} from 'angular2/src/facade/collection';
Renderer,
IterableDiffer,
KeyValueDiffer,
CollectionChangeRecord,
KeyValueChangeRecord
} from '@angular/core';
import {isPresent, isString, isArray} from '../../src/facade/lang';
import {StringMapWrapper, isListLikeIterable} from '../../src/facade/collection';
/**
* The `NgClass` directive conditionally adds and removes CSS classes on an HTML element based on
@ -31,13 +33,14 @@ import {StringMapWrapper, isListLikeIterable} from 'angular2/src/facade/collecti
* ### Example ([live demo](http://plnkr.co/edit/a4YdtmWywhJ33uqfpPPn?p=preview)):
*
* ```
* import {Component, NgClass} from 'angular2/angular2';
* import {Component} from '@angular/core';
* import {NgClass} from '@angular/common';
*
* @Component({
* selector: 'toggle-button',
* inputs: ['isDisabled'],
* template: `
* <div class="button" [ng-class]="{active: isOn, disabled: isDisabled}"
* <div class="button" [ngClass]="{active: isOn, disabled: isDisabled}"
* (click)="toggle(!isOn)">
* Click me!
* </div>`,
@ -70,68 +73,70 @@ import {StringMapWrapper, isListLikeIterable} from 'angular2/src/facade/collecti
* }
* ```
*/
@Directive({selector: '[ng-class]', inputs: ['rawClass: ng-class', 'initialClasses: class']})
@Directive({selector: '[ngClass]', inputs: ['rawClass: ngClass', 'initialClasses: class']})
export class NgClass implements DoCheck, OnDestroy {
private _differ: any;
private _mode: string;
private _initialClasses = [];
private _rawClass;
private _iterableDiffer: IterableDiffer;
private _keyValueDiffer: KeyValueDiffer;
private _initialClasses: string[] = [];
private _rawClass: string[] | Set<string>;
constructor(private _iterableDiffers: IterableDiffers, private _keyValueDiffers: KeyValueDiffers,
private _ngEl: ElementRef, private _renderer: Renderer) {}
set initialClasses(v) {
set initialClasses(v: string) {
this._applyInitialClasses(true);
this._initialClasses = isPresent(v) && isString(v) ? v.split(' ') : [];
this._applyInitialClasses(false);
this._applyClasses(this._rawClass, false);
}
set rawClass(v) {
set rawClass(v: string | string[] | Set<string>| {[key: string]: any}) {
this._cleanupClasses(this._rawClass);
if (isString(v)) {
v = v.split(' ');
v = (<string>v).split(' ');
}
this._rawClass = v;
this._rawClass = <string[] | Set<string>>v;
this._iterableDiffer = null;
this._keyValueDiffer = null;
if (isPresent(v)) {
if (isListLikeIterable(v)) {
this._differ = this._iterableDiffers.find(v).create(null);
this._mode = 'iterable';
this._iterableDiffer = this._iterableDiffers.find(v).create(null);
} else {
this._differ = this._keyValueDiffers.find(v).create(null);
this._mode = 'keyValue';
this._keyValueDiffer = this._keyValueDiffers.find(v).create(null);
}
} else {
this._differ = null;
}
}
ngDoCheck(): void {
if (isPresent(this._differ)) {
var changes = this._differ.diff(this._rawClass);
if (isPresent(this._iterableDiffer)) {
var changes = this._iterableDiffer.diff(this._rawClass);
if (isPresent(changes)) {
if (this._mode == 'iterable') {
this._applyIterableChanges(changes);
} else {
this._applyKeyValueChanges(changes);
}
this._applyIterableChanges(changes);
}
}
if (isPresent(this._keyValueDiffer)) {
var changes = this._keyValueDiffer.diff(this._rawClass);
if (isPresent(changes)) {
this._applyKeyValueChanges(changes);
}
}
}
ngOnDestroy(): void { this._cleanupClasses(this._rawClass); }
private _cleanupClasses(rawClassVal): void {
private _cleanupClasses(rawClassVal: string[] | Set<string>| {[key: string]: any}): void {
this._applyClasses(rawClassVal, true);
this._applyInitialClasses(false);
}
private _applyKeyValueChanges(changes: any): void {
changes.forEachAddedItem((record) => { this._toggleClass(record.key, record.currentValue); });
changes.forEachChangedItem((record) => { this._toggleClass(record.key, record.currentValue); });
changes.forEachRemovedItem((record) => {
changes.forEachAddedItem(
(record: KeyValueChangeRecord) => { this._toggleClass(record.key, record.currentValue); });
changes.forEachChangedItem(
(record: KeyValueChangeRecord) => { this._toggleClass(record.key, record.currentValue); });
changes.forEachRemovedItem((record: KeyValueChangeRecord) => {
if (record.previousValue) {
this._toggleClass(record.key, false);
}
@ -139,15 +144,17 @@ export class NgClass implements DoCheck, OnDestroy {
}
private _applyIterableChanges(changes: any): void {
changes.forEachAddedItem((record) => { this._toggleClass(record.item, true); });
changes.forEachRemovedItem((record) => { this._toggleClass(record.item, false); });
changes.forEachAddedItem(
(record: CollectionChangeRecord) => { this._toggleClass(record.item, true); });
changes.forEachRemovedItem(
(record: CollectionChangeRecord) => { this._toggleClass(record.item, false); });
}
private _applyInitialClasses(isCleanup: boolean) {
this._initialClasses.forEach(className => this._toggleClass(className, !isCleanup));
}
private _applyClasses(rawClassVal: string[] | Set<string>| {[key: string]: string},
private _applyClasses(rawClassVal: string[] | Set<string>| {[key: string]: any},
isCleanup: boolean) {
if (isPresent(rawClassVal)) {
if (isArray(rawClassVal)) {
@ -155,23 +162,24 @@ export class NgClass implements DoCheck, OnDestroy {
} else if (rawClassVal instanceof Set) {
(<Set<string>>rawClassVal).forEach(className => this._toggleClass(className, !isCleanup));
} else {
StringMapWrapper.forEach(<{[k: string]: string}>rawClassVal, (expVal, className) => {
if (expVal) this._toggleClass(className, !isCleanup);
});
StringMapWrapper.forEach(<{[k: string]: any}>rawClassVal,
(expVal: any, className: string) => {
if (isPresent(expVal)) this._toggleClass(className, !isCleanup);
});
}
}
}
private _toggleClass(className: string, enabled): void {
private _toggleClass(className: string, enabled: boolean): void {
className = className.trim();
if (className.length > 0) {
if (className.indexOf(' ') > -1) {
var classes = className.split(/\s+/g);
for (var i = 0, len = classes.length; i < len; i++) {
this._renderer.setElementClass(this._ngEl, classes[i], enabled);
this._renderer.setElementClass(this._ngEl.nativeElement, classes[i], enabled);
}
} else {
this._renderer.setElementClass(this._ngEl, className, enabled);
this._renderer.setElementClass(this._ngEl.nativeElement, className, enabled);
}
}
}

View File

@ -6,26 +6,44 @@ import {
IterableDiffers,
ViewContainerRef,
TemplateRef,
ViewRef
} from 'angular2/core';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
EmbeddedViewRef,
TrackByFn,
DefaultIterableDiffer,
CollectionChangeRecord
} from '@angular/core';
import {isPresent, isBlank, getTypeNameForDebugging} from '../../src/facade/lang';
import {BaseException} from '../../src/facade/exceptions';
export class NgForRow {
constructor(public $implicit: any, public index: number, public count: number) {}
get first(): boolean { return this.index === 0; }
get last(): boolean { return this.index === this.count - 1; }
get even(): boolean { return this.index % 2 === 0; }
get odd(): boolean { return !this.even; }
}
/**
* The `NgFor` directive instantiates a template once per item from an iterable. The context for
* each instantiated template inherits from the outer context with the given loop variable set
* to the current item from the iterable.
*
* # Local Variables
* ### Local Variables
*
* `NgFor` provides several exported values that can be aliased to local variables:
*
* * `index` will be set to the current loop iteration for each template context.
* * `first` will be set to a boolean value indicating whether the item is the first one in the
* iteration.
* * `last` will be set to a boolean value indicating whether the item is the last one in the
* iteration.
* * `even` will be set to a boolean value indicating whether this item has an even index.
* * `odd` will be set to a boolean value indicating whether this item has an odd index.
*
* # Change Propagation
* ### Change Propagation
*
* When the contents of the iterator changes, `NgFor` makes the corresponding changes to the DOM:
*
@ -48,39 +66,48 @@ import {isPresent, isBlank} from 'angular2/src/facade/lang';
* elements were deleted and all new elements inserted). This is an expensive operation and should
* be avoided if possible.
*
* # Syntax
* ### Syntax
*
* - `<li *ng-for="#item of items; #i = index">...</li>`
* - `<li template="ng-for #item of items; #i = index">...</li>`
* - `<template ng-for #item [ng-for-of]="items" #i="index"><li>...</li></template>`
* - `<li *ngFor="let item of items; let i = index">...</li>`
* - `<li template="ngFor let item of items; let i = index">...</li>`
* - `<template ngFor let-item [ngForOf]="items" let-i="index"><li>...</li></template>`
*
* ### Example
*
* See a [live demo](http://plnkr.co/edit/KVuXxDp0qinGDyo307QW?p=preview) for a more detailed
* example.
*/
@Directive({selector: '[ng-for][ng-for-of]', inputs: ['ngForOf', 'ngForTemplate']})
@Directive({selector: '[ngFor][ngForOf]', inputs: ['ngForTrackBy', 'ngForOf', 'ngForTemplate']})
export class NgFor implements DoCheck {
/** @internal */
_ngForOf: any;
/** @internal */
_ngForTrackBy: TrackByFn;
private _differ: IterableDiffer;
constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef,
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)) {
this._differ = this._iterableDiffers.find(value).create(this._cdr);
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.`);
}
}
}
set ngForTemplate(value: TemplateRef) {
set ngForTemplate(value: TemplateRef<NgForRow>) {
if (isPresent(value)) {
this._templateRef = value;
}
}
set ngForTrackBy(value: TrackByFn) { this._ngForTrackBy = value; }
ngDoCheck() {
if (isPresent(this._differ)) {
var changes = this._differ.diff(this._ngForOf);
@ -88,19 +115,19 @@ export class NgFor implements DoCheck {
}
}
private _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 = [];
changes.forEachRemovedItem((removedRecord) =>
var recordViewTuples: RecordViewTuple[] = [];
changes.forEachRemovedItem((removedRecord: CollectionChangeRecord) =>
recordViewTuples.push(new RecordViewTuple(removedRecord, null)));
changes.forEachMovedItem((movedRecord) =>
changes.forEachMovedItem((movedRecord: CollectionChangeRecord) =>
recordViewTuples.push(new RecordViewTuple(movedRecord, null)));
var insertTuples = this._bulkRemove(recordViewTuples);
changes.forEachAddedItem((addedRecord) =>
changes.forEachAddedItem((addedRecord: CollectionChangeRecord) =>
insertTuples.push(new RecordViewTuple(addedRecord, null)));
this._bulkInsert(insertTuples);
@ -110,25 +137,31 @@ export class NgFor implements DoCheck {
}
for (var i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
this._viewContainer.get(i).setLocal('last', i === ilen - 1);
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(i);
viewRef.context.index = i;
viewRef.context.count = ilen;
}
changes.forEachIdentityChange((record) => {
var viewRef = <EmbeddedViewRef<NgForRow>>this._viewContainer.get(record.currentIndex);
viewRef.context.$implicit = record.item;
});
}
private _perViewChange(view, record) {
view.setLocal('\$implicit', record.item);
view.setLocal('index', record.currentIndex);
view.setLocal('even', (record.currentIndex % 2 == 0));
view.setLocal('odd', (record.currentIndex % 2 == 1));
private _perViewChange(view: EmbeddedViewRef<NgForRow>, record: CollectionChangeRecord) {
view.context.$implicit = record.item;
}
private _bulkRemove(tuples: RecordViewTuple[]): RecordViewTuple[] {
tuples.sort((a, b) => a.record.previousIndex - b.record.previousIndex);
var movedTuples = [];
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 = this._viewContainer.detach(tuple.record.previousIndex);
tuple.view =
<EmbeddedViewRef<NgForRow>>this._viewContainer.detach(tuple.record.previousIndex);
movedTuples.push(tuple);
} else {
this._viewContainer.remove(tuple.record.previousIndex);
@ -144,8 +177,8 @@ export class NgFor implements DoCheck {
if (isPresent(tuple.view)) {
this._viewContainer.insert(tuple.view, tuple.record.currentIndex);
} else {
tuple.view =
this._viewContainer.createEmbeddedView(this._templateRef, tuple.record.currentIndex);
tuple.view = this._viewContainer.createEmbeddedView(
this._templateRef, new NgForRow(null, null, null), tuple.record.currentIndex);
}
}
return tuples;
@ -153,9 +186,9 @@ export class NgFor implements DoCheck {
}
class RecordViewTuple {
view: ViewRef;
view: EmbeddedViewRef<NgForRow>;
record: any;
constructor(record, view) {
constructor(record: any, view: EmbeddedViewRef<NgForRow>) {
this.record = record;
this.view = view;
}

View File

@ -1,16 +1,16 @@
import {Directive, ViewContainerRef, TemplateRef} from 'angular2/core';
import {isBlank} from 'angular2/src/facade/lang';
import {Directive, ViewContainerRef, TemplateRef} from '@angular/core';
import {isBlank} from '../../src/facade/lang';
/**
* Removes or recreates a portion of the DOM tree based on an {expression}.
*
* If the expression assigned to `ng-if` evaluates to a false value then the element
* If the expression assigned to `ngIf` evaluates to a false value then the element
* is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.
*
* ### Example ([live demo](http://plnkr.co/edit/fe0kgemFBtmQOY31b4tw?p=preview)):
*
* ```
* <div *ng-if="errorCount > 0" class="error">
* <div *ngIf="errorCount > 0" class="error">
* <!-- Error message displayed when the errorCount property on the current context is greater
* than 0. -->
* {{errorCount}} errors detected
@ -19,17 +19,18 @@ import {isBlank} from 'angular2/src/facade/lang';
*
* ### Syntax
*
* - `<div *ng-if="condition">...</div>`
* - `<div template="ng-if condition">...</div>`
* - `<template [ng-if]="condition"><div>...</div></template>`
* - `<div *ngIf="condition">...</div>`
* - `<div template="ngIf condition">...</div>`
* - `<template [ngIf]="condition"><div>...</div></template>`
*/
@Directive({selector: '[ng-if]', inputs: ['ngIf']})
@Directive({selector: '[ngIf]', inputs: ['ngIf']})
export class NgIf {
private _prevCondition: boolean = null;
constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef) {}
constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<Object>) {
}
set ngIf(newCondition /* boolean */) {
set ngIf(newCondition: any /* boolean */) {
if (newCondition && (isBlank(this._prevCondition) || !this._prevCondition)) {
this._prevCondition = true;
this._viewContainer.createEmbeddedView(this._templateRef);

View File

@ -0,0 +1,148 @@
import {
Directive,
ViewContainerRef,
TemplateRef,
ContentChildren,
QueryList,
Attribute,
AfterContentInit,
Input
} from '@angular/core';
import {isPresent, NumberWrapper} from '../../src/facade/lang';
import {Map} from '../../src/facade/collection';
import {SwitchView} from './ng_switch';
const _CATEGORY_DEFAULT = 'other';
export abstract class NgLocalization { abstract getPluralCategory(value: any): string; }
/**
* `ngPlural` is an i18n directive that displays DOM sub-trees that match the switch expression
* value, or failing that, DOM sub-trees that match the switch expression's pluralization category.
*
* To use this directive, you must provide an extension of `NgLocalization` that maps values to
* category names. You then define a container element that sets the `[ngPlural]` attribute to a
* switch expression.
* - Inner elements defined with an `[ngPluralCase]` attribute will display based on their
* expression.
* - If `[ngPluralCase]` is set to a value starting with `=`, it will only display if the value
* matches the switch expression exactly.
* - Otherwise, the view will be treated as a "category match", and will only display if exact
* 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) {
* if(value < 5) {
* return 'few';
* }
* }
* }
*
* @Component({
* selector: 'app',
* providers: [provide(NgLocalization, {useClass: MyLocalization})]
* })
* @View({
* template: `
* <p>Value = {{value}}</p>
* <button (click)="inc()">Increment</button>
*
* <div [ngPlural]="value">
* <template ngPluralCase="=0">there is nothing</template>
* <template ngPluralCase="=1">there is one</template>
* <template ngPluralCase="few">there are a few</template>
* <template ngPluralCase="other">there is some number</template>
* </div>
* `,
* directives: [NgPlural, NgPluralCase]
* })
* export class App {
* value = 'init';
*
* inc() {
* this.value = this.value === 'init' ? 0 : this.value + 1;
* }
* }
*
* ```
*/
@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);
}
}
@Directive({selector: '[ngPlural]'})
export class NgPlural implements AfterContentInit {
private _switchValue: number;
private _activeView: SwitchView;
private _caseViews = new Map<any, SwitchView>();
@ContentChildren(NgPluralCase) cases: QueryList<NgPluralCase> = null;
constructor(private _localization: NgLocalization) {}
@Input()
set ngPlural(value: number) {
this._switchValue = value;
this._updateView();
}
ngAfterContentInit() {
this.cases.forEach((pluralCase: NgPluralCase): void => {
this._caseViews.set(this._formatValue(pluralCase), pluralCase._view);
});
this._updateView();
}
/** @internal */
_updateView(): void {
this._clearViews();
var view: SwitchView = this._caseViews.get(this._switchValue);
if (!isPresent(view)) view = this._getCategoryView(this._switchValue);
this._activateView(view);
}
/** @internal */
_clearViews() {
if (isPresent(this._activeView)) this._activeView.destroy();
}
/** @internal */
_activateView(view: SwitchView) {
if (!isPresent(view)) return;
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); }
}

View File

@ -1,3 +1,4 @@
import {KeyValueChangeRecord} from '@angular/core';
import {
DoCheck,
KeyValueDiffer,
@ -5,30 +6,31 @@ import {
ElementRef,
Directive,
Renderer
} from 'angular2/core';
import {isPresent, isBlank, print} from 'angular2/src/facade/lang';
} from '@angular/core';
import {isPresent, isBlank} from '../../src/facade/lang';
/**
* The `NgStyle` directive changes styles based on a result of expression evaluation.
*
* An expression assigned to the `ng-style` property must evaluate to an object and the
* An expression assigned to the `ngStyle` property must evaluate to an object and the
* corresponding element styles are updated based on changes to this object. Style names to update
* are taken from the object's keys, and values - from the corresponding object's values.
*
* ### Syntax
*
* - `<div [ng-style]="{'font-style': style}"></div>`
* - `<div [ng-style]="styleExp"></div>` - here the `styleExp` must evaluate to an object
* - `<div [ngStyle]="{'font-style': style}"></div>`
* - `<div [ngStyle]="styleExp"></div>` - here the `styleExp` must evaluate to an object
*
* ### Example ([live demo](http://plnkr.co/edit/YamGS6GkUh9GqWNQhCyM?p=preview)):
*
* ```
* import {Component, NgStyle} from 'angular2/angular2';
* import {Component} from '@angular/core';
* import {NgStyle} from '@angular/common';
*
* @Component({
* selector: 'ng-style-example',
* selector: 'ngStyle-example',
* template: `
* <h1 [ng-style]="{'font-style': style, 'font-size': size, 'font-weight': weight}">
* <h1 [ngStyle]="{'font-style': style, 'font-size': size, 'font-weight': weight}">
* Change style of this text!
* </h1>
*
@ -58,17 +60,17 @@ import {isPresent, isBlank, print} from 'angular2/src/facade/lang';
* In this example the `font-style`, `font-size` and `font-weight` styles will be updated
* based on the `style` property's value changes.
*/
@Directive({selector: '[ng-style]', inputs: ['rawStyle: ng-style']})
@Directive({selector: '[ngStyle]', inputs: ['rawStyle: ngStyle']})
export class NgStyle implements DoCheck {
/** @internal */
_rawStyle;
_rawStyle: {[key: string]: string};
/** @internal */
_differ: KeyValueDiffer;
constructor(private _differs: KeyValueDiffers, private _ngEl: ElementRef,
private _renderer: Renderer) {}
set rawStyle(v) {
set rawStyle(v: {[key: string]: string}) {
this._rawStyle = v;
if (isBlank(this._differ) && isPresent(v)) {
this._differ = this._differs.find(this._rawStyle).create(null);
@ -85,12 +87,15 @@ export class NgStyle implements DoCheck {
}
private _applyChanges(changes: any): void {
changes.forEachAddedItem((record) => { this._setStyle(record.key, record.currentValue); });
changes.forEachChangedItem((record) => { this._setStyle(record.key, record.currentValue); });
changes.forEachRemovedItem((record) => { 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, name, val);
this._renderer.setElementStyle(this._ngEl.nativeElement, name, val);
}
}

View File

@ -1,11 +1,12 @@
import {Directive, Host, ViewContainerRef, TemplateRef} from 'angular2/core';
import {isPresent, isBlank, normalizeBlank, CONST_EXPR} from 'angular2/src/facade/lang';
import {ListWrapper, Map} from 'angular2/src/facade/collection';
import {Directive, Host, ViewContainerRef, TemplateRef} from '@angular/core';
import {isPresent, isBlank, normalizeBlank} from '../../src/facade/lang';
import {ListWrapper, Map} from '../../src/facade/collection';
const _WHEN_DEFAULT = CONST_EXPR(new Object());
const _WHEN_DEFAULT = /*@ts2dart_const*/ new Object();
class SwitchView {
constructor(private _viewContainerRef: ViewContainerRef, private _templateRef: TemplateRef) {}
export class SwitchView {
constructor(private _viewContainerRef: ViewContainerRef,
private _templateRef: TemplateRef<Object>) {}
create(): void { this._viewContainerRef.createEmbeddedView(this._templateRef); }
@ -21,38 +22,38 @@ class SwitchView {
* `NgSwitch` simply inserts nested elements based on which match expression matches the value
* obtained from the evaluated switch expression. In other words, you define a container element
* (where you place the directive with a switch expression on the
* **`[ng-switch]="..."` attribute**), define any inner elements inside of the directive and
* place a `[ng-switch-when]` attribute per element.
* `[ngSwitch]="..."` attribute), define any inner elements inside of the directive and
* place a `[ngSwitchWhen]` attribute per element.
*
* The `ng-switch-when` property is used to inform `NgSwitch` which element to display when the
* expression is evaluated. If a matching expression is not found via a `ng-switch-when` property
* then an element with the `ng-switch-default` attribute is displayed.
* The `ngSwitchWhen` property is used to inform `NgSwitch` which element to display when the
* expression is evaluated. If a matching expression is not found via a `ngSwitchWhen` property
* then an element with the `ngSwitchDefault` attribute is displayed.
*
* ### Example ([live demo](http://plnkr.co/edit/DQMTII95CbuqWrl3lYAs?p=preview))
*
* ```typescript
* @Component({selector: 'app'})
* @View({
* @Component({
* selector: 'app',
* template: `
* <p>Value = {{value}}</p>
* <button (click)="inc()">Increment</button>
*
* <div [ng-switch]="value">
* <p *ng-switch-when="'init'">increment to start</p>
* <p *ng-switch-when="0">0, increment again</p>
* <p *ng-switch-when="1">1, increment again</p>
* <p *ng-switch-when="2">2, stop incrementing</p>
* <p *ng-switch-default>&gt; 2, STOP!</p>
* <div [ngSwitch]="value">
* <p *ngSwitchWhen="'init'">increment to start</p>
* <p *ngSwitchWhen="0">0, increment again</p>
* <p *ngSwitchWhen="1">1, increment again</p>
* <p *ngSwitchWhen="2">2, stop incrementing</p>
* <p *ngSwitchDefault>&gt; 2, STOP!</p>
* </div>
*
* <!-- alternate syntax -->
*
* <p [ng-switch]="value">
* <template ng-switch-when="init">increment to start</template>
* <template [ng-switch-when]="0">0, increment again</template>
* <template [ng-switch-when]="1">1, increment again</template>
* <template [ng-switch-when]="2">2, stop incrementing</template>
* <template ng-switch-default>&gt; 2, STOP!</template>
* <p [ngSwitch]="value">
* <template ngSwitchWhen="init">increment to start</template>
* <template [ngSwitchWhen]="0">0, increment again</template>
* <template [ngSwitchWhen]="1">1, increment again</template>
* <template [ngSwitchWhen]="2">2, stop incrementing</template>
* <template ngSwitchDefault>&gt; 2, STOP!</template>
* </p>
* `,
* directives: [NgSwitch, NgSwitchWhen, NgSwitchDefault]
@ -68,14 +69,14 @@ class SwitchView {
* bootstrap(App).catch(err => console.error(err));
* ```
*/
@Directive({selector: '[ng-switch]', inputs: ['ngSwitch']})
@Directive({selector: '[ngSwitch]', inputs: ['ngSwitch']})
export class NgSwitch {
private _switchValue: any;
private _useDefault: boolean = false;
private _valueViews = new Map<any, SwitchView[]>();
private _activeViews: SwitchView[] = [];
set ngSwitch(value) {
set ngSwitch(value: any) {
// Empty the currently active ViewContainers
this._emptyAllActiveViews();
@ -92,7 +93,7 @@ export class NgSwitch {
}
/** @internal */
_onWhenValueChanged(oldWhen, newWhen, view: SwitchView): void {
_onWhenValueChanged(oldWhen: any, newWhen: any, view: SwitchView): void {
this._deregisterView(oldWhen, view);
this._registerView(newWhen, view);
@ -136,7 +137,7 @@ export class NgSwitch {
}
/** @internal */
_registerView(value, view: SwitchView): void {
_registerView(value: any, view: SwitchView): void {
var views = this._valueViews.get(value);
if (isBlank(views)) {
views = [];
@ -146,7 +147,7 @@ export class NgSwitch {
}
/** @internal */
_deregisterView(value, view: SwitchView): void {
_deregisterView(value: any, view: SwitchView): void {
// `_WHEN_DEFAULT` is used a marker for non-registered whens
if (value === _WHEN_DEFAULT) return;
var views = this._valueViews.get(value);
@ -159,14 +160,14 @@ export class NgSwitch {
}
/**
* Insert the sub-tree when the `ng-switch-when` expression evaluates to the same value as the
* Insert the sub-tree when the `ngSwitchWhen` expression evaluates to the same value as the
* enclosing switch expression.
*
* If multiple match expression match the switch expression value, all of them are displayed.
*
* See {@link NgSwitch} for more details and example.
*/
@Directive({selector: '[ng-switch-when]', inputs: ['ngSwitchWhen']})
@Directive({selector: '[ngSwitchWhen]', inputs: ['ngSwitchWhen']})
export class NgSwitchWhen {
// `_WHEN_DEFAULT` is used as a marker for a not yet initialized value
/** @internal */
@ -175,13 +176,13 @@ export class NgSwitchWhen {
_view: SwitchView;
private _switch: NgSwitch;
constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef,
constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef<Object>,
@Host() ngSwitch: NgSwitch) {
this._switch = ngSwitch;
this._view = new SwitchView(viewContainer, templateRef);
}
set ngSwitchWhen(value) {
set ngSwitchWhen(value: any) {
this._switch._onWhenValueChanged(this._value, value, this._view);
this._value = value;
}
@ -193,9 +194,9 @@ export class NgSwitchWhen {
*
* See {@link NgSwitch} for more details and example.
*/
@Directive({selector: '[ng-switch-default]'})
@Directive({selector: '[ngSwitchDefault]'})
export class NgSwitchDefault {
constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef,
constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef<Object>,
@Host() sswitch: NgSwitch) {
sswitch._registerView(_WHEN_DEFAULT, new SwitchView(viewContainer, templateRef));
}

View File

@ -0,0 +1,26 @@
import {Directive, Input, ViewContainerRef, ViewRef, TemplateRef} from '@angular/core';
import {isPresent} from '../../src/facade/lang';
/**
* Creates and inserts an embedded view based on a prepared `TemplateRef`.
*
* ### Syntax
* - `<template [ngTemplateOutlet]="templateRefExpression"></template>`
*/
@Directive({selector: '[ngTemplateOutlet]'})
export class NgTemplateOutlet {
private _insertedViewRef: ViewRef;
constructor(private _viewContainerRef: ViewContainerRef) {}
@Input()
set ngTemplateOutlet(templateRef: TemplateRef<Object>) {
if (isPresent(this._insertedViewRef)) {
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._insertedViewRef));
}
if (isPresent(templateRef)) {
this._insertedViewRef = this._viewContainerRef.createEmbeddedView(templateRef);
}
}
}

View File

@ -21,7 +21,7 @@ class ObservableListDiff extends DefaultIterableDiffer {
}
}
dynamic diff(ObservableList collection) {
DefaultIterableDiffer diff(ObservableList collection) {
if (collection is! ObservableList) {
throw "Cannot change the type of a collection";
}
@ -57,7 +57,7 @@ class ObservableListDiff extends DefaultIterableDiffer {
class ObservableListDiffFactory implements IterableDifferFactory {
const ObservableListDiffFactory();
bool supports(obj) => obj is ObservableList;
IterableDiffer create(ChangeDetectorRef cdRef) {
IterableDiffer create(ChangeDetectorRef cdRef, [Function trackByFn]) {
return new ObservableListDiff(cdRef);
}
}

View File

@ -0,0 +1,10 @@
// TS does not have Observables
// I need to be here to make TypeScript think this is a module.
import {} from '../../src/facade/lang';
/**
* This module exists in Dart, but not in Typescript. This exported symbol
* is only here to help Typescript think this is a module.
*/
export var workaround_empty_observable_list_diff: any;

View File

@ -0,0 +1 @@
../../facade/src

View File

@ -7,9 +7,8 @@
* to read information
* from the form DOM elements.
*
* This module is not included in the `angular2` module; you must import the forms module
* Forms providers are not included in default providers; you must import these providers
* explicitly.
*
*/
export {AbstractControl, Control, ControlGroup, ControlArray} from './forms/model';
@ -31,12 +30,34 @@ export {
NgSelectOption,
SelectControlValueAccessor
} from './forms/directives/select_control_value_accessor';
export {FORM_DIRECTIVES} from './forms/directives';
export {FORM_DIRECTIVES, RadioButtonState} from './forms/directives';
export {NG_VALIDATORS, NG_ASYNC_VALIDATORS, Validators} from './forms/validators';
export {
RequiredValidator,
MinLengthValidator,
MaxLengthValidator,
PatternValidator,
Validator
} from './forms/directives/validators';
export {FormBuilder, FORM_PROVIDERS, FORM_BINDINGS} from './forms/form_builder';
export {FormBuilder} from './forms/form_builder';
import {FormBuilder} from './forms/form_builder';
import {RadioControlRegistry} from './forms/directives/radio_control_value_accessor';
import {Type} from '@angular/core';
/**
* Shorthand set of providers used for building Angular forms.
*
* ### Example
*
* ```typescript
* bootstrap(MyApp, [FORM_PROVIDERS]);
* ```
*/
export const FORM_PROVIDERS: Type[] = /*@ts2dart_const*/[FormBuilder, RadioControlRegistry];
/**
* See {@link FORM_PROVIDERS} instead.
*
* @deprecated
*/
export const FORM_BINDINGS = /*@ts2dart_const*/ FORM_PROVIDERS;

View File

@ -1,4 +1,4 @@
import {Type, CONST_EXPR} from 'angular2/src/facade/lang';
import {Type} from '@angular/core';
import {NgControlName} from './directives/ng_control_name';
import {NgFormControl} from './directives/ng_form_control';
import {NgModel} from './directives/ng_model';
@ -8,12 +8,18 @@ import {NgForm} from './directives/ng_form';
import {DefaultValueAccessor} from './directives/default_value_accessor';
import {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
import {NumberValueAccessor} from './directives/number_value_accessor';
import {RadioControlValueAccessor} from './directives/radio_control_value_accessor';
import {NgControlStatus} from './directives/ng_control_status';
import {
SelectControlValueAccessor,
NgSelectOption
} from './directives/select_control_value_accessor';
import {RequiredValidator, MinLengthValidator, MaxLengthValidator} from './directives/validators';
import {
RequiredValidator,
MinLengthValidator,
MaxLengthValidator,
PatternValidator
} from './directives/validators';
export {NgControlName} from './directives/ng_control_name';
export {NgFormControl} from './directives/ng_form_control';
@ -23,19 +29,28 @@ export {NgFormModel} from './directives/ng_form_model';
export {NgForm} from './directives/ng_form';
export {DefaultValueAccessor} from './directives/default_value_accessor';
export {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
export {
RadioControlValueAccessor,
RadioButtonState
} from './directives/radio_control_value_accessor';
export {NumberValueAccessor} from './directives/number_value_accessor';
export {NgControlStatus} from './directives/ng_control_status';
export {
SelectControlValueAccessor,
NgSelectOption
} from './directives/select_control_value_accessor';
export {RequiredValidator, MinLengthValidator, MaxLengthValidator} from './directives/validators';
export {
RequiredValidator,
MinLengthValidator,
MaxLengthValidator,
PatternValidator
} from './directives/validators';
export {NgControl} from './directives/ng_control';
export {ControlValueAccessor} from './directives/control_value_accessor';
/**
*
* A list of all the form directives used as part of a `@View` annotation.
* A list of all the form directives used as part of a `@Component` annotation.
*
* This is a shorthand for importing them each individually.
*
@ -49,7 +64,7 @@ export {ControlValueAccessor} from './directives/control_value_accessor';
* class MyApp {}
* ```
*/
export const FORM_DIRECTIVES: Type[] = CONST_EXPR([
export const FORM_DIRECTIVES: Type[] = /*@ts2dart_const*/[
NgControlName,
NgControlGroup,
@ -63,9 +78,11 @@ export const FORM_DIRECTIVES: Type[] = CONST_EXPR([
NumberValueAccessor,
CheckboxControlValueAccessor,
SelectControlValueAccessor,
RadioControlValueAccessor,
NgControlStatus,
RequiredValidator,
MinLengthValidator,
MaxLengthValidator
]);
MaxLengthValidator,
PatternValidator
];

View File

@ -1,6 +1,6 @@
import {AbstractControl} from '../model';
import {isPresent} from 'angular2/src/facade/lang';
import {unimplemented} from 'angular2/src/facade/exceptions';
import {isPresent} from '../../../src/facade/lang';
import {unimplemented} from '../../../src/facade/exceptions';
/**
* Base class for control directives.

View File

@ -1,33 +1,34 @@
import {Directive, Renderer, ElementRef, Self, forwardRef, Provider} from 'angular2/core';
import {Directive, Renderer, ElementRef, Self, forwardRef, Provider} from '@angular/core';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor';
import {CONST_EXPR} from 'angular2/src/facade/lang';
const CHECKBOX_VALUE_ACCESSOR = CONST_EXPR(new Provider(
NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => CheckboxControlValueAccessor), multi: true}));
export const CHECKBOX_VALUE_ACCESSOR: any = /*@ts2dart_const*/ {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CheckboxControlValueAccessor),
multi: true
};
/**
* The accessor for writing a value and listening to changes on a checkbox input element.
*
* ### Example
* ```
* <input type="checkbox" ng-control="rememberLogin">
* <input type="checkbox" ngControl="rememberLogin">
* ```
*/
@Directive({
selector:
'input[type=checkbox][ng-control],input[type=checkbox][ng-form-control],input[type=checkbox][ng-model]',
'input[type=checkbox][ngControl],input[type=checkbox][ngFormControl],input[type=checkbox][ngModel]',
host: {'(change)': 'onChange($event.target.checked)', '(blur)': 'onTouched()'},
bindings: [CHECKBOX_VALUE_ACCESSOR]
providers: [CHECKBOX_VALUE_ACCESSOR]
})
export class CheckboxControlValueAccessor implements ControlValueAccessor {
onChange = (_) => {};
onChange = (_: any) => {};
onTouched = () => {};
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
writeValue(value: any): void {
this._renderer.setElementProperty(this._elementRef, 'checked', value);
this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', value);
}
registerOnChange(fn: (_: any) => {}): void { this.onChange = fn; }
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }

View File

@ -1,5 +1,4 @@
import {OpaqueToken} from 'angular2/core';
import {CONST_EXPR} from 'angular2/src/facade/lang';
import {OpaqueToken} from '@angular/core';
/**
* A bridge between a control and a native element.
@ -26,4 +25,10 @@ export interface ControlValueAccessor {
registerOnTouched(fn: any): void;
}
export const NG_VALUE_ACCESSOR: OpaqueToken = CONST_EXPR(new OpaqueToken("NgValueAccessor"));
/**
* Used to provide a {@link ControlValueAccessor} for form controls.
*
* See {@link DefaultValueAccessor} for how to implement one.
*/
export const NG_VALUE_ACCESSOR: OpaqueToken =
/*@ts2dart_const*/ new OpaqueToken("NgValueAccessor");

View File

@ -1,9 +1,13 @@
import {Directive, ElementRef, Renderer, Self, forwardRef, Provider} from 'angular2/core';
import {Directive, ElementRef, Renderer, forwardRef} from '@angular/core';
import {isBlank} from '../../../src/facade/lang';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor';
import {isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
const DEFAULT_VALUE_ACCESSOR = CONST_EXPR(new Provider(
NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => DefaultValueAccessor), multi: true}));
export const DEFAULT_VALUE_ACCESSOR: any = /*@ts2dart_const*/
/* @ts2dart_Provider */ {
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
@ -11,27 +15,27 @@ const DEFAULT_VALUE_ACCESSOR = CONST_EXPR(new Provider(
*
* ### Example
* ```
* <input type="text" ng-control="searchQuery">
* <input type="text" ngControl="searchQuery">
* ```
*/
@Directive({
selector:
'input:not([type=checkbox])[ng-control],textarea[ng-control],input:not([type=checkbox])[ng-form-control],textarea[ng-form-control],input:not([type=checkbox])[ng-model],textarea[ng-model],[ng-default-control]',
'input:not([type=checkbox])[ngControl],textarea[ngControl],input:not([type=checkbox])[ngFormControl],textarea[ngFormControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]',
// TODO: vsavkin replace the above selector with the one below it once
// https://github.com/angular/angular/issues/3011 is implemented
// selector: '[ng-control],[ng-model],[ng-form-control]',
// selector: '[ngControl],[ngModel],[ngFormControl]',
host: {'(input)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
bindings: [DEFAULT_VALUE_ACCESSOR]
})
export class DefaultValueAccessor implements ControlValueAccessor {
onChange = (_) => {};
onChange = (_: any) => {};
onTouched = () => {};
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
writeValue(value: any): void {
var normalizedValue = isBlank(value) ? '' : value;
this._renderer.setElementProperty(this._elementRef, 'value', normalizedValue);
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', normalizedValue);
}
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }

View File

@ -42,4 +42,4 @@ export interface Form {
* Update the model for a particular control with a new value.
*/
updateModel(dir: NgControl, value: any): void;
}
}

View File

@ -1,6 +1,8 @@
import {unimplemented} from '../../../src/facade/exceptions';
import {ControlValueAccessor} from './control_value_accessor';
import {AbstractControlDirective} from './abstract_control_directive';
import {unimplemented} from 'angular2/src/facade/exceptions';
import {AsyncValidatorFn, ValidatorFn} from './validators';
/**
* A base class that all control directive extend.
@ -12,8 +14,8 @@ export abstract class NgControl extends AbstractControlDirective {
name: string = null;
valueAccessor: ControlValueAccessor = null;
get validator(): Function { return unimplemented(); }
get asyncValidator(): Function { return unimplemented(); }
get validator(): ValidatorFn { return <ValidatorFn>unimplemented(); }
get asyncValidator(): AsyncValidatorFn { return <AsyncValidatorFn>unimplemented(); }
abstract viewToModelUpdate(newValue: any): void;
}

View File

@ -9,17 +9,19 @@ import {
forwardRef,
Provider,
Self
} from 'angular2/core';
import {CONST_EXPR} from 'angular2/src/facade/lang';
} from '@angular/core';
import {ControlContainer} from './control_container';
import {controlPath, composeValidators, composeAsyncValidators} from './shared';
import {ControlGroup} from '../model';
import {Form} from './form_interface';
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
import {NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
import {AsyncValidatorFn, ValidatorFn} from './validators';
const controlGroupProvider =
CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgControlGroup)}));
export const controlGroupProvider: any =
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
provide: ControlContainer,
useExisting: forwardRef(() => NgControlGroup)
};
/**
* Creates and binds a control group to a DOM element.
@ -32,29 +34,26 @@ const controlGroupProvider =
* @Component({
* selector: 'my-app',
* directives: [FORM_DIRECTIVES],
* })
* @View({
* template: `
* <div>
* <h2>Angular2 Control &amp; ControlGroup Example</h2>
* <h2>Angular Control &amp; ControlGroup Example</h2>
* <form #f="ngForm">
* <div ng-control-group="name" #cg-name="ngForm">
* <div ngControlGroup="name" #cg-name="form">
* <h3>Enter your name:</h3>
* <p>First: <input ng-control="first" required></p>
* <p>Middle: <input ng-control="middle"></p>
* <p>Last: <input ng-control="last" required></p>
* <p>First: <input ngControl="first" required></p>
* <p>Middle: <input ngControl="middle"></p>
* <p>Last: <input ngControl="last" required></p>
* </div>
* <h3>Name value:</h3>
* <pre>{{valueOf(cgName)}}</pre>
* <p>Name is {{cgName?.control?.valid ? "valid" : "invalid"}}</p>
* <h3>What's your favorite food?</h3>
* <p><input ng-control="food"></p>
* <p><input ngControl="food"></p>
* <h3>Form value</h3>
* <pre>{{valueOf(f)}}</pre>
* </form>
* </div>
* `,
* directives: [FORM_DIRECTIVES]
* `
* })
* export class App {
* valueOf(cg: NgControlGroup): string {
@ -70,9 +69,9 @@ const controlGroupProvider =
* this group can be accessed separately from the overall form.
*/
@Directive({
selector: '[ng-control-group]',
selector: '[ngControlGroup]',
providers: [controlGroupProvider],
inputs: ['name: ng-control-group'],
inputs: ['name: ngControlGroup'],
exportAs: 'ngForm'
})
export class NgControlGroup extends ControlContainer implements OnInit,
@ -106,7 +105,7 @@ export class NgControlGroup extends ControlContainer implements OnInit,
*/
get formDirective(): Form { return this._parent.formDirective; }
get validator(): Function { return composeValidators(this._validators); }
get validator(): ValidatorFn { return composeValidators(this._validators); }
get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); }
get asyncValidator(): AsyncValidatorFn { return composeAsyncValidators(this._asyncValidators); }
}

View File

@ -1,6 +1,3 @@
import {CONST_EXPR} from 'angular2/src/facade/lang';
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
import {
OnChanges,
OnDestroy,
@ -14,8 +11,9 @@ import {
Inject,
Optional,
Self
} from 'angular2/core';
} from '@angular/core';
import {EventEmitter, ObservableWrapper} from '../../../src/facade/async';
import {ControlContainer} from './control_container';
import {NgControl} from './ng_control';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
@ -27,11 +25,15 @@ import {
selectValueAccessor
} from './shared';
import {Control} from '../model';
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
import {NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
import {ValidatorFn, AsyncValidatorFn} from './validators';
const controlNameBinding =
CONST_EXPR(new Provider(NgControl, {useExisting: forwardRef(() => NgControlName)}));
export const controlNameBinding: any =
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
provide: NgControl,
useExisting: forwardRef(() => NgControlName)
};
/**
* Creates and binds a control with a specified name to a DOM element.
@ -50,10 +52,10 @@ const controlNameBinding =
* directives: [FORM_DIRECTIVES],
* template: `
* <form #f="ngForm" (submit)='onLogIn(f.value)'>
* Login <input type='text' ng-control='login' #l="ngForm">
* <div *ng-if="!l.valid">Login is invalid</div>
* Login <input type='text' ngControl='login' #l="form">
* <div *ngIf="!l.valid">Login is invalid</div>
*
* Password <input type='password' ng-control='password'>
* Password <input type='password' ngControl='password'>
* <button type='submit'>Log in!</button>
* </form>
* `})
@ -64,7 +66,7 @@ const controlNameBinding =
* }
* ```
*
* We can also use ng-model to bind a domain model to the form.
* We can also use ngModel to bind a domain model to the form.
*
* ```
* @Component({
@ -72,9 +74,9 @@ const controlNameBinding =
* directives: [FORM_DIRECTIVES],
* template: `
* <form (submit)='onLogIn()'>
* Login <input type='text' ng-control='login' [(ng-model)]="credentials.login">
* Password <input type='password' ng-control='password'
* [(ng-model)]="credentials.password">
* Login <input type='text' ngControl='login' [(ngModel)]="credentials.login">
* Password <input type='password' ngControl='password'
* [(ngModel)]="credentials.password">
* <button type='submit'>Log in!</button>
* </form>
* `})
@ -89,7 +91,7 @@ const controlNameBinding =
* ```
*/
@Directive({
selector: '[ng-control]',
selector: '[ngControl]',
bindings: [controlNameBinding],
inputs: ['name: ngControl', 'model: ngModel'],
outputs: ['update: ngModelChange'],
@ -136,9 +138,9 @@ export class NgControlName extends NgControl implements OnChanges,
get formDirective(): any { return this._parent.formDirective; }
get validator(): Function { return composeValidators(this._validators); }
get validator(): ValidatorFn { return composeValidators(this._validators); }
get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); }
get asyncValidator(): AsyncValidatorFn { return composeAsyncValidators(this._asyncValidators); }
get control(): Control { return this.formDirective.getControl(this); }
}

View File

@ -1,9 +1,13 @@
import {Directive, Self} from 'angular2/core';
import {Directive, Self} from '@angular/core';
import {NgControl} from './ng_control';
import {isBlank, isPresent} from 'angular2/src/facade/lang';
import {isPresent} from '../../../src/facade/lang';
/**
* Directive automatically applied to Angular forms that sets CSS classes
* based on control status (valid/invalid/dirty/etc).
*/
@Directive({
selector: '[ng-control],[ng-model],[ng-form-control]',
selector: '[ngControl],[ngModel],[ngFormControl]',
host: {
'[class.ng-untouched]': 'ngClassUntouched',
'[class.ng-touched]': 'ngClassTouched',

View File

@ -1,22 +1,22 @@
import {Directive, forwardRef, Provider, Optional, Inject, Self} from '@angular/core';
import {
PromiseWrapper,
ObservableWrapper,
EventEmitter,
PromiseCompleter
} from 'angular2/src/facade/async';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
import {Directive, forwardRef, Provider, Optional, Inject, Self} from 'angular2/core';
} from '../../../src/facade/async';
import {ListWrapper} from '../../../src/facade/collection';
import {isPresent} from '../../../src/facade/lang';
import {NgControl} from './ng_control';
import {Form} from './form_interface';
import {NgControlGroup} from './ng_control_group';
import {ControlContainer} from './control_container';
import {AbstractControl, ControlGroup, Control} from '../model';
import {setUpControl, setUpControlGroup, composeValidators, composeAsyncValidators} from './shared';
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
import {NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
const formDirectiveProvider =
CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgForm)}));
export const formDirectiveProvider: any =
/*@ts2dart_const*/ {provide: ControlContainer, useExisting: forwardRef(() => NgForm)};
/**
* If `NgForm` is bound in a component, `<form>` elements in that component will be
@ -36,7 +36,7 @@ const formDirectiveProvider =
*
* ### Submission
*
* The `ng-submit` event signals when the user triggers a form submission.
* The `ngSubmit` event signals when the user triggers a form submission.
*
* ### Example ([live demo](http://plnkr.co/edit/ltdgYj4P0iY64AR71EpL?p=preview))
*
@ -47,16 +47,16 @@ const formDirectiveProvider =
* <div>
* <p>Submit the form to see the data object Angular builds</p>
* <h2>NgForm demo</h2>
* <form #f="ngForm" (ng-submit)="onSubmit(f.value)">
* <form #f="ngForm" (ngSubmit)="onSubmit(f.value)">
* <h3>Control group: credentials</h3>
* <div ng-control-group="credentials">
* <p>Login: <input type="text" ng-control="login"></p>
* <p>Password: <input type="password" ng-control="password"></p>
* <div ngControlGroup="credentials">
* <p>Login: <input type="text" ngControl="login"></p>
* <p>Password: <input type="password" ngControl="password"></p>
* </div>
* <h3>Control group: person</h3>
* <div ng-control-group="person">
* <p>First name: <input type="text" ng-control="firstName"></p>
* <p>Last name: <input type="text" ng-control="lastName"></p>
* <div ngControlGroup="person">
* <p>First name: <input type="text" ngControl="firstName"></p>
* <p>Last name: <input type="text" ngControl="lastName"></p>
* </div>
* <button type="submit">Submit Form</button>
* <p>Form data submitted:</p>
@ -78,7 +78,7 @@ const formDirectiveProvider =
* ```
*/
@Directive({
selector: 'form:not([ng-no-form]):not([ng-form-model]),ng-form,[ng-form]',
selector: 'form:not([ngNoForm]):not([ngFormModel]),ngForm,[ngForm]',
bindings: [formDirectiveProvider],
host: {
'(submit)': 'onSubmit()',

View File

@ -1,6 +1,3 @@
import {CONST_EXPR} from 'angular2/src/facade/lang';
import {StringMapWrapper} from 'angular2/src/facade/collection';
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
import {
OnChanges,
SimpleChange,
@ -11,10 +8,14 @@ import {
Inject,
Optional,
Self
} from 'angular2/core';
} from '@angular/core';
import {StringMapWrapper} from '../../../src/facade/collection';
import {EventEmitter, ObservableWrapper} from '../../../src/facade/async';
import {NgControl} from './ng_control';
import {Control} from '../model';
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
import {NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
import {
setUpControl,
@ -23,9 +24,13 @@ import {
isPropertyUpdated,
selectValueAccessor
} from './shared';
import {ValidatorFn, AsyncValidatorFn} from './validators';
const formControlBinding =
CONST_EXPR(new Provider(NgControl, {useExisting: forwardRef(() => NgFormControl)}));
export const formControlBinding: any =
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
provide: NgControl,
useExisting: forwardRef(() => NgFormControl)
};
/**
* Binds an existing {@link Control} to a DOM element.
@ -44,7 +49,7 @@ const formControlBinding =
* <h2>NgFormControl Example</h2>
* <form>
* <p>Element with existing control: <input type="text"
* [ng-form-control]="loginControl"></p>
* [ngFormControl]="loginControl"></p>
* <p>Value of existing control: {{loginControl.value}}</p>
* </form>
* </div>
@ -56,9 +61,9 @@ const formControlBinding =
* }
* ```
*
* ###ng-model
* ### ngModel
*
* We can also use `ng-model` to bind a domain model to the form.
* We can also use `ngModel` to bind a domain model to the form.
*
* ### Example ([live demo](http://plnkr.co/edit/yHMLuHO7DNgT8XvtjTDH?p=preview))
*
@ -66,7 +71,7 @@ const formControlBinding =
* @Component({
* selector: "login-comp",
* directives: [FORM_DIRECTIVES],
* template: "<input type='text' [ng-form-control]='loginControl' [(ng-model)]='login'>"
* template: "<input type='text' [ngFormControl]='loginControl' [(ngModel)]='login'>"
* })
* class LoginComp {
* loginControl: Control = new Control('');
@ -75,7 +80,7 @@ const formControlBinding =
* ```
*/
@Directive({
selector: '[ng-form-control]',
selector: '[ngFormControl]',
bindings: [formControlBinding],
inputs: ['form: ngFormControl', 'model: ngModel'],
outputs: ['update: ngModelChange'],
@ -110,9 +115,9 @@ export class NgFormControl extends NgControl implements OnChanges {
get path(): string[] { return []; }
get validator(): Function { return composeValidators(this._validators); }
get validator(): ValidatorFn { return composeValidators(this._validators); }
get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); }
get asyncValidator(): AsyncValidatorFn { return composeAsyncValidators(this._asyncValidators); }
get control(): Control { return this.form; }

View File

@ -1,6 +1,3 @@
import {CONST_EXPR} from 'angular2/src/facade/lang';
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
import {
SimpleChange,
OnChanges,
@ -10,7 +7,11 @@ import {
Inject,
Optional,
Self
} from 'angular2/core';
} from '@angular/core';
import {isBlank} from '../../../src/facade/lang';
import {ListWrapper, StringMapWrapper} from '../../../src/facade/collection';
import {BaseException} from '../../../src/facade/exceptions';
import {ObservableWrapper, EventEmitter} from '../../../src/facade/async';
import {NgControl} from './ng_control';
import {NgControlGroup} from './ng_control_group';
import {ControlContainer} from './control_container';
@ -19,8 +20,11 @@ import {Control, ControlGroup} from '../model';
import {setUpControl, setUpControlGroup, composeValidators, composeAsyncValidators} from './shared';
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
const formDirectiveProvider =
CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgFormModel)}));
export const formDirectiveProvider: any =
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
provide: ControlContainer,
useExisting: forwardRef(() => NgFormModel)
};
/**
* Binds an existing control group to a DOM element.
@ -36,9 +40,9 @@ const formDirectiveProvider =
* template: `
* <div>
* <h2>NgFormModel Example</h2>
* <form [ng-form-model]="loginForm">
* <p>Login: <input type="text" ng-control="login"></p>
* <p>Password: <input type="password" ng-control="password"></p>
* <form [ngFormModel]="loginForm">
* <p>Login: <input type="text" ngControl="login"></p>
* <p>Password: <input type="password" ngControl="password"></p>
* </form>
* <p>Value:</p>
* <pre>{{value}}</pre>
@ -62,17 +66,17 @@ const formDirectiveProvider =
* }
* ```
*
* We can also use ng-model to bind a domain model to the form.
* We can also use ngModel to bind a domain model to the form.
*
* ```typescript
* @Component({
* selector: "login-comp",
* directives: [FORM_DIRECTIVES],
* template: `
* <form [ng-form-model]='loginForm'>
* Login <input type='text' ng-control='login' [(ng-model)]='credentials.login'>
* Password <input type='password' ng-control='password'
* [(ng-model)]='credentials.password'>
* <form [ngFormModel]='loginForm'>
* Login <input type='text' ngControl='login' [(ngModel)]='credentials.login'>
* Password <input type='password' ngControl='password'
* [(ngModel)]='credentials.password'>
* <button (click)="onLogin()">Login</button>
* </form>`
* })
@ -95,9 +99,9 @@ const formDirectiveProvider =
* ```
*/
@Directive({
selector: '[ng-form-model]',
selector: '[ngFormModel]',
bindings: [formDirectiveProvider],
inputs: ['form: ng-form-model'],
inputs: ['form: ngFormModel'],
host: {'(submit)': 'onSubmit()'},
outputs: ['ngSubmit'],
exportAs: 'ngForm'
@ -114,6 +118,7 @@ export class NgFormModel extends ControlContainer implements Form,
}
ngOnChanges(changes: {[key: string]: SimpleChange}): void {
this._checkFormPresent();
if (StringMapWrapper.contains(changes, "form")) {
var sync = composeValidators(this._validators);
this.form.validator = Validators.compose([this.form.validator, sync]);
@ -173,4 +178,11 @@ export class NgFormModel extends ControlContainer implements Form,
dir.valueAccessor.writeValue(ctrl.value);
});
}
private _checkFormPresent() {
if (isBlank(this.form)) {
throw new BaseException(
`ngFormModel expects a form. Please pass one in. Example: <form [ngFormModel]="myCoolForm">`);
}
}
}

View File

@ -1,20 +1,18 @@
import {CONST_EXPR} from 'angular2/src/facade/lang';
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
import {
OnChanges,
SimpleChange,
Query,
Directive,
forwardRef,
Provider,
Inject,
Optional,
Self
} from 'angular2/core';
} from '@angular/core';
import {EventEmitter, ObservableWrapper} from '../../../src/facade/async';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
import {NgControl} from './ng_control';
import {Control} from '../model';
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
import {NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
import {
setUpControl,
isPropertyUpdated,
@ -22,17 +20,21 @@ import {
composeValidators,
composeAsyncValidators
} from './shared';
import {ValidatorFn, AsyncValidatorFn} from './validators';
const formControlBinding =
CONST_EXPR(new Provider(NgControl, {useExisting: forwardRef(() => NgModel)}));
export const formControlBinding: any =
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
provide: NgControl,
useExisting: forwardRef(() => NgModel)
};
/**
* Binds a domain model to a form control.
*
* ### Usage
*
* `ng-model` binds an existing domain model to a form control. For a
* two-way binding, use `[(ng-model)]` to ensure the model updates in
* `ngModel` binds an existing domain model to a form control. For a
* two-way binding, use `[(ngModel)]` to ensure the model updates in
* both directions.
*
* ### Example ([live demo](http://plnkr.co/edit/R3UX5qDaUqFO2VYR0UzH?p=preview))
@ -40,7 +42,7 @@ const formControlBinding =
* @Component({
* selector: "search-comp",
* directives: [FORM_DIRECTIVES],
* template: `<input type='text' [(ng-model)]="searchQuery">`
* template: `<input type='text' [(ngModel)]="searchQuery">`
* })
* class SearchComp {
* searchQuery: string;
@ -48,7 +50,7 @@ const formControlBinding =
* ```
*/
@Directive({
selector: '[ng-model]:not([ng-control]):not([ng-form-control])',
selector: '[ngModel]:not([ngControl]):not([ngFormControl])',
bindings: [formControlBinding],
inputs: ['model: ngModel'],
outputs: ['update: ngModelChange'],
@ -88,9 +90,9 @@ export class NgModel extends NgControl implements OnChanges {
get path(): string[] { return []; }
get validator(): Function { return composeValidators(this._validators); }
get validator(): ValidatorFn { return composeValidators(this._validators); }
get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); }
get asyncValidator(): AsyncValidatorFn { return composeAsyncValidators(this._asyncValidators); }
viewToModelUpdate(newValue: any): void {
this.viewModel = newValue;

View File

@ -10,3 +10,11 @@ Function normalizeValidator(dynamic validator){
}
}
Function normalizeAsyncValidator(dynamic validator){
if (validator is Validator) {
return (c) => validator.validate(c);
} else {
return validator;
}
}

View File

@ -0,0 +1,18 @@
import {AbstractControl} from '../model';
import {Validator, ValidatorFn, AsyncValidatorFn} from './validators';
export function normalizeValidator(validator: ValidatorFn | Validator): ValidatorFn {
if ((<Validator>validator).validate !== undefined) {
return (c: AbstractControl) => (<Validator>validator).validate(c);
} else {
return <ValidatorFn>validator;
}
}
export function normalizeAsyncValidator(validator: AsyncValidatorFn | Validator): AsyncValidatorFn {
if ((<Validator>validator).validate !== undefined) {
return (c: AbstractControl) => Promise.resolve((<Validator>validator).validate(c));
} else {
return <AsyncValidatorFn>validator;
}
}

View File

@ -1,9 +1,12 @@
import {Directive, ElementRef, Renderer, Self, forwardRef, Provider} from 'angular2/core';
import {Directive, ElementRef, Renderer, Self, forwardRef, Provider} from '@angular/core';
import {NumberWrapper} from '../../../src/facade/lang';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor';
import {isBlank, CONST_EXPR, NumberWrapper} from 'angular2/src/facade/lang';
const NUMBER_VALUE_ACCESSOR = CONST_EXPR(new Provider(
NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => NumberValueAccessor), multi: true}));
export const NUMBER_VALUE_ACCESSOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NumberValueAccessor),
multi: true
};
/**
* The accessor for writing a number value and listening to changes that is used by the
@ -11,12 +14,12 @@ const NUMBER_VALUE_ACCESSOR = CONST_EXPR(new Provider(
*
* ### Example
* ```
* <input type="number" [(ng-model)]="age">
* <input type="number" [(ngModel)]="age">
* ```
*/
@Directive({
selector:
'input[type=number][ng-control],input[type=number][ng-form-control],input[type=number][ng-model]',
'input[type=number][ngControl],input[type=number][ngFormControl],input[type=number][ngModel]',
host: {
'(change)': 'onChange($event.target.value)',
'(input)': 'onChange($event.target.value)',
@ -25,17 +28,17 @@ const NUMBER_VALUE_ACCESSOR = CONST_EXPR(new Provider(
bindings: [NUMBER_VALUE_ACCESSOR]
})
export class NumberValueAccessor implements ControlValueAccessor {
onChange = (_) => {};
onChange = (_: any) => {};
onTouched = () => {};
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
writeValue(value: number): void {
this._renderer.setElementProperty(this._elementRef, 'value', value);
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', value);
}
registerOnChange(fn: (_: number) => void): void {
this.onChange = (value) => { fn(NumberWrapper.parseFloat(value)); };
this.onChange = (value) => { fn(value == '' ? null : NumberWrapper.parseFloat(value)); };
}
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
}

View File

@ -0,0 +1,126 @@
import {
Directive,
ElementRef,
Renderer,
forwardRef,
Provider,
Input,
OnInit,
OnDestroy,
Injector,
Injectable
} from '@angular/core';
import {isPresent} from '../../../src/facade/lang';
import {ListWrapper} from '../../../src/facade/collection';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor';
import {NgControl} from './ng_control';
export const RADIO_VALUE_ACCESSOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RadioControlValueAccessor),
multi: true
};
/**
* Internal class used by Angular to uncheck radio buttons with the matching name.
*/
@Injectable()
export class RadioControlRegistry {
private _accessors: any[] = [];
add(control: NgControl, accessor: RadioControlValueAccessor) {
this._accessors.push([control, accessor]);
}
remove(accessor: RadioControlValueAccessor) {
var indexToRemove = -1;
for (var i = 0; i < this._accessors.length; ++i) {
if (this._accessors[i][1] === accessor) {
indexToRemove = i;
}
}
ListWrapper.removeAt(this._accessors, indexToRemove);
}
select(accessor: RadioControlValueAccessor) {
this._accessors.forEach((c) => {
if (c[0].control.root === accessor._control.control.root && c[1] !== accessor) {
c[1].fireUncheck();
}
});
}
}
/**
* The value provided by the forms API for radio buttons.
*/
export class RadioButtonState {
constructor(public checked: boolean, public value: string) {}
}
/**
* The accessor for writing a radio control value and listening to changes that is used by the
* {@link NgModel}, {@link NgFormControl}, and {@link NgControlName} directives.
*
* ### Example
* ```
* @Component({
* template: `
* <input type="radio" name="food" [(ngModel)]="foodChicken">
* <input type="radio" name="food" [(ngModel)]="foodFish">
* `
* })
* class FoodCmp {
* foodChicken = new RadioButtonState(true, "chicken");
* foodFish = new RadioButtonState(false, "fish");
* }
* ```
*/
@Directive({
selector:
'input[type=radio][ngControl],input[type=radio][ngFormControl],input[type=radio][ngModel]',
host: {'(change)': 'onChange()', '(blur)': 'onTouched()'},
providers: [RADIO_VALUE_ACCESSOR]
})
export class RadioControlValueAccessor implements ControlValueAccessor,
OnDestroy, OnInit {
/** @internal */
_state: RadioButtonState;
/** @internal */
_control: NgControl;
@Input() name: string;
/** @internal */
_fn: Function;
onChange = () => {};
onTouched = () => {};
constructor(private _renderer: Renderer, private _elementRef: ElementRef,
private _registry: RadioControlRegistry, private _injector: Injector) {}
ngOnInit(): void {
this._control = this._injector.get(NgControl);
this._registry.add(this._control, this);
}
ngOnDestroy(): void { this._registry.remove(this); }
writeValue(value: any): void {
this._state = value;
if (isPresent(value) && value.checked) {
this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', true);
}
}
registerOnChange(fn: (_: any) => {}): void {
this._fn = fn;
this.onChange = () => {
fn(new RadioButtonState(true, this._state.value));
this._registry.select(this);
};
}
fireUncheck(): void { this._fn(new RadioButtonState(false, this._state.value)); }
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
}

View File

@ -0,0 +1,139 @@
import {
Directive,
Renderer,
forwardRef,
Provider,
ElementRef,
Input,
Host,
OnDestroy,
Optional
} from '@angular/core';
import {
StringWrapper,
isPrimitive,
isPresent,
isBlank,
looseIdentical
} from '../../../src/facade/lang';
import {MapWrapper} from '../../../src/facade/collection';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from './control_value_accessor';
export const SELECT_VALUE_ACCESSOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SelectControlValueAccessor),
multi: true
};
function _buildValueString(id: string, value: any): string {
if (isBlank(id)) return `${value}`;
if (!isPrimitive(value)) value = "Object";
return StringWrapper.slice(`${id}: ${value}`, 0, 50);
}
function _extractId(valueString: string): string {
return valueString.split(":")[0];
}
/**
* The accessor for writing a value and listening to changes on a select element.
*
* Note: We have to listen to the 'change' event because 'input' events aren't fired
* for selects in Firefox and IE:
* https://bugzilla.mozilla.org/show_bug.cgi?id=1024350
* https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/4660045/
*
*/
@Directive({
selector: 'select[ngControl],select[ngFormControl],select[ngModel]',
host: {'(change)': 'onChange($event.target.value)', '(blur)': 'onTouched()'},
providers: [SELECT_VALUE_ACCESSOR]
})
export class SelectControlValueAccessor implements ControlValueAccessor {
value: any;
/** @internal */
_optionMap: Map<string, any> = new Map<string, any>();
/** @internal */
_idCounter: number = 0;
onChange = (_: any) => {};
onTouched = () => {};
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
writeValue(value: any): void {
this.value = value;
var valueString = _buildValueString(this._getOptionId(value), value);
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', valueString);
}
registerOnChange(fn: (value: any) => any): void {
this.onChange = (valueString: string) => { fn(this._getOptionValue(valueString)); };
}
registerOnTouched(fn: () => any): void { this.onTouched = fn; }
/** @internal */
_registerOption(): string { return (this._idCounter++).toString(); }
/** @internal */
_getOptionId(value: any): string {
for (let id of MapWrapper.keys(this._optionMap)) {
if (looseIdentical(this._optionMap.get(id), value)) return id;
}
return null;
}
/** @internal */
_getOptionValue(valueString: string): any {
let value = this._optionMap.get(_extractId(valueString));
return isPresent(value) ? value : valueString;
}
}
/**
* Marks `<option>` as dynamic, so Angular can be notified when options change.
*
* ### Example
*
* ```
* <select ngControl="city">
* <option *ngFor="let c of cities" [value]="c"></option>
* </select>
* ```
*/
@Directive({selector: 'option'})
export class NgSelectOption implements OnDestroy {
id: string;
constructor(private _element: ElementRef, private _renderer: Renderer,
@Optional() @Host() private _select: SelectControlValueAccessor) {
if (isPresent(this._select)) this.id = this._select._registerOption();
}
@Input('ngValue')
set ngValue(value: any) {
if (this._select == null) return;
this._select._optionMap.set(this.id, value);
this._setElementValue(_buildValueString(this.id, value));
this._select.writeValue(this._select.value);
}
@Input('value')
set value(value: any) {
this._setElementValue(value);
if (isPresent(this._select)) this._select.writeValue(this._select.value);
}
/** @internal */
_setElementValue(value: string): void {
this._renderer.setElementProperty(this._element.nativeElement, 'value', value);
}
ngOnDestroy() {
if (isPresent(this._select)) {
this._select._optionMap.delete(this.id);
this._select.writeValue(this._select.value);
}
}
}

View File

@ -1,6 +1,6 @@
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {isBlank, isPresent, looseIdentical} from 'angular2/src/facade/lang';
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
import {ListWrapper, StringMapWrapper} from '../../../src/facade/collection';
import {isBlank, isPresent, looseIdentical, hasConstructor} from '../../../src/facade/lang';
import {BaseException} from '../../../src/facade/exceptions';
import {ControlContainer} from './control_container';
import {NgControl} from './ng_control';
@ -13,7 +13,9 @@ import {DefaultValueAccessor} from './default_value_accessor';
import {NumberValueAccessor} from './number_value_accessor';
import {CheckboxControlValueAccessor} from './checkbox_value_accessor';
import {SelectControlValueAccessor} from './select_control_value_accessor';
import {normalizeValidator} from './normalize_validator';
import {RadioControlValueAccessor} from './radio_control_value_accessor';
import {normalizeValidator, normalizeAsyncValidator} from './normalize_validator';
import {ValidatorFn, AsyncValidatorFn} from './validators';
export function controlPath(name: string, parent: ControlContainer): string[] {
@ -31,14 +33,14 @@ export function setUpControl(control: Control, dir: NgControl): void {
dir.valueAccessor.writeValue(control.value);
// view -> model
dir.valueAccessor.registerOnChange(newValue => {
dir.valueAccessor.registerOnChange((newValue: any) => {
dir.viewToModelUpdate(newValue);
control.updateValue(newValue, {emitModelToViewChange: false});
control.markAsDirty();
});
// model -> view
control.registerOnChange(newValue => dir.valueAccessor.writeValue(newValue));
control.registerOnChange((newValue: any) => dir.valueAccessor.writeValue(newValue));
// touched
dir.valueAccessor.registerOnTouched(() => control.markAsTouched());
@ -55,13 +57,14 @@ function _throwError(dir: AbstractControlDirective, message: string): void {
throw new BaseException(`${message} '${path}'`);
}
export function composeValidators(validators: /* Array<Validator|Function> */ any[]): Function {
export function composeValidators(validators: /* Array<Validator|Function> */ any[]): ValidatorFn {
return isPresent(validators) ? Validators.compose(validators.map(normalizeValidator)) : null;
}
export function composeAsyncValidators(
validators: /* Array<Validator|Function> */ any[]): Function {
return isPresent(validators) ? Validators.composeAsync(validators.map(normalizeValidator)) : null;
validators: /* Array<Validator|Function> */ any[]): AsyncValidatorFn {
return isPresent(validators) ? Validators.composeAsync(validators.map(normalizeAsyncValidator)) :
null;
}
export function isPropertyUpdated(changes: {[key: string]: any}, viewModel: any): boolean {
@ -77,16 +80,17 @@ export function selectValueAccessor(dir: NgControl,
valueAccessors: ControlValueAccessor[]): ControlValueAccessor {
if (isBlank(valueAccessors)) return null;
var defaultAccessor;
var builtinAccessor;
var customAccessor;
valueAccessors.forEach(v => {
if (v instanceof DefaultValueAccessor) {
var defaultAccessor: ControlValueAccessor;
var builtinAccessor: ControlValueAccessor;
var customAccessor: ControlValueAccessor;
valueAccessors.forEach((v: ControlValueAccessor) => {
if (hasConstructor(v, DefaultValueAccessor)) {
defaultAccessor = v;
} else if (v instanceof CheckboxControlValueAccessor || v instanceof NumberValueAccessor ||
v instanceof SelectControlValueAccessor) {
} else if (hasConstructor(v, CheckboxControlValueAccessor) ||
hasConstructor(v, NumberValueAccessor) ||
hasConstructor(v, SelectControlValueAccessor) ||
hasConstructor(v, RadioControlValueAccessor)) {
if (isPresent(builtinAccessor))
_throwError(dir, "More than one built-in value accessor matches");
builtinAccessor = v;

View File

@ -0,0 +1,150 @@
import {forwardRef, Attribute, Directive} from '@angular/core';
import {NumberWrapper} from '../../facade/lang';
import {Validators, NG_VALIDATORS} from '../validators';
import {AbstractControl} from '../model';
import * as modelModule from '../model';
/**
* An interface that can be implemented by classes that can act as validators.
*
* ## Usage
*
* ```typescript
* @Directive({
* selector: '[custom-validator]',
* providers: [provide(NG_VALIDATORS, {useExisting: CustomValidatorDirective, multi: true})]
* })
* class CustomValidatorDirective implements Validator {
* validate(c: Control): {[key: string]: any} {
* return {"custom": true};
* }
* }
* ```
*/
export interface Validator { validate(c: modelModule.AbstractControl): {[key: string]: any}; }
const REQUIRED = /*@ts2dart_const*/ Validators.required;
export const REQUIRED_VALIDATOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
provide: NG_VALIDATORS,
useValue: REQUIRED,
multi: true
};
/**
* A Directive that adds the `required` validator to any controls marked with the
* `required` attribute, via the {@link NG_VALIDATORS} binding.
*
* ### Example
*
* ```
* <input ngControl="fullName" required>
* ```
*/
@Directive({
selector: '[required][ngControl],[required][ngFormControl],[required][ngModel]',
providers: [REQUIRED_VALIDATOR]
})
export class RequiredValidator {
}
export interface ValidatorFn { (c: AbstractControl): {[key: string]: any}; }
export interface AsyncValidatorFn {
(c: AbstractControl): any /*Promise<{[key: string]: any}>|Observable<{[key: string]: any}>*/;
}
/**
* Provivder which adds {@link MinLengthValidator} to {@link NG_VALIDATORS}.
*
* ## Example:
*
* {@example common/forms/ts/validators/validators.ts region='min'}
*/
export const MIN_LENGTH_VALIDATOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => MinLengthValidator),
multi: true
};
/**
* A directive which installs the {@link MinLengthValidator} for any `ngControl`,
* `ngFormControl`, or control with `ngModel` that also has a `minlength` attribute.
*/
@Directive({
selector: '[minlength][ngControl],[minlength][ngFormControl],[minlength][ngModel]',
providers: [MIN_LENGTH_VALIDATOR]
})
export class MinLengthValidator implements Validator {
private _validator: ValidatorFn;
constructor(@Attribute("minlength") minLength: string) {
this._validator = Validators.minLength(NumberWrapper.parseInt(minLength, 10));
}
validate(c: AbstractControl): {[key: string]: any} { return this._validator(c); }
}
/**
* Provider which adds {@link MaxLengthValidator} to {@link NG_VALIDATORS}.
*
* ## Example:
*
* {@example common/forms/ts/validators/validators.ts region='max'}
*/
export const MAX_LENGTH_VALIDATOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => MaxLengthValidator),
multi: true
};
/**
* A directive which installs the {@link MaxLengthValidator} for any `ngControl, `ngFormControl`,
* or control with `ngModel` that also has a `maxlength` attribute.
*/
@Directive({
selector: '[maxlength][ngControl],[maxlength][ngFormControl],[maxlength][ngModel]',
providers: [MAX_LENGTH_VALIDATOR]
})
export class MaxLengthValidator implements Validator {
private _validator: ValidatorFn;
constructor(@Attribute("maxlength") maxLength: string) {
this._validator = Validators.maxLength(NumberWrapper.parseInt(maxLength, 10));
}
validate(c: AbstractControl): {[key: string]: any} { return this._validator(c); }
}
/**
* A Directive that adds the `pattern` validator to any controls marked with the
* `pattern` attribute, via the {@link NG_VALIDATORS} binding. Uses attribute value
* as the regex to validate Control value against. Follows pattern attribute
* semantics; i.e. regex must match entire Control value.
*
* ### Example
*
* ```
* <input [ngControl]="fullName" pattern="[a-zA-Z ]*">
* ```
*/
export const PATTERN_VALIDATOR: any = /*@ts2dart_const*/ /*@ts2dart_Provider*/ {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => PatternValidator),
multi: true
};
@Directive({
selector: '[pattern][ngControl],[pattern][ngFormControl],[pattern][ngModel]',
providers: [PATTERN_VALIDATOR]
})
export class PatternValidator implements Validator {
private _validator: ValidatorFn;
constructor(@Attribute("pattern") pattern: string) {
this._validator = Validators.pattern(pattern);
}
validate(c: AbstractControl): {[key: string]: any} { return this._validator(c); }
}

View File

@ -1,7 +1,8 @@
import {Injectable} from 'angular2/core';
import {StringMapWrapper} from 'angular2/src/facade/collection';
import {isPresent, isArray, CONST_EXPR, Type} from 'angular2/src/facade/lang';
import {Injectable} from '@angular/core';
import {StringMapWrapper} from '../../src/facade/collection';
import {isPresent, isArray} from '../../src/facade/lang';
import * as modelModule from './model';
import {ValidatorFn, AsyncValidatorFn} from './directives/validators';
/**
@ -14,11 +15,11 @@ import * as modelModule from './model';
* selector: 'my-app',
* viewBindings: [FORM_BINDINGS]
* template: `
* <form [ng-form-model]="loginForm">
* <p>Login <input ng-control="login"></p>
* <div ng-control-group="passwordRetry">
* <p>Password <input type="password" ng-control="password"></p>
* <p>Confirm password <input type="password" ng-control="passwordConfirmation"></p>
* <form [ngFormModel]="loginForm">
* <p>Login <input ngControl="login"></p>
* <div ngControlGroup="passwordRetry">
* <p>Password <input type="password" ngControl="password"></p>
* <p>Confirm password <input type="password" ngControl="passwordConfirmation"></p>
* </div>
* </form>
* <h3>Form value:</h3>
@ -56,16 +57,18 @@ export class FormBuilder {
group(controlsConfig: {[key: string]: any},
extra: {[key: string]: any} = null): modelModule.ControlGroup {
var controls = this._reduceControls(controlsConfig);
var optionals = isPresent(extra) ? StringMapWrapper.get(extra, "optionals") : null;
var validator = isPresent(extra) ? StringMapWrapper.get(extra, "validator") : null;
var asyncValidator = isPresent(extra) ? StringMapWrapper.get(extra, "asyncValidator") : null;
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);
}
/**
* Construct a new {@link Control} with the given `value`,`validator`, and `asyncValidator`.
*/
control(value: Object, validator: Function = null,
asyncValidator: Function = null): modelModule.Control {
control(value: Object, validator: ValidatorFn = null,
asyncValidator: AsyncValidatorFn = null): modelModule.Control {
return new modelModule.Control(value, validator, asyncValidator);
}
@ -73,16 +76,17 @@ export class FormBuilder {
* Construct an array of {@link Control}s from the given `controlsConfig` array of
* configuration, with the given optional `validator` and `asyncValidator`.
*/
array(controlsConfig: any[], validator: Function = null,
asyncValidator: Function = null): modelModule.ControlArray {
array(controlsConfig: any[], validator: ValidatorFn = null,
asyncValidator: AsyncValidatorFn = null): modelModule.ControlArray {
var controls = controlsConfig.map(c => this._createControl(c));
return new modelModule.ControlArray(controls, validator, asyncValidator);
}
/** @internal */
_reduceControls(controlsConfig: any): {[key: string]: modelModule.AbstractControl} {
_reduceControls(controlsConfig: {[k: string]:
any}): {[key: string]: modelModule.AbstractControl} {
var controls: {[key: string]: modelModule.AbstractControl} = {};
StringMapWrapper.forEach(controlsConfig, (controlConfig, controlName) => {
StringMapWrapper.forEach(controlsConfig, (controlConfig: any, controlName: string) => {
controls[controlName] = this._createControl(controlConfig);
});
return controls;
@ -97,8 +101,8 @@ export class FormBuilder {
} else if (isArray(controlConfig)) {
var value = controlConfig[0];
var validator = controlConfig.length > 1 ? controlConfig[1] : null;
var asyncValidator = controlConfig.length > 2 ? controlConfig[2] : null;
var validator: ValidatorFn = controlConfig.length > 1 ? controlConfig[1] : null;
var asyncValidator: AsyncValidatorFn = controlConfig.length > 2 ? controlConfig[2] : null;
return this.control(value, validator, asyncValidator);
} else {
@ -106,19 +110,3 @@ export class FormBuilder {
}
}
}
/**
* Shorthand set of providers used for building Angular forms.
*
* ### Example
*
* ```typescript
* bootstrap(MyApp, [FORM_PROVIDERS]);
* ```
*/
export const FORM_PROVIDERS: Type[] = CONST_EXPR([FormBuilder]);
/**
* @deprecated
*/
export const FORM_BINDINGS = FORM_PROVIDERS;

View File

@ -1,7 +1,8 @@
import {StringWrapper, isPresent, isBlank, normalizeBool} from 'angular2/src/facade/lang';
import {Observable, EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
import {PromiseWrapper} from 'angular2/src/facade/promise';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {isPresent, isBlank, normalizeBool} from '../../src/facade/lang';
import {Observable, EventEmitter, ObservableWrapper} from '../../src/facade/async';
import {PromiseWrapper} from '../../src/facade/promise';
import {StringMapWrapper, ListWrapper} from '../../src/facade/collection';
import {ValidatorFn, AsyncValidatorFn} from './directives/validators';
/**
* Indicates that a Control is valid, i.e. that no errors exist in the input value.
@ -14,7 +15,7 @@ export const VALID = "VALID";
export const INVALID = "INVALID";
/**
* Indicates that a Control is pending, i.e. that async validation is occuring and
* Indicates that a Control is pending, i.e. that async validation is occurring and
* errors are not yet available for the input value.
*/
export const PENDING = "PENDING";
@ -62,9 +63,9 @@ export abstract class AbstractControl {
private _pristine: boolean = true;
private _touched: boolean = false;
private _parent: ControlGroup | ControlArray;
private _asyncValidationSubscription;
private _asyncValidationSubscription: any;
constructor(public validator: Function, public asyncValidator: Function) {}
constructor(public validator: ValidatorFn, public asyncValidator: AsyncValidatorFn) {}
get value(): any { return this._value; }
@ -137,15 +138,17 @@ export abstract class AbstractControl {
}
}
private _runValidator() { return isPresent(this.validator) ? this.validator(this) : null; }
private _runValidator(): {[key: string]: any} {
return isPresent(this.validator) ? this.validator(this) : null;
}
private _runAsyncValidator(emitEvent: boolean): void {
if (isPresent(this.asyncValidator)) {
this._status = PENDING;
this._cancelExistingSubscription();
var obs = toObservable(this.asyncValidator(this));
this._asyncValidationSubscription =
ObservableWrapper.subscribe(obs, res => this.setErrors(res, {emitEvent: emitEvent}));
this._asyncValidationSubscription = ObservableWrapper.subscribe(
obs, (res: {[key: string]: any}) => this.setErrors(res, {emitEvent: emitEvent}));
}
}
@ -208,6 +211,16 @@ export abstract class AbstractControl {
return isPresent(this.getError(errorCode, path));
}
get root(): AbstractControl {
let x: AbstractControl = this;
while (isPresent(x._parent)) {
x = x._parent;
}
return x;
}
/** @internal */
_updateControlsErrors(): void {
this._status = this._calculateStatus();
@ -258,7 +271,8 @@ export class Control extends AbstractControl {
/** @internal */
_onChange: Function;
constructor(value: any = null, validator: Function = null, asyncValidator: Function = null) {
constructor(value: any = null, validator: ValidatorFn = null,
asyncValidator: AsyncValidatorFn = null) {
super(validator, asyncValidator);
this._value = value;
this.updateValueAndValidity({onlySelf: true, emitEvent: false});
@ -307,9 +321,10 @@ export class Control extends AbstractControl {
/**
* Defines a part of a form, of fixed length, that can contain other controls.
*
* A `ControlGroup` aggregates the values and errors of each {@link Control} in the group. Thus, if
* one of the controls in a group is invalid, the entire group is invalid. Similarly, if a control
* changes its value, the entire group changes as well.
* A `ControlGroup` aggregates the values of each {@link Control} in the group.
* The status of a `ControlGroup` depends on the status of its children.
* If one of the controls in a group is invalid, the entire group is invalid.
* Similarly, if a control changes its value, the entire group changes as well.
*
* `ControlGroup` is one of the three fundamental building blocks used to define forms in Angular,
* along with {@link Control} and {@link ControlArray}. {@link ControlArray} can also contain other
@ -321,8 +336,8 @@ export class ControlGroup extends AbstractControl {
private _optionals: {[key: string]: boolean};
constructor(public controls: {[key: string]: AbstractControl},
optionals: {[key: string]: boolean} = null, validator: Function = null,
asyncValidator: Function = null) {
optionals: {[key: string]: boolean} = null, validator: ValidatorFn = null,
asyncValidator: AsyncValidatorFn = null) {
super(validator, asyncValidator);
this._optionals = isPresent(optionals) ? optionals : {};
this._initObservables();
@ -369,7 +384,8 @@ export class ControlGroup extends AbstractControl {
/** @internal */
_setParentForControls() {
StringMapWrapper.forEach(this.controls, (control, name) => { control.setParent(this); });
StringMapWrapper.forEach(
this.controls, (control: AbstractControl, name: string) => { control.setParent(this); });
}
/** @internal */
@ -378,7 +394,7 @@ export class ControlGroup extends AbstractControl {
/** @internal */
_anyControlsHaveStatus(status: string): boolean {
var res = false;
StringMapWrapper.forEach(this.controls, (control, name) => {
StringMapWrapper.forEach(this.controls, (control: AbstractControl, name: string) => {
res = res || (this.contains(name) && control.status == status);
});
return res;
@ -386,16 +402,17 @@ export class ControlGroup extends AbstractControl {
/** @internal */
_reduceValue() {
return this._reduceChildren({}, (acc, control, name) => {
acc[name] = control.value;
return acc;
});
return this._reduceChildren(
{}, (acc: {[k: string]: AbstractControl}, control: AbstractControl, name: string) => {
acc[name] = control.value;
return acc;
});
}
/** @internal */
_reduceChildren(initValue: any, fn: Function) {
var res = initValue;
StringMapWrapper.forEach(this.controls, (control, name) => {
StringMapWrapper.forEach(this.controls, (control: AbstractControl, name: string) => {
if (this._included(name)) {
res = fn(res, control, name);
}
@ -413,9 +430,10 @@ export class ControlGroup extends AbstractControl {
/**
* Defines a part of a form, of variable length, that can contain other controls.
*
* A `ControlArray` aggregates the values and errors of each {@link Control} in the group. Thus, if
* one of the controls in a group is invalid, the entire group is invalid. Similarly, if a control
* changes its value, the entire group changes as well.
* A `ControlArray` aggregates the values of each {@link Control} in the group.
* The status of a `ControlArray` depends on the status of its children.
* If one of the controls in a group is invalid, the entire array is invalid.
* Similarly, if a control changes its value, the entire array changes as well.
*
* `ControlArray` is one of the three fundamental building blocks used to define forms in Angular,
* along with {@link Control} and {@link ControlGroup}. {@link ControlGroup} can also contain
@ -432,8 +450,8 @@ export class ControlGroup extends AbstractControl {
* ### Example ([live demo](http://plnkr.co/edit/23DESOpbNnBpBHZt1BR4?p=preview))
*/
export class ControlArray extends AbstractControl {
constructor(public controls: AbstractControl[], validator: Function = null,
asyncValidator: Function = null) {
constructor(public controls: AbstractControl[], validator: ValidatorFn = null,
asyncValidator: AsyncValidatorFn = null) {
super(validator, asyncValidator);
this._initObservables();
this._setParentForControls();

View File

@ -0,0 +1,144 @@
import {OpaqueToken} from '@angular/core';
import {isBlank, isPresent, isString} from '../../src/facade/lang';
import {PromiseWrapper} from '../../src/facade/promise';
import {ObservableWrapper} from '../../src/facade/async';
import {StringMapWrapper} from '../../src/facade/collection';
import * as modelModule from './model';
import {ValidatorFn, AsyncValidatorFn} from './directives/validators';
/**
* Providers for validators to be used for {@link Control}s in a form.
*
* Provide this using `multi: true` to add validators.
*
* ### Example
*
* {@example core/forms/ts/ng_validators/ng_validators.ts region='ng_validators'}
*/
export const NG_VALIDATORS: OpaqueToken = /*@ts2dart_const*/ new OpaqueToken("NgValidators");
/**
* Providers for asynchronous validators to be used for {@link Control}s
* in a form.
*
* Provide this using `multi: true` to add validators.
*
* See {@link NG_VALIDATORS} for more details.
*/
export const NG_ASYNC_VALIDATORS: OpaqueToken =
/*@ts2dart_const*/ new OpaqueToken("NgAsyncValidators");
/**
* Provides a set of validators used by form controls.
*
* A validator is a function that processes a {@link Control} or collection of
* controls and returns a map of errors. A null map means that validation has passed.
*
* ### Example
*
* ```typescript
* var loginControl = new Control("", Validators.required)
* ```
*/
export class Validators {
/**
* Validator that requires controls to have a non-empty value.
*/
static required(control: modelModule.AbstractControl): {[key: string]: boolean} {
return isBlank(control.value) || (isString(control.value) && control.value == "") ?
{"required": true} :
null;
}
/**
* Validator that requires controls to have a value of a minimum length.
*/
static minLength(minLength: number): ValidatorFn {
return (control: modelModule.AbstractControl): {[key: string]: any} => {
if (isPresent(Validators.required(control))) return null;
var v: string = control.value;
return v.length < minLength ?
{"minlength": {"requiredLength": minLength, "actualLength": v.length}} :
null;
};
}
/**
* Validator that requires controls to have a value of a maximum length.
*/
static maxLength(maxLength: number): ValidatorFn {
return (control: modelModule.AbstractControl): {[key: string]: any} => {
if (isPresent(Validators.required(control))) return null;
var v: string = control.value;
return v.length > maxLength ?
{"maxlength": {"requiredLength": maxLength, "actualLength": v.length}} :
null;
};
}
/**
* Validator that requires a control to match a regex to its value.
*/
static pattern(pattern: string): ValidatorFn {
return (control: modelModule.AbstractControl): {[key: string]: any} => {
if (isPresent(Validators.required(control))) return null;
let regex = new RegExp(`^${pattern}$`);
let v: string = control.value;
return regex.test(v) ? null :
{"pattern": {"requiredPattern": `^${pattern}$`, "actualValue": v}};
};
}
/**
* No-op validator.
*/
static nullValidator(c: modelModule.AbstractControl): {[key: string]: boolean} { return null; }
/**
* Compose multiple validators into a single function that returns the union
* of the individual error maps.
*/
static compose(validators: ValidatorFn[]): ValidatorFn {
if (isBlank(validators)) return null;
var presentValidators = validators.filter(isPresent);
if (presentValidators.length == 0) return null;
return function(control: modelModule.AbstractControl) {
return _mergeErrors(_executeValidators(control, presentValidators));
};
}
static composeAsync(validators: AsyncValidatorFn[]): AsyncValidatorFn {
if (isBlank(validators)) return null;
var presentValidators = validators.filter(isPresent);
if (presentValidators.length == 0) return null;
return function(control: modelModule.AbstractControl) {
let promises = _executeAsyncValidators(control, presentValidators).map(_convertToPromise);
return PromiseWrapper.all(promises).then(_mergeErrors);
};
}
}
function _convertToPromise(obj: any): any {
return PromiseWrapper.isPromise(obj) ? obj : ObservableWrapper.toPromise(obj);
}
function _executeValidators(control: modelModule.AbstractControl,
validators: ValidatorFn[]): any[] {
return validators.map(v => v(control));
}
function _executeAsyncValidators(control: modelModule.AbstractControl,
validators: AsyncValidatorFn[]): any[] {
return validators.map(v => v(control));
}
function _mergeErrors(arrayOfErrors: any[]): {[key: string]: any} {
var res: {[key: string]: any} =
arrayOfErrors.reduce((res: {[key: string]: any}, errors: {[key: string]: any}) => {
return isPresent(errors) ? StringMapWrapper.merge(res, errors) : res;
}, {});
return StringMapWrapper.isEmpty(res) ? null : res;
}

View File

@ -0,0 +1,5 @@
export * from './location/platform_location';
export * from './location/location_strategy';
export * from './location/hash_location_strategy';
export * from './location/path_location_strategy';
export * from './location/location';

View File

@ -1,13 +1,10 @@
import {Injectable, Inject, Optional} from 'angular2/core';
import {
LocationStrategy,
joinWithSlash,
APP_BASE_HREF,
normalizeQueryParams
} from './location_strategy';
import {EventListener} from 'angular2/src/facade/browser';
import {isPresent} from 'angular2/src/facade/lang';
import {PlatformLocation} from './platform_location';
import {Injectable, Inject, Optional} from '@angular/core';
import {isPresent} from '../../src/facade/lang';
import {LocationStrategy, APP_BASE_HREF} from './location_strategy';
import {Location} from './location';
import {UrlChangeListener, PlatformLocation} from './platform_location';
/**
* `HashLocationStrategy` is a {@link LocationStrategy} used to configure the
@ -21,15 +18,17 @@ import {PlatformLocation} from './platform_location';
* ### Example
*
* ```
* import {Component, provide} from 'angular2/angular2';
* import {Component, provide} from '@angular/core';
* import {
* ROUTER_DIRECTIVES,
* ROUTER_PROVIDERS,
* RouteConfig,
* Location,
* LocationStrategy,
* HashLocationStrategy
* } from 'angular2/router';
* } from '@angular/common';
* import {
* ROUTER_DIRECTIVES,
* ROUTER_PROVIDERS,
* RouteConfig
* } from '@angular/router';
*
* @Component({directives: [ROUTER_DIRECTIVES]})
* @RouteConfig([
@ -58,7 +57,7 @@ export class HashLocationStrategy extends LocationStrategy {
}
}
onPopState(fn: EventListener): void {
onPopState(fn: UrlChangeListener): void {
this._platformLocation.onPopState(fn);
this._platformLocation.onHashChange(fn);
}
@ -69,21 +68,21 @@ export class HashLocationStrategy extends LocationStrategy {
// 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) +
normalizeQueryParams(this._platformLocation.search);
return (path.length > 0 ? path.substring(1) : path);
}
prepareExternalUrl(internal: string): string {
var url = joinWithSlash(this._baseHref, internal);
var url = Location.joinWithSlash(this._baseHref, internal);
return url.length > 0 ? ('#' + url) : url;
}
pushState(state: any, title: string, path: string, queryParams: string) {
var url = this.prepareExternalUrl(path + normalizeQueryParams(queryParams));
var url = this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams));
if (url.length == 0) {
url = this._platformLocation.pathname;
}
@ -91,7 +90,7 @@ export class HashLocationStrategy extends LocationStrategy {
}
replaceState(state: any, title: string, path: string, queryParams: string) {
var url = this.prepareExternalUrl(path + normalizeQueryParams(queryParams));
var url = this.prepareExternalUrl(path + Location.normalizeQueryParams(queryParams));
if (url.length == 0) {
url = this._platformLocation.pathname;
}

View File

@ -1,6 +1,7 @@
import {Injectable, Inject} from '@angular/core';
import {EventEmitter, ObservableWrapper} from '../../src/facade/async';
import {LocationStrategy} from './location_strategy';
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
import {Injectable, Inject} from 'angular2/core';
/**
* `Location` is a service that applications can use to interact with a browser's URL.
@ -21,13 +22,13 @@ import {Injectable, Inject} from 'angular2/core';
* ### Example
*
* ```
* import {Component} from 'angular2/angular2';
* import {Component} from '@angular/core';
* import {Location} from '@angular/common';
* import {
* ROUTER_DIRECTIVES,
* ROUTER_PROVIDERS,
* RouteConfig,
* Location
* } from 'angular2/router';
* RouteConfig
* } from '@angular/router';
*
* @Component({directives: [ROUTER_DIRECTIVES]})
* @RouteConfig([
@ -51,7 +52,7 @@ export class Location {
constructor(public platformStrategy: LocationStrategy) {
var browserBaseHref = this.platformStrategy.getBaseHref();
this._baseHref = stripTrailingSlash(stripIndexHtml(browserBaseHref));
this._baseHref = Location.stripTrailingSlash(_stripIndexHtml(browserBaseHref));
this.platformStrategy.onPopState((ev) => {
ObservableWrapper.callEmit(this._subject, {'url': this.path(), 'pop': true, 'type': ev.type});
});
@ -67,7 +68,7 @@ export class Location {
* trailing slashes
*/
normalize(url: string): string {
return stripTrailingSlash(_stripBaseHref(this._baseHref, stripIndexHtml(url)));
return Location.stripTrailingSlash(_stripBaseHref(this._baseHref, _stripIndexHtml(url)));
}
/**
@ -117,6 +118,50 @@ export class Location {
onReturn: () => void = null): Object {
return ObservableWrapper.subscribe(this._subject, onNext, onThrow, onReturn);
}
/**
* Given a string of url parameters, prepend with '?' if needed, otherwise return parameters as
* is.
*/
public static normalizeQueryParams(params: string): string {
return (params.length > 0 && params.substring(0, 1) != '?') ? ('?' + params) : params;
}
/**
* Given 2 parts of a url, join them with a slash if needed.
*/
public static joinWithSlash(start: string, end: string): string {
if (start.length == 0) {
return end;
}
if (end.length == 0) {
return start;
}
var slashes = 0;
if (start.endsWith('/')) {
slashes++;
}
if (end.startsWith('/')) {
slashes++;
}
if (slashes == 2) {
return start + end.substring(1);
}
if (slashes == 1) {
return start + end;
}
return start + '/' + end;
}
/**
* If url has a trailing slash, remove it, otherwise return url as is.
*/
public static stripTrailingSlash(url: string): string {
if (/\/$/g.test(url)) {
url = url.substring(0, url.length - 1);
}
return url;
}
}
function _stripBaseHref(baseHref: string, url: string): string {
@ -126,17 +171,10 @@ function _stripBaseHref(baseHref: string, url: string): string {
return url;
}
function stripIndexHtml(url: string): string {
function _stripIndexHtml(url: string): string {
if (/\/index.html$/g.test(url)) {
// '/index.html'.length == 11
return url.substring(0, url.length - 11);
}
return url;
}
function stripTrailingSlash(url: string): string {
if (/\/$/g.test(url)) {
url = url.substring(0, url.length - 1);
}
return url;
}

View File

@ -1,10 +1,10 @@
import {CONST_EXPR} from 'angular2/src/facade/lang';
import {OpaqueToken} from 'angular2/core';
import {OpaqueToken} from '@angular/core';
import {UrlChangeListener} from './platform_location';
/**
* `LocationStrategy` is responsible for representing and reading route state
* from the browser's URL. Angular provides two strategies:
* {@link HashLocationStrategy} (default) and {@link PathLocationStrategy}.
* {@link HashLocationStrategy} and {@link PathLocationStrategy} (default).
*
* This is used under the hood of the {@link Location} service.
*
@ -24,7 +24,7 @@ export abstract class LocationStrategy {
abstract replaceState(state: any, title: string, url: string, queryParams: string): void;
abstract forward(): void;
abstract back(): void;
abstract onPopState(fn: (_: any) => any): void;
abstract onPopState(fn: UrlChangeListener): void;
abstract getBaseHref(): string;
}
@ -40,8 +40,9 @@ export abstract class LocationStrategy {
* ### Example
*
* ```
* import {Component} from 'angular2/angular2';
* import {ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig} from 'angular2/router';
* import {Component} from '@angular/core';
* import {ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig} from '@angular/router';
* import {APP_BASE_HREF} from '@angular/common';
*
* @Component({directives: [ROUTER_DIRECTIVES]})
* @RouteConfig([
@ -53,36 +54,8 @@ export abstract class LocationStrategy {
*
* bootstrap(AppCmp, [
* ROUTER_PROVIDERS,
* PathLocationStrategy,
* provide(APP_BASE_HREF, {useValue: '/my/app'})
* ]);
* ```
*/
export const APP_BASE_HREF: OpaqueToken = CONST_EXPR(new OpaqueToken('appBaseHref'));
export function normalizeQueryParams(params: string): string {
return (params.length > 0 && params.substring(0, 1) != '?') ? ('?' + params) : params;
}
export function joinWithSlash(start: string, end: string): string {
if (start.length == 0) {
return end;
}
if (end.length == 0) {
return start;
}
var slashes = 0;
if (start.endsWith('/')) {
slashes++;
}
if (end.startsWith('/')) {
slashes++;
}
if (slashes == 2) {
return start + end.substring(1);
}
if (slashes == 1) {
return start + end;
}
return start + '/' + end;
}
export const APP_BASE_HREF: OpaqueToken = /*@ts2dart_const*/ new OpaqueToken('appBaseHref');

View File

@ -1,14 +1,10 @@
import {Injectable, Inject, Optional} from 'angular2/core';
import {EventListener, History, Location} from 'angular2/src/facade/browser';
import {isBlank} from 'angular2/src/facade/lang';
import {BaseException} from 'angular2/src/facade/exceptions';
import {
LocationStrategy,
APP_BASE_HREF,
normalizeQueryParams,
joinWithSlash
} from './location_strategy';
import {PlatformLocation} from './platform_location';
import {Injectable, Inject, Optional} from '@angular/core';
import {isBlank} from '../../src/facade/lang';
import {BaseException} from '../../src/facade/exceptions';
import {PlatformLocation, UrlChangeListener} from './platform_location';
import {LocationStrategy, APP_BASE_HREF} from './location_strategy';
import {Location} from './location';
/**
* `PathLocationStrategy` is a {@link LocationStrategy} used to configure the
@ -30,14 +26,17 @@ import {PlatformLocation} from './platform_location';
* ### Example
*
* ```
* import {Component, provide} from 'angular2/angular2';
* import {Component, provide} from '@angular/core';
* import {bootstrap} from '@angular/platform-browser/browser';
* import {
* Location,
* APP_BASE_HREF
* } from '@angular/common';
* import {
* ROUTER_DIRECTIVES,
* ROUTER_PROVIDERS,
* RouteConfig,
* Location
* } from 'angular2/router';
* RouteConfig
* } from '@angular/router';
*
* @Component({directives: [ROUTER_DIRECTIVES]})
* @RouteConfig([
@ -75,26 +74,29 @@ export class PathLocationStrategy extends LocationStrategy {
this._baseHref = href;
}
onPopState(fn: EventListener): void {
onPopState(fn: UrlChangeListener): void {
this._platformLocation.onPopState(fn);
this._platformLocation.onHashChange(fn);
}
getBaseHref(): string { return this._baseHref; }
prepareExternalUrl(internal: string): string { return joinWithSlash(this._baseHref, internal); }
prepareExternalUrl(internal: string): string {
return Location.joinWithSlash(this._baseHref, internal);
}
path(): string {
return this._platformLocation.pathname + normalizeQueryParams(this._platformLocation.search);
return this._platformLocation.pathname +
Location.normalizeQueryParams(this._platformLocation.search);
}
pushState(state: any, title: string, url: string, queryParams: string) {
var externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams));
var externalUrl = this.prepareExternalUrl(url + Location.normalizeQueryParams(queryParams));
this._platformLocation.pushState(state, title, externalUrl);
}
replaceState(state: any, title: string, url: string, queryParams: string) {
var externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams));
var externalUrl = this.prepareExternalUrl(url + Location.normalizeQueryParams(queryParams));
this._platformLocation.replaceState(state, title, externalUrl);
}

View File

@ -0,0 +1,48 @@
/**
* This class should not be used directly by an application developer. Instead, use
* {@link Location}.
*
* `PlatformLocation` encapsulates all calls to DOM apis, which allows the Router to be platform
* agnostic.
* This means that we can have different implementation of `PlatformLocation` for the different
* platforms
* that angular supports. For example, the default `PlatformLocation` is {@link
* BrowserPlatformLocation},
* however when you run your app in a WebWorker you use {@link WebWorkerPlatformLocation}.
*
* The `PlatformLocation` class is used directly by all implementations of {@link LocationStrategy}
* when
* they need to interact with the DOM apis like pushState, popState, etc...
*
* {@link LocationStrategy} in turn is used by the {@link Location} service which is used directly
* by
* the {@link Router} in order to navigate between routes. Since all interactions between {@link
* Router} /
* {@link Location} / {@link LocationStrategy} and DOM apis flow through the `PlatformLocation`
* class
* they are all platform independent.
*/
export abstract class PlatformLocation {
abstract getBaseHrefFromDOM(): string;
abstract onPopState(fn: UrlChangeListener): void;
abstract onHashChange(fn: UrlChangeListener): void;
/* abstract */ get pathname(): string { return null; }
/* abstract */ get search(): string { return null; }
/* abstract */ get hash(): string { return null; }
abstract replaceState(state: any, title: string, url: string): void;
abstract pushState(state: any, title: string, url: string): void;
abstract forward(): void;
abstract back(): void;
}
/**
* A serializable version of the event from onPopState or onHashChange
*/
export interface UrlChangeEvent { type: string; }
export interface UrlChangeListener { (e: UrlChangeEvent): any; }

View File

@ -0,0 +1,17 @@
/**
* @module
* @description
* This module provides a set of common Pipes.
*/
export {AsyncPipe} from './pipes/async_pipe';
export {DatePipe} from './pipes/date_pipe';
export {JsonPipe} from './pipes/json_pipe';
export {SlicePipe} from './pipes/slice_pipe';
export {LowerCasePipe} from './pipes/lowercase_pipe';
export {NumberPipe, DecimalPipe, PercentPipe, CurrencyPipe} from './pipes/number_pipe';
export {UpperCasePipe} from './pipes/uppercase_pipe';
export {ReplacePipe} from './pipes/replace_pipe';
export {I18nPluralPipe} from './pipes/i18n_plural_pipe';
export {I18nSelectPipe} from './pipes/i18n_select_pipe';
export {COMMON_PIPES} from './pipes/common_pipes';

View File

@ -1,13 +1,7 @@
import {isBlank, isPresent, isPromise, CONST} from 'angular2/src/facade/lang';
import {Promise, ObservableWrapper, Observable, EventEmitter} from 'angular2/src/facade/async';
import {
Pipe,
Injectable,
ChangeDetectorRef,
OnDestroy,
PipeTransform,
WrappedValue
} from 'angular2/core';
import {Pipe, Injectable, ChangeDetectorRef, OnDestroy, WrappedValue} from '@angular/core';
import {isBlank, isPresent, isPromise} from '../../src/facade/lang';
import {ObservableWrapper, Observable, EventEmitter} from '../../src/facade/async';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
@ -22,7 +16,7 @@ class ObservableStrategy {
}
class PromiseStrategy {
createSubscription(async: any, updateLatestValue: any): any {
createSubscription(async: Promise<any>, updateLatestValue: (v: any) => any): any {
return async.then(updateLatestValue);
}
@ -33,7 +27,7 @@ class PromiseStrategy {
var _promiseStrategy = new PromiseStrategy();
var _observableStrategy = new ObservableStrategy();
var __unused: Promise<any>; // avoid unused import when Promise union types are erased
/**
* The `async` pipe subscribes to an Observable or Promise and returns the latest value it has
@ -55,7 +49,7 @@ var _observableStrategy = new ObservableStrategy();
*/
@Pipe({name: 'async', pure: false})
@Injectable()
export class AsyncPipe implements PipeTransform, OnDestroy {
export class AsyncPipe implements OnDestroy {
/** @internal */
_latestValue: Object = null;
/** @internal */
@ -76,12 +70,13 @@ export class AsyncPipe implements PipeTransform, OnDestroy {
}
}
transform(obj: Observable<any>| Promise<any>| EventEmitter<any>, args?: any[]): any {
transform(obj: Observable<any>| Promise<any>| EventEmitter<any>): any {
if (isBlank(this._obj)) {
if (isPresent(obj)) {
this._subscribe(obj);
}
return null;
this._latestReturnedValue = this._latestValue;
return this._latestValue;
}
if (obj !== this._obj) {
@ -101,8 +96,8 @@ export class AsyncPipe implements PipeTransform, OnDestroy {
_subscribe(obj: Observable<any>| Promise<any>| EventEmitter<any>): void {
this._obj = obj;
this._strategy = this._selectStrategy(obj);
this._subscription =
this._strategy.createSubscription(obj, value => this._updateLatestValue(obj, value));
this._subscription = this._strategy.createSubscription(
obj, (value: Object) => this._updateLatestValue(obj, value));
}
/** @internal */

View File

@ -10,9 +10,18 @@ import {JsonPipe} from './json_pipe';
import {SlicePipe} from './slice_pipe';
import {DatePipe} from './date_pipe';
import {DecimalPipe, PercentPipe, CurrencyPipe} from './number_pipe';
import {CONST_EXPR} from 'angular2/src/facade/lang';
import {ReplacePipe} from './replace_pipe';
import {I18nPluralPipe} from './i18n_plural_pipe';
import {I18nSelectPipe} from './i18n_select_pipe';
export const COMMON_PIPES = CONST_EXPR([
/**
* A collection of Angular core pipes that are likely to be used in each and every
* application.
*
* This collection can be used to quickly enumerate all the built-in pipes in the `pipes`
* property of the `@Component` decorator.
*/
export const COMMON_PIPES = /*@ts2dart_const*/[
AsyncPipe,
UpperCasePipe,
LowerCasePipe,
@ -21,5 +30,8 @@ export const COMMON_PIPES = CONST_EXPR([
DecimalPipe,
PercentPipe,
CurrencyPipe,
DatePipe
]);
DatePipe,
ReplacePipe,
I18nPluralPipe,
I18nSelectPipe
];

View File

@ -1,16 +1,12 @@
import {PipeTransform, Pipe, Injectable} from '@angular/core';
import {
isDate,
isNumber,
isPresent,
Date,
DateWrapper,
CONST,
isBlank,
FunctionWrapper
} from 'angular2/src/facade/lang';
import {DateFormatter} from 'angular2/src/facade/intl';
import {PipeTransform, WrappedValue, Pipe, Injectable} from 'angular2/core';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
} from '../../src/facade/lang';
import {DateFormatter} from '../../src/facade/intl';
import {StringMapWrapper} from '../../src/facade/collection';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
@ -84,7 +80,6 @@ var defaultLocale: string = 'en-US';
*
* {@example core/pipes/ts/date_pipe/date_pipe_example.ts region='DatePipe'}
*/
@CONST()
@Pipe({name: 'date', pure: true})
@Injectable()
export class DatePipe implements PipeTransform {
@ -101,14 +96,13 @@ export class DatePipe implements PipeTransform {
};
transform(value: any, args: any[]): string {
transform(value: any, pattern: string = 'mediumDate'): string {
if (isBlank(value)) return null;
if (!this.supports(value)) {
throw new InvalidPipeArgumentException(DatePipe, value);
}
var pattern: string = isPresent(args) && args.length > 0 ? args[0] : 'mediumDate';
if (isNumber(value)) {
value = DateWrapper.fromMillis(value);
}

View File

@ -0,0 +1,54 @@
import {Injectable, PipeTransform, Pipe} from '@angular/core';
import {isStringMap, StringWrapper, isPresent, RegExpWrapper} from '../../src/facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
var interpolationExp: RegExp = RegExpWrapper.create('#');
/**
*
* 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.
*
* ## Example
*
* ```
* <div>
* {{ messages.length | i18nPlural: messageMapping }}
* </div>
*
* class MyApp {
* messages: any[];
* messageMapping: any = {
* '=0': 'No messages.',
* '=1': 'One message.',
* 'other': '# messages.'
* }
* ...
* }
* ```
*
*/
@Pipe({name: 'i18nPlural', pure: true})
@Injectable()
export class I18nPluralPipe implements PipeTransform {
transform(value: number, pluralMap: {[count: string]: string}): string {
var key: string;
var valueStr: string;
if (!isStringMap(pluralMap)) {
throw new InvalidPipeArgumentException(I18nPluralPipe, pluralMap);
}
key = value === 0 || value === 1 ? `=${value}` : 'other';
valueStr = isPresent(value) ? value.toString() : '';
return StringWrapper.replaceAll(pluralMap[key], interpolationExp, valueStr);
}
}

View File

@ -0,0 +1,45 @@
import {Injectable, PipeTransform, Pipe} from '@angular/core';
import {isStringMap} from '../../src/facade/lang';
import {StringMapWrapper} from '../../src/facade/collection';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
/**
*
* Generic selector that displays the string that matches the current value.
*
* ## Usage
*
* expression | i18nSelect:mapping
*
* where `mapping` is an object that indicates the text that should be displayed
* for different values of the provided `expression`.
*
* ## Example
*
* ```
* <div>
* {{ gender | i18nSelect: inviteMap }}
* </div>
*
* class MyApp {
* gender: string = 'male';
* inviteMap: any = {
* 'male': 'Invite her.',
* 'female': 'Invite him.',
* 'other': 'Invite them.'
* }
* ...
* }
* ```
*/
@Pipe({name: 'i18nSelect', pure: true})
@Injectable()
export class I18nSelectPipe implements PipeTransform {
transform(value: string, mapping: {[key: string]: string}): string {
if (!isStringMap(mapping)) {
throw new InvalidPipeArgumentException(I18nSelectPipe, mapping);
}
return StringMapWrapper.contains(mapping, value) ? mapping[value] : mapping['other'];
}
}

View File

@ -1,5 +1,5 @@
import {CONST, Type, stringify} from 'angular2/src/facade/lang';
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
import {Type, stringify} from '../../src/facade/lang';
import {BaseException} from '../../src/facade/exceptions';
export class InvalidPipeArgumentException extends BaseException {
constructor(type: Type, value: Object) {

View File

@ -1,5 +1,6 @@
import {isBlank, isPresent, Json, CONST} from 'angular2/src/facade/lang';
import {Injectable, PipeTransform, WrappedValue, Pipe} from 'angular2/core';
import {Injectable, PipeTransform, WrappedValue, Pipe} from '@angular/core';
import {Json} from '../../src/facade/lang';
/**
* Transforms any input value using `JSON.stringify`. Useful for debugging.
@ -7,9 +8,9 @@ import {Injectable, PipeTransform, WrappedValue, Pipe} from 'angular2/core';
* ### Example
* {@example core/pipes/ts/json_pipe/json_pipe_example.ts region='JsonPipe'}
*/
@CONST()
/* @ts2dart_const */
@Pipe({name: 'json', pure: false})
@Injectable()
export class JsonPipe implements PipeTransform {
transform(value: any, args: any[] = null): string { return Json.stringify(value); }
transform(value: any): string { return Json.stringify(value); }
}

View File

@ -1,5 +1,5 @@
import {isString, CONST, isBlank} from 'angular2/src/facade/lang';
import {Injectable, PipeTransform, WrappedValue, Pipe} from 'angular2/core';
import {Injectable, PipeTransform, WrappedValue, Pipe} from '@angular/core';
import {isString, isBlank} from '../../src/facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
/**
@ -9,11 +9,11 @@ import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
*
* {@example core/pipes/ts/lowerupper_pipe/lowerupper_pipe_example.ts region='LowerUpperPipe'}
*/
@CONST()
/* @ts2dart_const */
@Pipe({name: 'lowercase'})
@Injectable()
export class LowerCasePipe implements PipeTransform {
transform(value: string, args: any[] = null): string {
transform(value: string): string {
if (isBlank(value)) return value;
if (!isString(value)) {
throw new InvalidPipeArgumentException(LowerCasePipe, value);

View File

@ -1,17 +1,15 @@
import {Injectable, PipeTransform, WrappedValue, Pipe} from '@angular/core';
import {
isNumber,
isPresent,
isBlank,
StringWrapper,
NumberWrapper,
RegExpWrapper,
CONST,
FunctionWrapper
} from 'angular2/src/facade/lang';
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
import {NumberFormatter, NumberFormatStyle} from 'angular2/src/facade/intl';
import {Injectable, PipeTransform, WrappedValue, Pipe} from 'angular2/core';
import {ListWrapper} from 'angular2/src/facade/collection';
} from '../../src/facade/lang';
import {BaseException} from '../../src/facade/exceptions';
import {NumberFormatter, NumberFormatStyle} from '../../src/facade/intl';
import {ListWrapper} from '../../src/facade/collection';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
@ -21,7 +19,6 @@ var _re = RegExpWrapper.create('^(\\d+)?\\.((\\d+)(\\-(\\d+))?)?$');
/**
* Internal base class for numeric pipes.
*/
@CONST()
@Injectable()
export class NumberPipe {
/** @internal */
@ -83,12 +80,10 @@ export class NumberPipe {
*
* {@example core/pipes/ts/number_pipe/number_pipe_example.ts region='NumberPipe'}
*/
@CONST()
@Pipe({name: 'number'})
@Injectable()
export class DecimalPipe extends NumberPipe implements PipeTransform {
transform(value: any, args: any[]): string {
var digits: string = ListWrapper.first(args);
transform(value: any, digits: string = null): string {
return NumberPipe._format(value, NumberFormatStyle.Decimal, digits);
}
}
@ -109,12 +104,10 @@ export class DecimalPipe extends NumberPipe implements PipeTransform {
*
* {@example core/pipes/ts/number_pipe/number_pipe_example.ts region='PercentPipe'}
*/
@CONST()
@Pipe({name: 'percent'})
@Injectable()
export class PercentPipe extends NumberPipe implements PipeTransform {
transform(value: any, args: any[]): string {
var digits: string = ListWrapper.first(args);
transform(value: any, digits: string = null): string {
return NumberPipe._format(value, NumberFormatStyle.Percent, digits);
}
}
@ -139,14 +132,11 @@ export class PercentPipe extends NumberPipe implements PipeTransform {
*
* {@example core/pipes/ts/number_pipe/number_pipe_example.ts region='CurrencyPipe'}
*/
@CONST()
@Pipe({name: 'currency'})
@Injectable()
export class CurrencyPipe extends NumberPipe implements PipeTransform {
transform(value: any, args: any[]): string {
var currencyCode: string = isPresent(args) && args.length > 0 ? args[0] : 'USD';
var symbolDisplay: boolean = isPresent(args) && args.length > 1 ? args[1] : false;
var digits: string = isPresent(args) && args.length > 2 ? args[2] : null;
transform(value: any, currencyCode: string = 'USD', symbolDisplay: boolean = false,
digits: string = null): string {
return NumberPipe._format(value, NumberFormatStyle.Currency, digits, currencyCode,
symbolDisplay);
}

View File

@ -0,0 +1,85 @@
import {Injectable, PipeTransform, Pipe} from '@angular/core';
import {
isBlank,
isString,
isNumber,
isFunction,
RegExpWrapper,
StringWrapper
} from '../../src/facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
/**
* Creates a new String with some or all of the matches of a pattern replaced by
* a replacement.
*
* The pattern to be matched is specified by the 'pattern' parameter.
*
* The replacement to be set is specified by the 'replacement' parameter.
*
* An optional 'flags' parameter can be set.
*
* ### Usage
*
* expression | replace:pattern:replacement
*
* All behavior is based on the expected behavior of the JavaScript API
* String.prototype.replace() function.
*
* Where the input expression is a [String] or [Number] (to be treated as a string),
* the `pattern` is a [String] or [RegExp],
* the 'replacement' is a [String] or [Function].
*
* --Note--: The 'pattern' parameter will be converted to a RegExp instance. Make sure to escape the
* string properly if you are matching for regular expression special characters like parenthesis,
* brackets etc.
*/
@Pipe({name: 'replace'})
@Injectable()
export class ReplacePipe implements PipeTransform {
transform(value: any, pattern: string | RegExp, replacement: Function | string): any {
if (isBlank(value)) {
return value;
}
if (!this._supportedInput(value)) {
throw new InvalidPipeArgumentException(ReplacePipe, value);
}
var input = value.toString();
if (!this._supportedPattern(pattern)) {
throw new InvalidPipeArgumentException(ReplacePipe, pattern);
}
if (!this._supportedReplacement(replacement)) {
throw new InvalidPipeArgumentException(ReplacePipe, replacement);
}
// template fails with literal RegExp e.g /pattern/igm
// var rgx = pattern instanceof RegExp ? pattern : RegExpWrapper.create(pattern);
if (isFunction(replacement)) {
var rgxPattern = isString(pattern) ? RegExpWrapper.create(<string>pattern) : <RegExp>pattern;
return StringWrapper.replaceAllMapped(input, rgxPattern, <Function>replacement);
}
if (pattern instanceof RegExp) {
// use the replaceAll variant
return StringWrapper.replaceAll(input, pattern, <string>replacement);
}
return StringWrapper.replace(input, <string>pattern, <string>replacement);
}
private _supportedInput(input: any): boolean { return isString(input) || isNumber(input); }
private _supportedPattern(pattern: any): boolean {
return isString(pattern) || pattern instanceof RegExp;
}
private _supportedReplacement(replacement: any): boolean {
return isString(replacement) || isFunction(replacement);
}
}

View File

@ -1,7 +1,9 @@
import {isBlank, isString, isArray, StringWrapper, CONST} from 'angular2/src/facade/lang';
import {BaseException} from 'angular2/src/facade/exceptions';
import {ListWrapper} from 'angular2/src/facade/collection';
import {Injectable, PipeTransform, WrappedValue, Pipe} from 'angular2/core';
import {Injectable, PipeTransform, WrappedValue, Pipe} from '@angular/core';
import {isBlank, isString, isArray, StringWrapper} from '../../src/facade/lang';
import {BaseException} from '../../src/facade/exceptions';
import {ListWrapper} from '../../src/facade/collection';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
/**
@ -42,7 +44,7 @@ import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
*
* ## List Example
*
* This `ng-for` example:
* This `ngFor` example:
*
* {@example core/pipes/ts/slice_pipe/slice_pipe_example.ts region='SlicePipe_list'}
*
@ -59,16 +61,11 @@ import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
@Pipe({name: 'slice', pure: false})
@Injectable()
export class SlicePipe implements PipeTransform {
transform(value: any, args: any[] = null): any {
if (isBlank(args) || args.length == 0) {
throw new BaseException('Slice pipe requires one argument');
}
transform(value: any, start: number, end: number = null): any {
if (!this.supports(value)) {
throw new InvalidPipeArgumentException(SlicePipe, value);
}
if (isBlank(value)) return value;
var start: number = args[0];
var end: number = args.length > 1 ? args[1] : null;
if (isString(value)) {
return StringWrapper.slice(value, start, end);
}

View File

@ -1,5 +1,5 @@
import {isString, CONST, isBlank} from 'angular2/src/facade/lang';
import {PipeTransform, WrappedValue, Injectable, Pipe} from 'angular2/core';
import {PipeTransform, WrappedValue, Injectable, Pipe} from '@angular/core';
import {isString, isBlank} from '../../src/facade/lang';
import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
/**
@ -9,11 +9,10 @@ import {InvalidPipeArgumentException} from './invalid_pipe_argument_exception';
*
* {@example core/pipes/ts/lowerupper_pipe/lowerupper_pipe_example.ts region='LowerUpperPipe'}
*/
@CONST()
@Pipe({name: 'uppercase'})
@Injectable()
export class UpperCasePipe implements PipeTransform {
transform(value: string, args: any[] = null): string {
transform(value: string): string {
if (isBlank(value)) return value;
if (!isString(value)) {
throw new InvalidPipeArgumentException(UpperCasePipe, value);

View File

@ -1,60 +1,51 @@
import {
ComponentFixture,
AsyncTestCompleter,
TestComponentBuilder,
beforeEach,
beforeEachProviders,
ddescribe,
xdescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
} from 'angular2/testing_internal';
import {ListWrapper, StringMapWrapper, SetWrapper} from 'angular2/src/facade/collection';
import {Component, View, provide} from 'angular2/core';
import {NgFor} from 'angular2/common';
import {NgClass} from 'angular2/src/common/directives/ng_class';
import {APP_VIEW_POOL_CAPACITY} from 'angular2/src/core/linker/view_pool';
} 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';
function detectChangesAndCheck(fixture: ComponentFixture, classes: string, elIndex: number = 0) {
function detectChangesAndCheck(fixture: ComponentFixture<any>, classes: string) {
fixture.detectChanges();
expect(fixture.debugElement.componentViewChildren[elIndex].nativeElement.className)
.toEqual(classes);
expect(fixture.debugElement.children[0].nativeElement.className).toEqual(classes);
}
export function main() {
describe('binding to CSS class list', () => {
describe('viewpool support', () => {
beforeEachProviders(() => { return [provide(APP_VIEW_POOL_CAPACITY, {useValue: 100})]; });
it('should clean up when the directive is destroyed',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div *ngFor="let item of items" [ngClass]="item"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.items = [['0']];
fixture.detectChanges();
fixture.debugElement.componentInstance.items = [['1']];
it('should clean up when the directive is destroyed',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div *ng-for="var item of items" [ng-class]="item"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.items = [['0']];
fixture.detectChanges();
fixture.debugElement.componentInstance.items = [['1']];
detectChangesAndCheck(fixture, '1');
detectChangesAndCheck(fixture, '1', 1);
async.done();
});
}));
});
async.done();
});
}));
describe('expressions evaluating to objects', () => {
it('should add classes specified in an object literal',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="{foo: true, bar: false}"></div>';
var template = '<div [ngClass]="{foo: true, bar: false}"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -67,7 +58,7 @@ export function main() {
it('should add classes specified in an object literal without change in class names',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [ng-class]="{'foo-bar': true, 'fooBar': true}"></div>`;
var template = `<div [ngClass]="{'foo-bar': true, 'fooBar': true}"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -79,7 +70,7 @@ export function main() {
it('should add and remove classes based on changes in object literal values',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="{foo: condition, bar: !condition}"></div>';
var template = '<div [ngClass]="{foo: condition, bar: !condition}"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -95,7 +86,7 @@ export function main() {
it('should add and remove classes based on changes to the expression object',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="objExpr"></div>';
var template = '<div [ngClass]="objExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -117,7 +108,7 @@ export function main() {
it('should add and remove classes based on reference changes to the expression object',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="objExpr"></div>';
var template = '<div [ngClass]="objExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -136,7 +127,7 @@ export function main() {
it('should remove active classes when expression evaluates to null',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="objExpr"></div>';
var template = '<div [ngClass]="objExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -156,7 +147,7 @@ export function main() {
it('should allow multiple classes per expression',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="objExpr"></div>';
var template = '<div [ngClass]="objExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -181,7 +172,7 @@ export function main() {
it('should split by one or more spaces between classes',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="objExpr"></div>';
var template = '<div [ngClass]="objExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -200,7 +191,7 @@ export function main() {
it('should add classes specified in a list literal',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [ng-class]="['foo', 'bar', 'foo-bar', 'fooBar']"></div>`;
var template = `<div [ngClass]="['foo', 'bar', 'foo-bar', 'fooBar']"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -212,7 +203,7 @@ export function main() {
it('should add and remove classes based on changes to the expression',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="arrExpr"></div>';
var template = '<div [ngClass]="arrExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -235,7 +226,7 @@ export function main() {
it('should add and remove classes when a reference changes',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="arrExpr"></div>';
var template = '<div [ngClass]="arrExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -251,7 +242,7 @@ export function main() {
it('should take initial classes into account when a reference changes',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div class="foo" [ng-class]="arrExpr"></div>';
var template = '<div class="foo" [ngClass]="arrExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -267,7 +258,7 @@ export function main() {
it('should ignore empty or blank class names',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div class="foo" [ng-class]="arrExpr"></div>';
var template = '<div class="foo" [ngClass]="arrExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -282,7 +273,7 @@ export function main() {
it('should trim blanks from class names',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div class="foo" [ng-class]="arrExpr"></div>';
var template = '<div class="foo" [ngClass]="arrExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -298,7 +289,7 @@ export function main() {
it('should allow multiple classes per item in arrays',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="arrExpr"></div>';
var template = '<div [ngClass]="arrExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -320,7 +311,7 @@ export function main() {
it('should add and remove classes if the set instance changed',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="setExpr"></div>';
var template = '<div [ngClass]="setExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -343,7 +334,7 @@ export function main() {
it('should add classes specified in a string literal',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [ng-class]="'foo bar foo-bar fooBar'"></div>`;
var template = `<div [ngClass]="'foo bar foo-bar fooBar'"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -355,7 +346,7 @@ export function main() {
it('should add and remove classes based on changes to the expression',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="strExpr"></div>';
var template = '<div [ngClass]="strExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -375,7 +366,7 @@ export function main() {
it('should remove active classes when switching from string to null',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [ng-class]="strExpr"></div>`;
var template = `<div [ngClass]="strExpr"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -391,7 +382,7 @@ export function main() {
it('should take initial classes into account when switching from string to null',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div class="foo" [ng-class]="strExpr"></div>`;
var template = `<div class="foo" [ngClass]="strExpr"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -407,7 +398,7 @@ export function main() {
it('should ignore empty and blank strings',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div class="foo" [ng-class]="strExpr"></div>`;
var template = `<div class="foo" [ngClass]="strExpr"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -425,7 +416,7 @@ export function main() {
it('should co-operate with the class attribute',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [ng-class]="objExpr" class="init foo"></div>';
var template = '<div [ngClass]="objExpr" class="init foo"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -445,7 +436,7 @@ export function main() {
it('should co-operate with the interpolated class attribute',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [ng-class]="objExpr" class="{{'init foo'}}"></div>`;
var template = `<div [ngClass]="objExpr" class="{{'init foo'}}"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -465,7 +456,7 @@ export function main() {
it('should co-operate with the class attribute and binding to it',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [ng-class]="objExpr" class="init" [class]="'foo'"></div>`;
var template = `<div [ngClass]="objExpr" class="init" [class]="'foo'"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -486,7 +477,7 @@ export function main() {
it('should co-operate with the class attribute and class.name binding',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div class="init foo" [ng-class]="objExpr" [class.baz]="condition"></div>';
'<div class="init foo" [ngClass]="objExpr" [class.baz]="condition"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -508,7 +499,7 @@ export function main() {
it('should co-operate with initial class and class attribute binding when binding changes',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div class="init" [ng-class]="objExpr" [class]="strExpr"></div>';
var template = '<div class="init" [ngClass]="objExpr" [class]="strExpr"></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -532,8 +523,7 @@ export function main() {
})
}
@Component({selector: 'test-cmp'})
@View({directives: [NgClass, NgFor]})
@Component({selector: 'test-cmp', directives: [NgClass, NgFor], template: ''})
class TestComponent {
condition: boolean = true;
items: any[];

View File

@ -1,27 +1,28 @@
import {
AsyncTestCompleter,
TestComponentBuilder,
beforeEach,
beforeEachProviders,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
} from 'angular2/testing_internal';
import {ListWrapper} from 'angular2/src/facade/collection';
import {Component, View, TemplateRef, ContentChild} from 'angular2/core';
import {NgFor} from 'angular2/src/common/directives/ng_for';
} 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';
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';
export function main() {
describe('ng-for', () => {
describe('ngFor', () => {
var TEMPLATE =
'<div><copy-me template="ng-for #item of items">{{item.toString()}};</copy-me></div>';
'<div><copy-me template="ngFor let item of items">{{item.toString()}};</copy-me></div>';
it('should reflect initial elements',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
@ -98,7 +99,7 @@ export function main() {
it('should iterate over an array of objects',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<ul><li template="ng-for #item of items">{{item["name"]}};</li></ul>';
var template = '<ul><li template="ngFor let item of items">{{item["name"]}};</li></ul>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -128,7 +129,7 @@ export function main() {
it('should gracefully handle nulls',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<ul><li template="ng-for #item of null">{{item}};</li></ul>';
var template = '<ul><li template="ngFor let item of null">{{item}};</li></ul>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
@ -157,6 +158,24 @@ export function main() {
});
}));
if (!IS_DART) {
it('should throw on non-iterable ref and suggest using an array',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
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 ref changing to string',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideTemplate(TestComponent, TEMPLATE)
@ -187,8 +206,8 @@ export function main() {
it('should repeat over nested arrays',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div>' +
'<div template="ng-for #item of items">' +
'<div template="ng-for #subitem of item">' +
'<div template="ngFor let item of items">' +
'<div template="ngFor let subitem of item">' +
'{{subitem}}-{{item.length}};' +
'</div>|' +
'</div>' +
@ -213,8 +232,8 @@ export function main() {
it('should repeat over nested arrays with no intermediate element',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div><template ng-for #item [ng-for-of]="items">' +
'<div template="ng-for #subitem of item">' +
var template = '<div><template ngFor let-item [ngForOf]="items">' +
'<div template="ngFor let subitem of item">' +
'{{subitem}}-{{item.length}};' +
'</div></template></div>';
@ -232,10 +251,37 @@ export function main() {
});
}));
it('should repeat over nested ngIf that are the last node in the ngFor temlate',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var 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];
fixture.debugElement.componentInstance.items = items;
fixture.detectChanges();
expect(el).toHaveText('0|even|');
items.push(1);
fixture.detectChanges();
expect(el).toHaveText('0|even|1|');
items.push(1);
fixture.detectChanges();
expect(el).toHaveText('0|even|1|2|even|');
async.done();
});
}));
it('should display indices correctly',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div><copy-me template="ng-for: var item of items; var i=index">{{i.toString()}}</copy-me></div>';
'<div><copy-me template="ngFor: let item of items; let i=index">{{i.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -251,10 +297,29 @@ export function main() {
});
}));
it('should display first item correctly',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div><copy-me template="ngFor: let item of items; let isFirst=first">{{isFirst.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.items = [0, 1, 2];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('truefalsefalse');
fixture.debugElement.componentInstance.items = [2, 1];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('truefalse');
async.done();
});
}));
it('should display last item correctly',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div><copy-me template="ng-for: var item of items; var isLast=last">{{isLast.toString()}}</copy-me></div>';
'<div><copy-me template="ngFor: let item of items; let isLast=last">{{isLast.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -273,7 +338,7 @@ export function main() {
it('should display even items correctly',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div><copy-me template="ng-for: var item of items; var isEven=even">{{isEven.toString()}}</copy-me></div>';
'<div><copy-me template="ngFor: let item of items; let isEven=even">{{isEven.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -292,7 +357,7 @@ export function main() {
it('should display odd items correctly',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div><copy-me template="ng-for: var item of items; var isOdd=odd">{{isOdd.toString()}}</copy-me></div>';
'<div><copy-me template="ngFor: let item of items; let isOdd=odd">{{isOdd.toString()}}</copy-me></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -312,13 +377,13 @@ export function main() {
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideTemplate(
TestComponent,
'<ul><template ng-for [ng-for-of]="items" [ng-for-template]="contentTpl"></template></ul>')
'<ul><template ngFor [ngForOf]="items" [ngForTemplate]="contentTpl"></template></ul>')
.overrideTemplate(
ComponentUsingTestComponent,
'<test-cmp><li template="#item #i=index">{{i}}: {{item}};</li></test-cmp>')
'<test-cmp><li template="let item; let i=index">{{i}}: {{item}};</li></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
var testComponent = fixture.debugElement.componentViewChildren[0];
var testComponent = fixture.debugElement.children[0];
testComponent.componentInstance.items = ['a', 'b', 'c'];
fixture.detectChanges();
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
@ -329,12 +394,12 @@ export function main() {
it('should use a default template if a custom one is null',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideTemplate(TestComponent, `<ul><template ng-for #item [ng-for-of]="items"
[ng-for-template]="contentTpl" #i="index">{{i}}: {{item}};</template></ul>`)
tcb.overrideTemplate(TestComponent, `<ul><template ngFor let-item [ngForOf]="items"
[ngForTemplate]="contentTpl" let-i="index">{{i}}: {{item}};</template></ul>`)
.overrideTemplate(ComponentUsingTestComponent, '<test-cmp></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
var testComponent = fixture.debugElement.componentViewChildren[0];
var testComponent = fixture.debugElement.children[0];
testComponent.componentInstance.items = ['a', 'b', 'c'];
fixture.detectChanges();
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
@ -345,14 +410,14 @@ export function main() {
it('should use a custom template when both default and a custom one are present',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
tcb.overrideTemplate(TestComponent, `<ul><template ng-for #item [ng-for-of]="items"
[ng-for-template]="contentTpl" #i="index">{{i}}=> {{item}};</template></ul>`)
tcb.overrideTemplate(TestComponent, `<ul><template ngFor let-item [ngForOf]="items"
[ngForTemplate]="contentTpl" let-i="index">{{i}}=> {{item}};</template></ul>`)
.overrideTemplate(
ComponentUsingTestComponent,
'<test-cmp><li template="#item #i=index">{{i}}: {{item}};</li></test-cmp>')
'<test-cmp><li template="let item; let i=index">{{i}}: {{item}};</li></test-cmp>')
.createAsync(ComponentUsingTestComponent)
.then((fixture) => {
var testComponent = fixture.debugElement.componentViewChildren[0];
var testComponent = fixture.debugElement.children[0];
testComponent.componentInstance.items = ['a', 'b', 'c'];
fixture.detectChanges();
expect(testComponent.nativeElement).toHaveText('0: a;1: b;2: c;');
@ -360,6 +425,83 @@ export function main() {
async.done();
});
}));
describe('track by', function() {
it('should not replace tracked items',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var 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 firstP = buildItemList();
var finalP = buildItemList();
expect(finalP.nativeElement).toBe(firstP.nativeElement);
async.done();
});
}));
it('should update implicit local variable on view',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.items = [{'id': 'a', 'color': 'blue'}];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('blue');
fixture.debugElement.componentInstance.items = [{'id': 'a', 'color': 'red'}];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('red');
async.done();
});
}));
it('should move items around and keep them updated ',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackById">{{item['color']}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.items =
[{'id': 'a', 'color': 'blue'}, {'id': 'b', 'color': 'yellow'}];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('blueyellow');
fixture.debugElement.componentInstance.items =
[{'id': 'b', 'color': 'orange'}, {'id': 'a', 'color': 'red'}];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('orangered');
async.done();
});
}));
it('should handle added and removed items properly when tracking by index',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<div><template ngFor let-item [ngForOf]="items" [ngForTrackBy]="trackByIndex">{{item}}</template></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.items = ['a', 'b', 'c', 'd'];
fixture.detectChanges();
fixture.debugElement.componentInstance.items = ['e', 'f', 'g', 'h'];
fixture.detectChanges();
fixture.debugElement.componentInstance.items = ['e', 'f', 'h'];
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('efh');
async.done();
});
}));
});
});
}
@ -367,16 +509,16 @@ class Foo {
toString() { return 'foo'; }
}
@Component({selector: 'test-cmp'})
@View({directives: [NgFor]})
@Component({selector: 'test-cmp', directives: [NgFor, NgIf], template: ''})
class TestComponent {
@ContentChild(TemplateRef) contentTpl: TemplateRef;
@ContentChild(TemplateRef) contentTpl: TemplateRef<Object>;
items: any;
constructor() { this.items = [1, 2]; }
trackById(index: number, item: any): string { return item['id']; }
trackByIndex(index: number, item: any): number { return index; }
}
@Component({selector: 'outer-cmp'})
@View({directives: [TestComponent]})
@Component({selector: 'outer-cmp', directives: [TestComponent], template: ''})
class ComponentUsingTestComponent {
items: any;
constructor() { this.items = [1, 2]; }

View File

@ -1,35 +1,35 @@
import {
AsyncTestCompleter,
TestComponentBuilder,
beforeEach,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
} from 'angular2/testing_internal';
} from '@angular/core/testing/testing_internal';
import {expect} from '@angular/platform-browser/testing';
import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {Component, View} from 'angular2/core';
import {NgIf} from 'angular2/common';
import {Component} from '@angular/core';
import {NgIf} from '@angular/common';
import {IS_DART} from 'angular2/src/facade/lang';
import {IS_DART} from '../../src/facade/lang';
export function main() {
describe('ng-if directive', () => {
describe('ngIf directive', () => {
it('should work in a template attribute',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var html = '<div><copy-me template="ng-if booleanCondition">hello</copy-me></div>';
var html = '<div><copy-me template="ngIf booleanCondition">hello</copy-me></div>';
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('hello');
async.done();
@ -39,13 +39,14 @@ export function main() {
it('should work in a template element',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var html =
'<div><template [ng-if]="booleanCondition"><copy-me>hello2</copy-me></template></div>';
'<div><template [ngIf]="booleanCondition"><copy-me>hello2</copy-me></template></div>';
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('hello2');
async.done();
@ -54,26 +55,29 @@ export function main() {
it('should toggle node when condition changes',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var html = '<div><copy-me template="ng-if booleanCondition">hello</copy-me></div>';
var html = '<div><copy-me template="ngIf booleanCondition">hello</copy-me></div>';
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.booleanCondition = false;
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(0);
expect(fixture.debugElement.nativeElement).toHaveText('');
fixture.debugElement.componentInstance.booleanCondition = true;
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('hello');
fixture.debugElement.componentInstance.booleanCondition = false;
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(0);
expect(fixture.debugElement.nativeElement).toHaveText('');
@ -84,38 +88,43 @@ export function main() {
it('should handle nested if correctly',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var html =
'<div><template [ng-if]="booleanCondition"><copy-me *ng-if="nestedBooleanCondition">hello</copy-me></template></div>';
'<div><template [ngIf]="booleanCondition"><copy-me *ngIf="nestedBooleanCondition">hello</copy-me></template></div>';
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.booleanCondition = false;
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(0);
expect(fixture.debugElement.nativeElement).toHaveText('');
fixture.debugElement.componentInstance.booleanCondition = true;
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('hello');
fixture.debugElement.componentInstance.nestedBooleanCondition = false;
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(0);
expect(fixture.debugElement.nativeElement).toHaveText('');
fixture.debugElement.componentInstance.nestedBooleanCondition = true;
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('hello');
fixture.debugElement.componentInstance.booleanCondition = false;
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(0);
expect(fixture.debugElement.nativeElement).toHaveText('');
@ -127,30 +136,33 @@ export function main() {
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var html =
'<div>' +
'<copy-me template="ng-if numberCondition + 1 >= 2">helloNumber</copy-me>' +
'<copy-me template="ng-if stringCondition == \'foo\'">helloString</copy-me>' +
'<copy-me template="ng-if functionCondition(stringCondition, numberCondition)">helloFunction</copy-me>' +
'<copy-me template="ngIf numberCondition + 1 >= 2">helloNumber</copy-me>' +
'<copy-me template="ngIf stringCondition == \'foo\'">helloString</copy-me>' +
'<copy-me template="ngIf functionCondition(stringCondition, numberCondition)">helloFunction</copy-me>' +
'</div>';
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(3);
expect(DOM.getText(fixture.debugElement.nativeElement))
expect(getDOM().getText(fixture.debugElement.nativeElement))
.toEqual('helloNumberhelloStringhelloFunction');
fixture.debugElement.componentInstance.numberCondition = 0;
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('helloString');
fixture.debugElement.componentInstance.numberCondition = 1;
fixture.debugElement.componentInstance.stringCondition = "bar";
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(
getDOM().querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('helloNumber');
async.done();
@ -161,19 +173,23 @@ export function main() {
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) => {
var html = '<div><copy-me template="ng-if numberCondition">hello</copy-me></div>';
var html = '<div><copy-me template="ngIf numberCondition">hello</copy-me></div>';
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
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(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(getDOM()
.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me')
.length)
.toEqual(1);
expect(fixture.debugElement.nativeElement).toHaveText('hello');
@ -183,20 +199,20 @@ export function main() {
it('should not recreate the element if the condition goes from true to true (JS)',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var html = '<div><copy-me template="ng-if numberCondition">hello</copy-me></div>';
var html = '<div><copy-me template="ngIf numberCondition">hello</copy-me></div>';
tcb.overrideTemplate(TestComponent, html)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
DOM.addClass(DOM.querySelector(fixture.debugElement.nativeElement, 'copy-me'),
"foo");
getDOM().addClass(
getDOM().querySelector(fixture.debugElement.nativeElement, 'copy-me'), "foo");
fixture.debugElement.componentInstance.numberCondition = 2;
fixture.detectChanges();
expect(
DOM.hasClass(DOM.querySelector(fixture.debugElement.nativeElement, 'copy-me'),
"foo"))
expect(getDOM().hasClass(
getDOM().querySelector(fixture.debugElement.nativeElement, 'copy-me'),
"foo"))
.toBe(true);
async.done();
@ -207,13 +223,15 @@ export function main() {
if (IS_DART) {
it('should not create the element if the condition is not a boolean (DART)',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var html = '<div><copy-me template="ng-if numberCondition">hello</copy-me></div>';
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(DOM.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me').length)
expect(getDOM()
.querySelectorAll(fixture.debugElement.nativeElement, 'copy-me')
.length)
.toEqual(0);
expect(fixture.debugElement.nativeElement).toHaveText('');
async.done();
@ -224,8 +242,7 @@ export function main() {
});
}
@Component({selector: 'test-cmp'})
@View({directives: [NgIf]})
@Component({selector: 'test-cmp', directives: [NgIf], template: ''})
class TestComponent {
booleanCondition: boolean;
nestedBooleanCondition: boolean;

View File

@ -0,0 +1,135 @@
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, ComponentFixture} from '@angular/compiler/testing';
import {Component, Injectable, provide} from '@angular/core';
import {NgPlural, NgPluralCase, NgLocalization} from '@angular/common';
export function main() {
describe('switch', () => {
beforeEachProviders(() => [provide(NgLocalization, {useClass: TestLocalizationMap})]);
it('should display the template according to the exact value',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div>' +
'<ul [ngPlural]="switchValue">' +
'<template ngPluralCase="=0"><li>you have no messages.</li></template>' +
'<template ngPluralCase="=1"><li>you have one message.</li></template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.switchValue = 0;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have no messages.');
fixture.debugElement.componentInstance.switchValue = 1;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have one message.');
async.done();
});
}));
it('should display the template according to the category',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div>' +
'<ul [ngPlural]="switchValue">' +
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
'<template ngPluralCase="many"><li>you have many messages.</li></template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.switchValue = 2;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have a few messages.');
fixture.debugElement.componentInstance.switchValue = 8;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have many messages.');
async.done();
});
}));
it('should default to other when no matches are found',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div>' +
'<ul [ngPlural]="switchValue">' +
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
'<template ngPluralCase="other"><li>default message.</li></template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.switchValue = 100;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('default message.');
async.done();
});
}));
it('should prioritize value matches over category matches',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
'<div>' +
'<ul [ngPlural]="switchValue">' +
'<template ngPluralCase="few"><li>you have a few messages.</li></template>' +
'<template ngPluralCase="=2">you have two messages.</template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.switchValue = 2;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have two messages.');
fixture.debugElement.componentInstance.switchValue = 3;
fixture.detectChanges();
expect(fixture.debugElement.nativeElement).toHaveText('you have a few messages.');
async.done();
});
}));
});
}
@Injectable()
export class TestLocalizationMap extends NgLocalization {
getPluralCategory(value: number): string {
if (value > 1 && value < 4) {
return 'few';
} else if (value >= 4 && value < 10) {
return 'many';
} else {
return 'other';
}
}
}
@Component({selector: 'test-cmp', directives: [NgPlural, NgPluralCase], template: ''})
class TestComponent {
switchValue: number;
constructor() { this.switchValue = null; }
}

View File

@ -1,39 +1,38 @@
import {
AsyncTestCompleter,
TestComponentBuilder,
beforeEach,
beforeEachProviders,
ddescribe,
xdescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
} from 'angular2/testing_internal';
} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {StringMapWrapper} from 'angular2/src/facade/collection';
import {StringMapWrapper} from '../../src/facade/collection';
import {Component, View} from 'angular2/core';
import {Component} from '@angular/core';
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {NgStyle} from 'angular2/src/common/directives/ng_style';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {NgStyle} from '@angular/common/src/directives/ng_style';
export function main() {
describe('binding to CSS styles', () => {
it('should add styles specified in an object literal',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [ng-style]="{'max-width': '40px'}"></div>`;
var template = `<div [ngStyle]="{'max-width': '40px'}"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
async.done();
@ -42,7 +41,7 @@ export function main() {
it('should add and change styles specified in an object expression',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [ng-style]="expr"></div>`;
var template = `<div [ngStyle]="expr"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
@ -51,15 +50,15 @@ export function main() {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
expr = fixture.debugElement.componentInstance.expr;
expr['max-width'] = '30%';
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('30%');
async.done();
@ -68,21 +67,21 @@ export function main() {
it('should remove styles when deleting a key in an object expression',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [ng-style]="expr"></div>`;
var template = `<div [ngStyle]="expr"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
StringMapWrapper.delete(fixture.debugElement.componentInstance.expr, 'max-width');
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('');
async.done();
@ -91,27 +90,27 @@ export function main() {
it('should co-operate with the style attribute',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div style="font-size: 12px" [ng-style]="expr"></div>`;
var template = `<div style="font-size: 12px" [ngStyle]="expr"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'font-size'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
StringMapWrapper.delete(fixture.debugElement.componentInstance.expr, 'max-width');
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('');
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'font-size'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
async.done();
@ -120,28 +119,28 @@ export function main() {
it('should co-operate with the style.[styleName]="expr" special-case in the compiler',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [style.font-size.px]="12" [ng-style]="expr"></div>`;
var template = `<div [style.font-size.px]="12" [ngStyle]="expr"></div>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.debugElement.componentInstance.expr = {'max-width': '40px'};
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('40px');
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'font-size'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
StringMapWrapper.delete(fixture.debugElement.componentInstance.expr, 'max-width');
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'font-size'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'font-size'))
.toEqual('12px');
fixture.detectChanges();
expect(DOM.getStyle(fixture.debugElement.componentViewChildren[0].nativeElement,
'max-width'))
expect(
getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'max-width'))
.toEqual('');
async.done();
@ -150,8 +149,7 @@ export function main() {
})
}
@Component({selector: 'test-cmp'})
@View({directives: [NgStyle]})
@Component({selector: 'test-cmp', directives: [NgStyle], template: ''})
class TestComponent {
expr;
}

View File

@ -1,20 +1,18 @@
import {
AsyncTestCompleter,
TestComponentBuilder,
beforeEach,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
} from 'angular2/testing_internal';
} 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';
import {Component, View} from 'angular2/core';
import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from 'angular2/src/common/directives/ng_switch';
import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from '@angular/common';
export function main() {
describe('switch', () => {
@ -22,9 +20,9 @@ export function main() {
it('should switch amongst when values',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div>' +
'<ul [ng-switch]="switchValue">' +
'<template ng-switch-when="a"><li>when a</li></template>' +
'<template ng-switch-when="b"><li>when b</li></template>' +
'<ul [ngSwitch]="switchValue">' +
'<template ngSwitchWhen="a"><li>when a</li></template>' +
'<template ngSwitchWhen="b"><li>when b</li></template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
@ -48,9 +46,9 @@ export function main() {
it('should switch amongst when values with fallback to default',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div>' +
'<ul [ng-switch]="switchValue">' +
'<li template="ng-switch-when \'a\'">when a</li>' +
'<li template="ng-switch-default">when default</li>' +
'<ul [ngSwitch]="switchValue">' +
'<li template="ngSwitchWhen \'a\'">when a</li>' +
'<li template="ngSwitchDefault">when default</li>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
@ -74,13 +72,13 @@ export function main() {
it('should support multiple whens with the same value',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div>' +
'<ul [ng-switch]="switchValue">' +
'<template ng-switch-when="a"><li>when a1;</li></template>' +
'<template ng-switch-when="b"><li>when b1;</li></template>' +
'<template ng-switch-when="a"><li>when a2;</li></template>' +
'<template ng-switch-when="b"><li>when b2;</li></template>' +
'<template ng-switch-default><li>when default1;</li></template>' +
'<template ng-switch-default><li>when default2;</li></template>' +
'<ul [ngSwitch]="switchValue">' +
'<template ngSwitchWhen="a"><li>when a1;</li></template>' +
'<template ngSwitchWhen="b"><li>when b1;</li></template>' +
'<template ngSwitchWhen="a"><li>when a2;</li></template>' +
'<template ngSwitchWhen="b"><li>when b2;</li></template>' +
'<template ngSwitchDefault><li>when default1;</li></template>' +
'<template ngSwitchDefault><li>when default2;</li></template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
@ -107,10 +105,10 @@ export function main() {
it('should switch amongst when values',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div>' +
'<ul [ng-switch]="switchValue">' +
'<template [ng-switch-when]="when1"><li>when 1;</li></template>' +
'<template [ng-switch-when]="when2"><li>when 2;</li></template>' +
'<template ng-switch-default><li>when default;</li></template>' +
'<ul [ngSwitch]="switchValue">' +
'<template [ngSwitchWhen]="when1"><li>when 1;</li></template>' +
'<template [ngSwitchWhen]="when2"><li>when 2;</li></template>' +
'<template ngSwitchDefault><li>when default;</li></template>' +
'</ul></div>';
tcb.overrideTemplate(TestComponent, template)
@ -145,8 +143,8 @@ export function main() {
});
}
@Component({selector: 'test-cmp'})
@View({directives: [NgSwitch, NgSwitchWhen, NgSwitchDefault]})
@Component(
{selector: 'test-cmp', directives: [NgSwitch, NgSwitchWhen, NgSwitchDefault], template: ''})
class TestComponent {
switchValue: any;
when1: any;

View File

@ -0,0 +1,110 @@
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';
import {NgTemplateOutlet} from '@angular/common';
export function main() {
describe('insert', () => {
it('should do nothing if templateRef is null',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<template [ngTemplateOutlet]="null"></template>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('');
async.done();
});
}));
it('should insert content specified by TemplateRef',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<tpl-refs #refs="tplRefs"><template>foo</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('');
var refs = fixture.debugElement.children[0].references['refs'];
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('foo');
async.done();
});
}));
it('should clear content if TemplateRef becomes null',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template =
`<tpl-refs #refs="tplRefs"><template>foo</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
var refs = fixture.debugElement.children[0].references['refs'];
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('foo');
fixture.componentInstance.currentTplRef = null;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('');
async.done();
});
}));
it('should swap content if TemplateRef changes',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<tpl-refs #refs="tplRefs"><template>foo</template><template>bar</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
var refs = fixture.debugElement.children[0].references['refs'];
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('foo');
fixture.componentInstance.currentTplRef = refs.tplRefs.last;
fixture.detectChanges();
expect(fixture.nativeElement).toHaveText('bar');
async.done();
});
}));
});
}
@Directive({selector: 'tpl-refs', exportAs: 'tplRefs'})
class CaptureTplRefs {
@ContentChildren(TemplateRef) tplRefs: QueryList<TemplateRef<any>>;
}
@Component({selector: 'test-cmp', directives: [NgTemplateOutlet, CaptureTplRefs], template: ''})
class TestComponent {
currentTplRef: TemplateRef<any>;
}

View File

@ -1,25 +1,24 @@
import {
AsyncTestCompleter,
TestComponentBuilder,
beforeEach,
ddescribe,
describe,
el,
expect,
iit,
inject,
it,
xit,
} from 'angular2/testing_internal';
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {Component, Directive, View} from 'angular2/core';
import {ElementRef} from 'angular2/src/core/linker/element_ref';
} from '@angular/core/testing/testing_internal';
import {TestComponentBuilder, ComponentFixture} from '@angular/compiler/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {Component, Directive} from '@angular/core';
import {ElementRef} from '@angular/core/src/linker/element_ref';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
export function main() {
describe('non-bindable', () => {
it('should not interpolate children',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div>{{text}}<span ng-non-bindable>{{text}}</span></div>';
var template = '<div>{{text}}<span ngNonBindable>{{text}}</span></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
@ -31,29 +30,29 @@ export function main() {
it('should ignore directives on child nodes',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div ng-non-bindable><span id=child test-dec>{{text}}</span></div>';
var template = '<div ngNonBindable><span id=child test-dec>{{text}}</span></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
// We must use DOM.querySelector instead of fixture.query here
// We must use getDOM().querySelector instead of fixture.query here
// since the elements inside are not compiled.
var span = DOM.querySelector(fixture.debugElement.nativeElement, '#child');
expect(DOM.hasClass(span, 'compiled')).toBeFalsy();
var span = getDOM().querySelector(fixture.debugElement.nativeElement, '#child');
expect(getDOM().hasClass(span, 'compiled')).toBeFalsy();
async.done();
});
}));
it('should trigger directives on the same node',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div><span id=child ng-non-bindable test-dec>{{text}}</span></div>';
var template = '<div><span id=child ngNonBindable test-dec>{{text}}</span></div>';
tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((fixture) => {
fixture.detectChanges();
var span = DOM.querySelector(fixture.debugElement.nativeElement, '#child');
expect(DOM.hasClass(span, 'compiled')).toBeTruthy();
var span = getDOM().querySelector(fixture.debugElement.nativeElement, '#child');
expect(getDOM().hasClass(span, 'compiled')).toBeTruthy();
async.done();
});
}));
@ -62,11 +61,10 @@ export function main() {
@Directive({selector: '[test-dec]'})
class TestDirective {
constructor(el: ElementRef) { DOM.addClass(el.nativeElement, 'compiled'); }
constructor(el: ElementRef) { getDOM().addClass(el.nativeElement, 'compiled'); }
}
@Component({selector: 'test-cmp'})
@View({directives: [TestDirective]})
@Component({selector: 'test-cmp', directives: [TestDirective], template: ''})
class TestComponent {
text: string;
constructor() { this.text = 'foo'; }

View File

@ -6,9 +6,7 @@ import 'package:angular2/core.dart' show ChangeDetectorRef;
import 'package:angular2/common.dart' show ObservableListDiffFactory;
@proxy
class SpyChangeDetectorRef extends SpyObject implements ChangeDetectorRef {
noSuchMethod(m) => super.noSuchMethod(m);
}
class SpyChangeDetectorRef extends SpyObject implements ChangeDetectorRef {}
main() {
describe('ObservableListDiff', () {

View File

@ -1,24 +1,24 @@
import {
ddescribe,
describe,
fakeAsync,
flushMicrotasks,
it,
iit,
xit,
expect,
beforeEach,
afterEach,
el,
AsyncTestCompleter,
inject,
tick
} from 'angular2/testing_internal';
inject
} from '@angular/core/testing/testing_internal';
import {
fakeAsync,
flushMicrotasks,
Log,
tick,
} from '@angular/core/testing';
import {SpyNgControl, SpyValueAccessor} from '../spies';
import {QueryList} from 'angular2/core';
import {
ControlGroup,
Control,
@ -35,13 +35,13 @@ import {
CheckboxControlValueAccessor,
SelectControlValueAccessor,
Validator
} from 'angular2/common';
} from '@angular/common';
import {selectValueAccessor, composeValidators} from 'angular2/src/common/forms/directives/shared';
import {TimerWrapper} from 'angular2/src/facade/async';
import {PromiseWrapper} from 'angular2/src/facade/promise';
import {SimpleChange} from 'angular2/src/core/change_detection';
import {selectValueAccessor, composeValidators} from '@angular/common/src/forms/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;
@ -71,7 +71,7 @@ function asyncValidator(expected, timeout = 0) {
export function main() {
describe("Form Directives", () => {
var defaultAccessor;
var defaultAccessor: DefaultValueAccessor;
beforeEach(() => { defaultAccessor = new DefaultValueAccessor(null, null); });
@ -94,21 +94,21 @@ export function main() {
});
it("should return select accessor when provided", () => {
var selectAccessor = new SelectControlValueAccessor(null, null, new QueryList<any>());
var selectAccessor = new SelectControlValueAccessor(null, null);
expect(selectValueAccessor(dir, [defaultAccessor, selectAccessor]))
.toEqual(selectAccessor);
});
it("should throw when more than one build-in accessor is provided", () => {
var checkboxAccessor = new CheckboxControlValueAccessor(null, null);
var selectAccessor = new SelectControlValueAccessor(null, null, new QueryList<any>());
var selectAccessor = new SelectControlValueAccessor(null, null);
expect(() => selectValueAccessor(dir, [checkboxAccessor, selectAccessor])).toThrowError();
});
it("should return custom accessor when provided", () => {
var customAccessor = new SpyValueAccessor();
var checkboxAccessor = new CheckboxControlValueAccessor(null, null);
expect(selectValueAccessor(dir, [defaultAccessor, customAccessor, checkboxAccessor]))
expect(selectValueAccessor(dir, <any>[defaultAccessor, customAccessor, checkboxAccessor]))
.toEqual(customAccessor);
});

View File

@ -6,11 +6,10 @@ import {
xit,
expect,
beforeEach,
afterEach,
el
} from 'angular2/testing_internal';
import {Control, FormBuilder} from 'angular2/common';
import {PromiseWrapper} from 'angular2/src/facade/promise';
afterEach
} from '@angular/core/testing/testing_internal';
import {Control, FormBuilder} from '@angular/common';
import {PromiseWrapper} from '../../src/facade/promise';
export function main() {
function syncValidator(_) { return null; }

File diff suppressed because it is too large Load Diff

View File

@ -7,19 +7,17 @@ import {
expect,
beforeEach,
afterEach,
el,
AsyncTestCompleter,
fakeAsync,
tick,
inject
} from 'angular2/testing_internal';
import {ControlGroup, Control, ControlArray, Validators} from 'angular2/common';
import {IS_DART, isPresent, CONST_EXPR} from 'angular2/src/facade/lang';
import {PromiseWrapper} from 'angular2/src/facade/promise';
import {TimerWrapper, ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
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';
import {IS_DART, isPresent} from '../../src/facade/lang';
import {PromiseWrapper} from '../../src/facade/promise';
import {TimerWrapper, ObservableWrapper, EventEmitter} from '../../src/facade/async';
export function main() {
function asyncValidator(expected, timeouts = CONST_EXPR({})) {
function asyncValidator(expected, timeouts = /*@ts2dart_const*/ {}) {
return (c) => {
var completer = PromiseWrapper.completer();
var t = isPresent(timeouts[c.value]) ? timeouts[c.value] : 0;

View File

@ -6,15 +6,12 @@ import {
xit,
expect,
beforeEach,
afterEach,
fakeAsync,
tick,
el
} from 'angular2/testing_internal';
import {ControlGroup, Control, Validators, AbstractControl, ControlArray} from 'angular2/common';
import {PromiseWrapper} from 'angular2/src/facade/promise';
import {EventEmitter, ObservableWrapper, TimerWrapper} from 'angular2/src/facade/async';
import {CONST_EXPR} from 'angular2/src/facade/lang';
afterEach
} from '@angular/core/testing/testing_internal';
import {fakeAsync, flushMicrotasks, Log, tick} from '@angular/core/testing';
import {ControlGroup, Control, Validators, AbstractControl, ControlArray} from '@angular/common';
import {PromiseWrapper} from '../../src/facade/promise';
import {EventEmitter, ObservableWrapper, TimerWrapper} from '../../src/facade/async';
export function main() {
function validator(key: string, error: any) {
@ -35,6 +32,9 @@ export function main() {
it("should not error on a non-empty string",
() => { expect(Validators.required(new Control("not empty"))).toEqual(null); });
it("should accept zero as valid",
() => { expect(Validators.required(new Control(0))).toEqual(null); });
});
describe("minLength", () => {
@ -63,12 +63,28 @@ export function main() {
it("should not error on valid strings",
() => { expect(Validators.maxLength(2)(new Control("aa"))).toEqual(null); });
it("should error on short strings", () => {
it("should error on long strings", () => {
expect(Validators.maxLength(2)(new Control("aaa")))
.toEqual({"maxlength": {"requiredLength": 2, "actualLength": 3}});
});
});
describe("pattern", () => {
it("should not error on an empty string",
() => { expect(Validators.pattern("[a-zA-Z ]*")(new Control(""))).toEqual(null); });
it("should not error on null",
() => { expect(Validators.pattern("[a-zA-Z ]*")(new Control(null))).toEqual(null); });
it("should not error on valid strings",
() => { expect(Validators.pattern("[a-zA-Z ]*")(new Control("aaAA"))).toEqual(null); });
it("should error on failure to match string", () => {
expect(Validators.pattern("[a-zA-Z ]*")(new Control("aaa0")))
.toEqual({"pattern": {"requiredPattern": "^[a-zA-Z ]*$", "actualValue": "aaa0"}});
});
});
describe("compose", () => {
it("should return null when given null",
() => { expect(Validators.compose(null)).toBe(null); });
@ -121,7 +137,7 @@ export function main() {
]);
var value = null;
c(new Control("invalid")).then(v => value = v);
(<Promise<any>>c(new Control("invalid"))).then(v => value = v);
tick(1);
@ -132,7 +148,7 @@ export function main() {
var c = Validators.composeAsync([asyncValidator("expected", {"one": true})]);
var value = null;
c(new Control("expected")).then(v => value = v);
(<Promise<any>>c(new Control("expected"))).then(v => value = v);
tick(1);
@ -143,7 +159,7 @@ export function main() {
var c = Validators.composeAsync([asyncValidator("expected", {"one": true}), null]);
var value = null;
c(new Control("invalid")).then(v => value = v);
(<Promise<any>>c(new Control("invalid"))).then(v => value = v);
tick(1);

View File

@ -7,22 +7,22 @@ import {
expect,
beforeEach,
afterEach,
AsyncTestCompleter,
inject,
browserDetection
} from 'angular2/testing_internal';
} from '@angular/core/testing/testing_internal';
import {AsyncTestCompleter} from '@angular/core/testing/testing_internal';
import {SpyChangeDetectorRef} from '../spies';
import {isBlank} from 'angular2/src/facade/lang';
import {AsyncPipe} from 'angular2/common';
import {WrappedValue} from 'angular2/core';
import {isBlank} from '../../src/facade/lang';
import {AsyncPipe} from '@angular/common';
import {WrappedValue} from '@angular/core';
import {
EventEmitter,
ObservableWrapper,
PromiseWrapper,
TimerWrapper
} from 'angular2/src/facade/async';
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
} from '../../src/facade/async';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
import {PromiseCompleter} from '../../src/facade/promise';
import {browserDetection} from '@angular/platform-browser/testing';
export function main() {
describe("AsyncPipe", () => {
@ -92,7 +92,7 @@ export function main() {
TimerWrapper.setTimeout(() => {
expect(ref.spy('markForCheck')).toHaveBeenCalled();
async.done();
}, 0)
}, 10)
}));
});
@ -116,16 +116,16 @@ export function main() {
describe("Promise", () => {
var message = new Object();
var pipe;
var completer;
var ref;
var pipe: AsyncPipe;
var completer: PromiseCompleter<any>;
var ref: SpyChangeDetectorRef;
// adds longer timers for passing tests in IE
var timer = (!isBlank(DOM) && browserDetection.isIE) ? 50 : 0;
var timer = (!isBlank(getDOM()) && browserDetection.isIE) ? 50 : 10;
beforeEach(() => {
completer = PromiseWrapper.completer();
ref = new SpyChangeDetectorRef();
pipe = new AsyncPipe(ref);
pipe = new AsyncPipe(<any>ref);
});
describe("transform", () => {
@ -173,11 +173,12 @@ export function main() {
it("should request a change detection check upon receiving a new value",
inject([AsyncTestCompleter], (async) => {
var markForCheck = ref.spy('markForCheck');
pipe.transform(completer.promise);
completer.resolve(message);
TimerWrapper.setTimeout(() => {
expect(ref.spy('markForCheck')).toHaveBeenCalled();
expect(markForCheck).toHaveBeenCalled();
async.done();
}, timer)
}));
@ -206,14 +207,14 @@ export function main() {
describe('null', () => {
it('should return null when given null', () => {
var pipe = new AsyncPipe(null);
expect(pipe.transform(null, [])).toEqual(null);
expect(pipe.transform(null)).toEqual(null);
});
});
describe('other types', () => {
it('should throw when given an invalid object', () => {
var pipe = new AsyncPipe(null);
expect(() => pipe.transform(<any>"some bogus object", [])).toThrowError();
expect(() => pipe.transform(<any>"some bogus object")).toThrowError();
});
});
});

View File

@ -0,0 +1,82 @@
import {
ddescribe,
describe,
it,
iit,
xit,
expect,
beforeEach,
afterEach
} from '@angular/core/testing/testing_internal';
import {browserDetection} from '@angular/platform-browser/testing';
import {DatePipe} from '@angular/common';
import {DateWrapper} from '../../src/facade/lang';
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
export function main() {
describe("DatePipe", () => {
var date;
var pipe;
beforeEach(() => {
date = DateWrapper.create(2015, 6, 15, 21, 43, 11);
pipe = new DatePipe();
});
it('should be marked as pure',
() => { expect(new PipeResolver().resolve(DatePipe).pure).toEqual(true); });
describe("supports", () => {
it("should support date", () => { expect(pipe.supports(date)).toBe(true); });
it("should support int", () => { expect(pipe.supports(123456789)).toBe(true); });
it("should not support other objects", () => {
expect(pipe.supports(new Object())).toBe(false);
expect(pipe.supports(null)).toBe(false);
});
});
// TODO(mlaval): enable tests when Intl API is no longer used, see
// https://github.com/angular/angular/issues/3333
if (browserDetection.supportsIntlApi) {
describe("transform", () => {
it('should format each component correctly', () => {
expect(pipe.transform(date, 'y')).toEqual('2015');
expect(pipe.transform(date, 'yy')).toEqual('15');
expect(pipe.transform(date, 'M')).toEqual('6');
expect(pipe.transform(date, 'MM')).toEqual('06');
expect(pipe.transform(date, 'MMM')).toEqual('Jun');
expect(pipe.transform(date, 'MMMM')).toEqual('June');
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, 'm')).toEqual('43');
expect(pipe.transform(date, 's')).toEqual('11');
});
it('should format common multi component patterns', () => {
expect(pipe.transform(date, 'yMEd')).toEqual('Mon, 6/15/2015');
expect(pipe.transform(date, 'MEd')).toEqual('Mon, 6/15');
expect(pipe.transform(date, 'MMMd')).toEqual('Jun 15');
expect(pipe.transform(date, 'yMMMMEEEEd')).toEqual('Monday, June 15, 2015');
expect(pipe.transform(date, 'jms')).toEqual('9:43:11 PM');
expect(pipe.transform(date, 'ms')).toEqual('43:11');
});
it('should format with pattern aliases', () => {
expect(pipe.transform(date, 'medium')).toEqual('Jun 15, 2015, 9:43:11 PM');
expect(pipe.transform(date, 'short')).toEqual('6/15/2015, 9:43 PM');
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:43:11 PM');
expect(pipe.transform(date, 'shortTime')).toEqual('9:43 PM');
});
});
}
});
}

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