837efc2 chore(bundles): properly publish router.min.js bundle

This commit is contained in:
Pawel Kozlowski
2015-11-18 19:25:08 +00:00
parent dbf8f88a9e
commit 09dda358b7
2014 changed files with 388683 additions and 33446 deletions
+2 -2
View File
@@ -1,2 +1,2 @@
Wed Nov 18 19:17:00 UTC 2015
c855c5ddc2642cc1c8da6463082d785f5c80874b
Wed Nov 18 19:25:08 UTC 2015
837efc2a0febada12ff56024406bfe72ec5b340a
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"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.
View File
+8
View File
@@ -0,0 +1,8 @@
export * from './common';
export * from './core';
export * from './profile';
export * from './lifecycle_hooks';
export * from './platform/browser';
export * from './upgrade';
export { UrlResolver, AppRootUrl } from './compiler';
import "./manual_typings/globals-es6.d.ts";
Vendored
+1 -1
View File
@@ -1,4 +1,4 @@
function __export(m) {
'use strict';function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
__export(require('./common'));
+1 -1
View File
@@ -1,4 +1,4 @@
var ng = require('./angular2');
'use strict';var ng = require('./angular2');
// the router and http should have their own SFX bundle
// But currently the module arithmetic 'angular2/router_sfx - angular2/angular2',
// is not support by system builder.
+5
View File
@@ -0,0 +1,5 @@
export { Animation } from './src/animate/animation';
export { AnimationBuilder } from './src/animate/animation_builder';
export { BrowserDetails } from './src/animate/browser_details';
export { CssAnimationBuilder } from './src/animate/css_animation_builder';
export { CssAnimationOptions } from './src/animate/css_animation_options';
+1 -1
View File
@@ -1,4 +1,4 @@
var animation_1 = require('./src/animate/animation');
'use strict';var animation_1 = require('./src/animate/animation');
exports.Animation = animation_1.Animation;
var animation_builder_1 = require('./src/animate/animation_builder');
exports.AnimationBuilder = animation_builder_1.AnimationBuilder;
+5
View File
@@ -0,0 +1,5 @@
/**
* See {@link bootstrap} for more information.
* @deprecated
*/
export { bootstrap } from 'angular2/platform/browser';
+1 -1
View File
@@ -1,4 +1,4 @@
/**
'use strict';/**
* See {@link bootstrap} for more information.
* @deprecated
*/
+5
View File
@@ -0,0 +1,5 @@
/**
* See {@link bootstrap} for more information.
* @deprecated
*/
export { bootstrapStatic } from 'angular2/platform/browser_static';
+1 -1
View File
@@ -1,4 +1,4 @@
/**
'use strict';/**
* See {@link bootstrap} for more information.
* @deprecated
*/
File diff suppressed because one or more lines are too long
+38924
View File
File diff suppressed because one or more lines are too long
+26
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1177
View File
File diff suppressed because it is too large Load Diff
+1177
View File
File diff suppressed because it is too large Load Diff
+1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+2413
View File
File diff suppressed because it is too large Load Diff
+2
View File
File diff suppressed because one or more lines are too long
+2074
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+4
View File
@@ -0,0 +1,4 @@
export * from './src/common/pipes';
export * from './src/common/directives';
export * from './src/common/forms';
export * from './src/common/common_directives';
+1 -1
View File
@@ -1,4 +1,4 @@
function __export(m) {
'use strict';function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
__export(require('./src/common/pipes'));
+9
View File
@@ -0,0 +1,9 @@
/**
* @module
* @description
* Starting point to import all compiler APIs.
*/
export * from './src/compiler/url_resolver';
export * from './src/compiler/xhr';
export * from './src/compiler/compiler';
export * from './src/compiler/app_root_url';
+1 -1
View File
@@ -1,4 +1,4 @@
function __export(m) {
'use strict';function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
/**
Vendored
+26
View File
@@ -0,0 +1,26 @@
/**
* @module
* @description
* Starting point to import all public core APIs.
*/
export * from './src/core/metadata';
export * from './src/core/util';
export * from './src/core/di';
export * from './src/common/pipes';
export * from './src/facade/facade';
export * from './src/core/linker';
export { platform, createNgZone, PlatformRef, ApplicationRef } from './src/core/application_ref';
export { APP_ID, APP_COMPONENT } from './src/core/application_tokens';
export * from './src/core/zone';
export * from './src/core/render';
export * from './src/common/directives';
export * from './src/common/forms';
export { DebugElement, Scope, inspectElement, asNativeElements } from './src/core/debug/debug_element';
export * from './src/core/testability/testability';
export * from './src/core/change_detection';
export * from './src/core/platform_directives_and_pipes';
export * from './src/core/dev_mode';
export * from './src/core/reflection/reflection';
export * from './src/core/application_common_providers';
export * from './src/core/platform_common_providers';
export * from './src/core/dom/dom_adapter';
+1 -1
View File
@@ -1,4 +1,4 @@
function __export(m) {
'use strict';function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
/**
-10
View File
@@ -1,10 +0,0 @@
@name Change Detection
@description
# Change Detection
* Mechanisms by which changes are detected in the model
* DAG
* Order of evaluation
* Pure Functions
* `onChange` method
* Parser
-7
View File
@@ -1,7 +0,0 @@
# Expressions
## Binding Semantics
### Formatters
## Statement Semantics
-3
View File
@@ -1,3 +0,0 @@
# Record
## RecordRange
-9
View File
@@ -1,9 +0,0 @@
@cheatsheetSection
Bootstrapping
@cheatsheetIndex 0
@description
`import {bootstrap} from 'angular2/angular2';`
@cheatsheetItem
`bootstrap​(MyAppComponent, [MyService, provide(...)]);`
Bootstraps an application with MyAppComponent as the root component and configures the DI providers.
-25
View File
@@ -1,25 +0,0 @@
@cheatsheetSection
Built-in directives
@cheatsheetIndex 2
@description
`import {NgIf, ...} from 'angular2/angular2';`
@cheatsheetItem
`<section *ng-if="showSection">`|`*ng-if`
Removes or recreates a portion of the DOM tree based on the showSection expression.
@cheatsheetItem
`<li *ng-for="#item of list">`|`*ng-for`
Turns the li element and its contents into a template, and uses that to instantiate a view for each item in list.
@cheatsheetItem
`<div [ng-switch]="conditionExpression">
<template [ng-switch-when]="case1Exp">...</template>
<template ng-switch-when="case2LiteralString">...</template>
<template ng-switch-default>...</template>
</div>`|`[ng-switch]`|`[ng-switch-when]`|`ng-switch-when`|`ng-switch-default`
Conditionally swaps the contents of the div by selecting one of the embedded templates based on the current value of conditionExpression.
@cheatsheetItem
`<div [ng-class]="{active: isActive, disabled: isDisabled}">`|`[ng-class]`
Binds the presence of css classes on the element to the truthiness of the associated map values. The right-hand side expression should return {class-name: true/false} map.
-21
View File
@@ -1,21 +0,0 @@
@cheatsheetSection
Class decorators
@cheatsheetIndex 4
@description
`import {Directive, ...} from 'angular2/angular2';`
@cheatsheetItem
`@Component({...})
class MyComponent() {}`|`@Component({...})`
Declares that a class is a component and provides metadata about the component.
@cheatsheetItem
`@Pipe({...})
class MyPipe() {}`|`@Pipe({...})`
Declares that a class is a pipe and provides metadata about the pipe.
@cheatsheetItem
`@Injectable()
class MyService() {}`|`@Injectable()`
Declares that a class has dependencies that should be injected into the constructor when the dependency
injector is creating an instance of this class.
@@ -1,32 +0,0 @@
@cheatsheetSection
Component configuration
@cheatsheetIndex 6
@description
`@Component` extends `@Directive`,
so the `@Directive` configuration applies to components as well
@cheatsheetItem
`viewProviders: [MyService, provide(...)]`|`viewProviders:`
Array of dependency injection providers scoped to this component's view.
@cheatsheetItem
`template: 'Hello {{name}}'
templateUrl: 'my-component.html'`|`template:`|`templateUrl:`
Inline template / external template url of the component's view.
@cheatsheetItem
`styles: ['.primary {color: red}']
styleUrls: ['my-component.css']`|`styles:`|`styleUrls:`
List of inline css styles / external stylesheet urls for styling component’s view.
@cheatsheetItem
`directives: [MyDirective, MyComponent]`|`directives:`
List of directives used in the the component’s template.
@cheatsheetItem
`pipes: [MyPipe, OtherPipe]`|`pipes:`
List of pipes used in the component's template.
-20
View File
@@ -1,20 +0,0 @@
@cheatsheetSection
Dependency injection configuration
@cheatsheetIndex 9
@description
`import {provide} from 'angular2/angular2';`
@cheatsheetItem
`provide(MyService, {useClass: MyMockService})``provide`|`useClass`
Sets or overrides the provider for MyService to the MyMockService class.
@cheatsheetItem
`provide(MyService, {useFactory: myFactory})``provide`|`useFactory`
Sets or overrides the provider for MyService to the myFactory factory function.
@cheatsheetItem
`provide(MyValue, {useValue: 41})``provide`|`useValue`
Sets or overrides the provider for MyValue to the value 41.
@@ -1,46 +0,0 @@
@cheatsheetSection
Class field decorators for directives and components
@cheatsheetIndex 7
@description
`import {Input, ...} from 'angular2/angular2';`
@cheatsheetItem
`@Input() myProperty;`|`@Input()`
Declares an input property that we can update via property binding, e.g.
`<my-cmp [my-property]="someExpression">`
@cheatsheetItem
`@Output() myEvent = new EventEmitter();`|`@Output()`
Declares an output property that fires events to which we can subscribe with an event binding, e.g. `<my-cmp (my-event)="doSomething()">`
@cheatsheetItem
`@HostBinding('[class.valid]') isValid;`|`@HostBinding('[class.valid]')`
Binds a host element property (e.g. css class valid) to directive/component property (e.g. isValid)
@cheatsheetItem
`@HostListener('click', ['$event']) onClick(e) {...}`|`@HostListener('click', ['$event'])`
Subscribes to a host element event (e.g. click) with a directive/component method (e.g., onClick), optionally passing an argument ($event)
@cheatsheetItem
`@ContentChild(myPredicate) myChildComponent;`|`@ContentChild(myPredicate)`
Binds the first result of the component content query (myPredicate) to the myChildComponent property of the class.
@cheatsheetItem
`@ContentChildren(myPredicate) myChildComponents;`|`@ContentChildren(myPredicate)`
Binds the results of the component content query (myPredicate) to the myChildComponents property of the class.
@cheatsheetItem
`@ViewChild(myPredicate) myChildComponent;`|`@ViewChild(myPredicate)`
Binds the first result of the component view query (myPredicate) to the myChildComponent property of the class. Not available for directives.
@cheatsheetItem
`@ViewChildren(myPredicate) myChildComponents;`|`@ViewChildren(myPredicate)`
Binds the results of the component view query (myPredicate) to the myChildComponents property of the class. Not available for directives.
@@ -1,16 +0,0 @@
@cheatsheetSection
Directive configuration
@cheatsheetIndex 5
@description
`@Directive({ property1: value1, ... }) )`
@cheatsheetItem
`selector: '.cool-button:not(a)'`|`selector:`
Specifies a css selector that identifies this directive within a template. Supported selectors include: `element`,
`[attribute]`, `.class`, and `:not()`.
Does not support parent-child relationship selectors.
@cheatsheetItem
`providers: [MyService, provide(...)]`|`providers:`
Array of dependency injection providers for this directive and its children.
-9
View File
@@ -1,9 +0,0 @@
@cheatsheetSection
Forms
@cheatsheetIndex 3
@description
`import {FORM_DIRECTIVES} from 'angular2/angular2';`
@cheatsheetItem
`<input [(ng-model)]="userName">`|`[(ng-model)]`
Provides two-way data-binding, parsing and validation for form controls.
-49
View File
@@ -1,49 +0,0 @@
@cheatsheetSection
Directive and component change detection and lifecycle hooks
@cheatsheetIndex 8
@description
(implemented as class methods)
@cheatsheetItem
`constructor(myService: MyService, ...) { ... }`|`constructor(myService: MyService, ...)`
The class constructor is called before any other lifecycle hook. Use it to inject dependencies, but avoid any serious work here.
@cheatsheetItem
`onChanges(changeRecord) { ... }`|`onChanges(changeRecord)`
Called after every change to input properties and before processing content or child views.
@cheatsheetItem
`onInit() { ... }`|`onInit()`
Called after the constructor, initializing input properties, and the first call to onChanges.
@cheatsheetItem
`doCheck() { ... }`|`doCheck()`
Called every time that the input properties of a component or a directive are checked. Use it to extend change detection by performing a custom check.
@cheatsheetItem
`afterContentInit() { ... }`|`afterContentInit()`
Called after onInit when the component's or directive's content has been initialized.
@cheatsheetItem
`afterContentChecked() { ... }`|`afterContentChecked()`
Called after every check of the component's or directive's content.
@cheatsheetItem
`afterViewInit() { ... }`|`afterViewInit()`
Called after afterContentInit when the component's view has been initialized. Applies to components only.
@cheatsheetItem
`afterViewChecked() { ... }`|`afterViewChecked()`
Called after every check of the component's view. Applies to components only.
@cheatsheetItem
`onDestroy() { ... }`|`onDestroy()`
Called once, before the instance is destroyed.
-55
View File
@@ -1,55 +0,0 @@
@cheatsheetSection
Routing and navigation
@cheatsheetIndex 10
@description
`import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, ...} from 'angular2/router';`
@cheatsheetItem
`@RouteConfig([
{ path: '/:myParam', component: MyComponent, as: 'MyCmp' },
{ path: '/staticPath', component: ..., as: ...},
{ path: '/*wildCardParam', component: ..., as: ...}
])
class MyComponent() {}`|`@RouteConfig`
Configures routes for the decorated component. Supports static, parameterized and wildcard routes.
@cheatsheetItem
`<router-outlet></router-outlet>`|`router-outlet`
Marks the location to load the component of the active route.
@cheatsheetItem
`<a [router-link]="[ '/MyCmp', {myParam: 'value' } ]">`|`[router-link]`
Creates a link to a different view based on a route instruction consisting of a route name and optional parameters. The route name matches the as property of a configured route. Add the '/' prefix to navigate to a root route; add the './' prefix for a child route.
@cheatsheetItem
`@CanActivate(() => { ... })class MyComponent() {}`|`@CanActivate`
A component decorator defining a function that the router should call first to determine if it should activate this component. Should return a boolean or a promise.
@cheatsheetItem
`onActivate(nextInstruction, prevInstruction) { ... }`|`onActivate`
After navigating to a component, the router calls component's onActivate method (if defined).
@cheatsheetItem
`canReuse(nextInstruction, prevInstruction) { ... }`|`canReuse`
The router calls a component's canReuse method (if defined) to determine whether to reuse the instance or destroy it and create a new instance. Should return a boolean or a promise.
@cheatsheetItem
`onReuse(nextInstruction, prevInstruction) { ... }`|`onReuse`
The router calls the component's onReuse method (if defined) when it re-uses a component instance.
@cheatsheetItem
`canDeactivate(nextInstruction, prevInstruction) { ... }`|`canDeactivate`
The router calls the canDeactivate methods (if defined) of every component that would be removed after a navigation. The navigation proceeds if and only if all such methods return true or a promise that is resolved.
@cheatsheetItem
`onDeactivate(nextInstruction, prevInstruction) { ... }`|`onDeactivate`
Called before the directive is removed as the result of a route change. May return a promise that pauses removing the directive until the promise resolves.
-56
View File
@@ -1,56 +0,0 @@
@cheatsheetSection
Template syntax
@cheatsheetIndex 1
@description
@cheatsheetItem
`<input [value]="firstName">`|`[value]`
Binds property `value` to the result of expression `firstName`.
@cheatsheetItem
`<div [attr.role]="myAriaRole">`|`[attr.role]`
Binds attribute `role` to the result of expression `myAriaRole`.
@cheatsheetItem
`<div [class.extra-sparkle]="isDelightful">`|`[class.extra-sparkle]`
Binds the presence of the css class `extra-sparkle` on the element to the truthiness of the expression `isDelightful`.
@cheatsheetItem
`<div [style.width.px]="mySize">`|`[style.width.px]`
Binds style property `width` to the result of expression `mySize` in pixels. Units are optional.
@cheatsheetItem
`<button (click)="readRainbow($event)">`|`(click)`
Calls method `readRainbow` when a click event is triggered on this button element (or its children) and passes in the event object.
@cheatsheetItem
`<div title="Hello {{ponyName}}">`|`{{ponyName}}`
Binds a property to an interpolated string, e.g. "Hello Seabiscuit". Equivalent to:
`<div [title]="'Hello' + ponyName">`
@cheatsheetItem
`<p>Hello {{ponyName}}</p>`|`{{ponyName}}`
Binds text content to an interpolated string, e.g. "Hello Seabiscuit".
@cheatsheetItem
`<my-cmp [(title)]="name">`|`[(title)]`
Sets up two-way data binding. Equivalent to: `<my-cmp [title]="name" (title-change)="name=$event">`
@cheatsheetItem
`<video #movieplayer ...>
<button (click)="movieplayer.play()">
</video>`|`#movieplayer`|`(click)`
Creates a local variable `movieplayer` that provides access to the `video` element instance in data-binding and event-binding expressions in the current template.
@cheatsheetItem
`<p *my-unless="myExpression">...</p>`|`*my-unless`
The `*` symbol means that the current element will be turned into an embedded template. Equivalent to:
`<template [myless]="myExpression"><p>...</p></template>`
@cheatsheetItem
`<p>Card No.: {{cardNumber | myCreditCardNumberFormatter}}</p>`|`{{cardNumber | myCreditCardNumberFormatter}}`
Transforms the current value of expression `cardNumber` via the pipe called `creditCardNumberFormatter`.
@cheatsheetItem
`<p>Employer: {{employer?.companyName}}</p>`|`{{employer?.companyName}}`
The Elvis operator (`?`) means that the `employer` field is optional and if `undefined`, the rest of the expression should be ignored.
-3
View File
@@ -1,3 +0,0 @@
# Overview
* High level description of all of the components.
-610
View File
@@ -1,610 +0,0 @@
# Templates
Templates are markup which is added to HTML to declaratively describe how the application model should be
projected to DOM as well as which DOM events should invoke which methods on the controller. Templates contain
syntaxes which are core to Angular and allows for data-binding, event-binding, template-instantiation.
The design of the template syntax has these properties:
* All data-binding expressions are easily identifiable. (i.e. there is never an ambiguity whether the value should be
interpreted as string literal or as an expression.)
* All events and their statements are easily identifiable.
* All places of DOM instantiation are easily identifiable.
* All places of variable declaration are easily identifiable.
The above properties guarantee that the templates are easy to parse by tools (such as IDEs) and reason about by people.
At no point is it necessary to understand which directives are active or what their semantics are in order to reason
about the template runtime characteristics.
## Summary
Below is a summary of the kinds of syntaxes which Angular templating supports. The syntaxes are explained in more
detail in the following sections.
<table>
<thead>
<tr>
<th>Description</th><th>Short</th><th>Canonical</th>
</tr>
</thead>
<tbody>
<tr>
<th>Text Interpolation</th>
<td>
<pre>
&lt;div&gt;{{exp}}&lt;/div&gt;
</pre>
Example:
<pre>
&lt;div&gt;
Hello {{name}}!
&lt;br&gt;
Goodbye {{name}}!
&lt;/div&gt;
</pre>
</td>
<td>
<pre>
&lt;div [text|index]="exp"&gt;&lt;/div&gt;
</pre>
Example:
<pre>
&lt;div
[text|0]=" 'Hello' + stringify(name) + '!' "
[text|2]=" 'Goodbye' + stringify(name) + '!' "&gt;
&lt;b&gt;x&lt;/b&gt;
&lt;/div&gt;
</pre>
</td>
</tr>
<tr>
<th>Property Interpolation</th>
<td>
<pre>
&lt;div name="{{exp}}"&gt;&lt;/div&gt;
</pre>
Example:
<pre>
&lt;div class="{{selected}}"&gt;&lt;/div&gt;
</pre>
</td>
<td>
<pre>
&lt;div [name]="stringify(exp)"&gt;&lt;/div&gt;
</pre>
Example:
<pre>
&lt;div [title]="stringify(selected)"&gt;&lt;/div&gt;
</pre>
</td>
</tr>
<tr>
<th>Property binding</th>
<td>
<pre>
&lt;div [prop]="exp"&gt;&lt;/div&gt;
</pre>
Example:
<pre>
&lt;div [hidden]="true"&gt;&lt;/div&gt;
</pre>
</td>
<td>
<pre>
&lt;div bind-prop="exp"&gt;&lt;/div&gt;
</pre>
Example:
<pre>
&lt;div bind-hidden="true"&gt;&lt;/div&gt;
</pre>
</td>
</tr>
<tr>
<th>Event binding (non-bubbling)</th>
<td>
<pre>
&lt;div (event)="statement"&gt;&lt;/div&gt;
</pre>
Example:
<pre>
&lt;div (click)="doX()"&gt;&lt;/div&gt;
</pre>
</td>
<td>
<pre>
&lt;div on-event="statement"&gt;&lt;/div&gt;
</pre>
Example:
<pre>
&lt;video #player&gt;
&lt;button (click)="player.play()"&gt;play&lt;/button&gt;
&lt;/video&gt;
</pre>
Or:
<pre>
&lt;div def="symbol"&gt;&lt;/div&gt;
</pre>
Example:
<pre>
&lt;video def="player"&gt;
&lt;button on-click="player.play()"&gt;play&lt;/button&gt;
&lt;/video&gt;
</pre>
</td>
</tr>
<tr>
<th>Inline Template</th>
<td>
<pre>
&lt;div template="..."&gt;...&lt;/div&gt;
</pre>
Example:
<pre>
&lt;ul&gt;
&lt;li template="for: #item of items"&gt;
{{item}}
&lt;/li&gt;
&lt;/ul&gt;
</pre>
</td>
<td>
<pre>
&lt;template&gt;...&lt;/template&gt;
</pre>
Example:
<pre>
&lt;ul&gt;
&lt;template def-for:"item"
bind-for-in="items"&gt;
&lt;li&gt;
{{item}}
&lt;/li&gt;
&lt;/template&gt;
&lt;/ul&gt;
</pre>
</td>
</tr>
<tr>
<th>Explicit Template</th>
<td>
<pre>
&lt;template&gt;...&lt;/template&gt;
</pre>
Example:
<pre>
&lt;template #for="item"
[for-in]="items"&gt;
_some_content_to_repeat_
&lt;/template&gt;
</pre>
</td>
<td>
<pre>
&lt;template&gt;...&lt;/template&gt;
</pre>
Example:
<pre>
&lt;template def-for="item"
bind-for-in="items"&gt;
_some_content_to_repeat_
&lt;/template&gt;
</pre>
</td>
</tr>
</tbody>
</table>
## Property Binding
Binding application model data to the UI is the most common kind of bindings in an Angular application. The bindings
are always in the form of `property-name` which is assigned an `expression`. The generic form is:
<table>
<tr>
<th>Short form</th>
<td><pre>&lt;some-element [some-property]="expression"&gt;</pre></td>
</tr>
<tr>
<th>Canonical form</th>
<td><pre>&lt;some-element bind-some-property="expression"&gt;</pre></td>
</tr>
</table>
Where:
* `some-element` can be any existing DOM element.
* `some-property` (escaped with `[]` or `bind-`) is the name of the property on `some-element`. In this case the
dash-case is converted into camel-case `someProperty`.
* `expression` is a valid expression (as defined in section below).
Example:
```
<div [title]="user.firstName">
```
In the above example the `title` property of the `div` element will be updated whenever the `user.firstName` changes
its value.
Key points:
* The binding is to the element property not the element attribute.
* To prevent custom element from accidentally reading the literal `expression` on the title element, the attribute name
is escaped. In our case the `title` is escaped to `[title]` through the addition of square brackets `[]`.
* A binding value (in this case `user.firstName`) will always be an expression, never a string literal.
NOTE: Unlike Angular v1, Angular v2 binds to properties of elements rather than attributes of elements. This is
done to better support custom elements, and to allow binding for values other than strings.
NOTE: Some editors/server side pre-processors may have trouble generating `[]` around the attribute name. For this
reason Angular also supports a canonical version which is prefixed using `bind-`.
### String Interpolation
Property bindings are the only data bindings which Angular supports, but for convenience Angular supports an interpolation
syntax which is just a short hand for the data binding syntax.
```
<span>Hello {{name}}!</span>
```
is a short hand for:
```
<span [text|0]=" 'Hello ' + stringify(name) + '!' "></span>
```
The above says to bind the `'Hello ' + stringify(name) + '!'` expression to the zero-th child of the `span`'s `text`
property. The index is necessary in case there are more than one text nodes, or if the text node we wish to bind to
is not the first one.
Similarly the same rules apply to interpolation inside attributes.
```
<span title="Hello {{name}}!"></span>
```
is a short hand for:
```
<span [title]=" 'Hello ' + stringify(name) + '!' "></span>
```
NOTE: `stringify()` is a built in implicit function which converts its argument to a string representation, while
keeping `null` and `undefined` as empty strings.
## Local Variables
## Inline Templates
Data binding allows updating the DOM's properties, but it does not allow for changing of the DOM structure. To change
DOM structure we need the ability to define child templates, and then instantiate these templates into Views. The
Views than can be inserted and removed as needed to change the DOM structure.
<table>
<tr>
<th>Short form</th>
<td>
<pre>
parent template
&lt;element&gt;
&lt;some-element template="instantiating-directive-microsyntax"&gt;child template&lt;/some-element&gt;
&lt;/element&gt;
</pre>
</td>
</tr>
<tr>
<th>Canonical form</th>
<td>
<pre>
parent template
&lt;element&gt;
&lt;template instantiating-directive-bindings&gt;
&lt;some-element&gt;child template&lt;/some-element&gt;
&lt;/template&gt;
&lt;/element&gt;
</pre>
</td>
</tr>
</table>
Where:
* `template` defines a child template and designates the anchor where Views (instances of the template) will be
inserted. The template can be defined implicitly with `template` attribute, which turns the current element into
a template, or explicitly with `<template>` element. Explicit declaration is longer, but it allows for having
templates which have more than one root DOM node.
* `viewport` is required for templates. The directive is responsible for deciding when
and in which order should child views be inserted into this location. Such a directive usually has one or
more bindings and can be represented as either `viewport-directive-bindings` or
`viewport-directive-microsyntax` on `template` element or attribute. See template microsyntax for more details.
Example of conditionally included template:
```
Hello {{user}}!
<div template="ng-if: isAdministrator">
...administrator menu here...
</div>
```
In the above example the `ng-if` directive determines whether the child view (an instance of the child template) should be
inserted into the root view. The `ng-if` makes this decision based on if the `isAdministrator` binding is true.
The above example is in the short form, for better clarity let's rewrite it in the canonical form, which is functionally
identical.
```
Hello {{user}}!
<template [ng-if]="isAdministrator">
<div>
...administrator menu here...
</div>
</template>
```
### Template Microsyntax
Often times it is necessary to encode a lot of different bindings into a template to control how the instantiation
of the templates occurs. One such example is `ng-for`.
```
<form #foo=form>
</form>
<ul>
<template [ng-for] #person [ng-for-of]="people" #i="index">
<li>{{i}}. {{person}}<li>
</template>
</ul>
```
Where:
* `[ng-for]` triggers the for directive.
* `#person` exports the implicit `ng-for` item.
* `[ng-for-of]="people"` binds an iterable object to the `ng-for` controller.
* `#i=index` exports item index as `i`.
The above example is explicit but quite wordy. For this reason in most situations a short hand version of the
syntax is preferable.
```
<ul>
<li template="ng-for; #person; of=people; #i=index;">{{i}}. {{person}}<li>
</ul>
```
Notice how each key value pair is translated to a `key=value;` statement in the `template` attribute. This makes the
repeat syntax a much shorter, but we can do better. Turns out that most punctuation is optional in the short version
which allows us to further shorten the text.
```
<ul>
<li template="ng-for #person of people #i=index">{{i}}. {{person}}<li>
</ul>
```
We can also optionally use `var` instead of `#` and add `:` to `for` which creates the following recommended
microsyntax for `ng-for`.
```
<ul>
<li template="ng-for: var person of people; var i=index">{{i}}. {{person}}<li>
</ul>
```
Finally, we can move the `ng-for` keyword to the left hand side and prefix it with `*` as so:
```
<ul>
<li *ng-for="var person of people; var i=index">{{i}}. {{person}}<li>
</ul>
```
The format is intentionally defined freely, so that developers of directives can build an expressive microsyntax for
their directives. The following code describes a more formal definition.
```
expression: ... // as defined in Expressions section
local: [a-zA-Z][a-zA-Z0-9]* // exported variable name available for binding
internal: [a-zA-Z][a-zA-Z0-9]* // internal variable name which the directive exports.
key: [a-z][-|_|a-z0-9]]* // key which maps to attribute name
keyExpression: key[:|=]?expression // binding which maps an expression to a property
varExport: [#|var]local(=internal)? // binding which exports a local variable from a directive
microsyntax: ([[key|keyExpression|varExport][;|,]?)*
```
Where
* `expression` is an Angular expression as defined in section: Expressions.
* `local` is a local identifier for local variables.
* `internal` is an internal variable which the directive exports for binding.
* `key` is an attribute name usually only used to trigger a specific directive.
* `keyExpression` is an property name to which the expression will be bound to.
* `varExport` allows exporting of directive internal state as variables for further binding. If no `internal` name
is specified, the exporting is to an implicit variable.
* `microsyntax` allows you to build a simple microsyntax which can still clearly identify which expressions bind to
which properties as well as which variables are exported for binding.
NOTE: the `template` attribute must be present to make it clear to the user that a sub-template is being created. This
goes along with the philosophy that the developer should be able to reason about the template without understanding the
semantics of the instantiator directive.
## Binding Events
Binding events allows wiring events from DOM (or other components) to the Angular controller.
<table>
<tr>
<th>Short form</th>
<td><pre>&lt;some-element (some-event)="statement"&gt;</pre></td>
</tr>
<tr>
<th>Canonical form</th>
<td><pre>&lt;some-element on-some-event="statement"&gt;</pre></td>
</tr>
</table>
Where:
* `some-element` Any element which can generate DOM events (or has an angular directive which generates the event).
* `some-event` (escaped with `()` or `on-`) is the name of the event `some-event`. In this case the
dash-case is converted into camel-case `someEvent`.
* `statement` is a valid statement (as defined in section below).
If the execution of the statement returns `false`, then `preventDefault`is applied on the DOM event.
Angular listens to bubbled DOM events (as in the case of clicking on any child), as shown below:
<table>
<tr>
<th>Short form</th>
<td><pre>&lt;some-element (some-event)="statement"&gt;</pre></td>
</tr>
<tr>
<th>Canonical form</th>
<td><pre>&lt;some-element on-some-event="statement"&gt;</pre></td>
</tr>
</table>
Example:
```
@Component(...)
class Example {
submit() {
// do something when button is clicked
}
}
<button (click)="submit()">Submit</button>
```
In the above example, when clicking on the submit button angular will invoke the `submit` method on the surrounding
component's controller.
NOTE: Unlike Angular v1, Angular v2 treats event bindings as core constructs not as directives. This means that there
is no need to create an event directive for each kind of event. This makes it possible for Angular v2 to easily
bind to custom events of Custom Elements, whose event names are not known ahead of time.
## Expressions, Statements and Formatters
Angular templates contain expressions for binding to data and statements for binding to events. Expressions and statements
have different semantics.
### Expressions
Expressions can be used to bind to properties only. Expressions represent how data should be projected to the View.
Expressions should not have any side effect and should be idempotent. Examples of where expressions can be used in
Angular are:
```
<div title="{{expression}}">{{expression}}</div>
<div [title]="expression">...</div>
<div bind-title="expression">...</div>
<div template="ng-if: expression">...</div>
```
Expressions are simplified version of expression in the language in which you are writing your application. (i.e.
expressions follow JS syntax and semantics in JS and Dart syntax and semantics in Dart). Unlike expressions in the
language, binding expressions behave differently in following ways:
* *Must be defined*: Unlike Angular v1, Angular v2 will throw an error on dereferencing fields which are not defined.
For example: `user.name` will throw an error if `user` is defined but it does not have `name` property. If the `name`
property is not known, it must be declared and set to some value such as empty string, `null` (or `undefined` in JS).
This is done to allow early detection of errors in the templates.
* *Safe dereference*: Expressions `user.name` where `user` is null will throw `NullPointerException` in the language.
In contrast Angular will silently ignore `null` on `user`. This is done because Views often have to wait for the data
to arrive from the backend and many fields will be `null` until the data arrives. Safe dereference is so common in the
Views that we have made it the default.
* *Single expression*: An expression must be a single statement. (i.e. no `;`)
* *No assignments*: Binding expressions can not contain assignments.
* *No keywords*: Binding expressions can not contain keywords such as: `var`, `if`, and so on.
* *Formatters*: Angular expressions can be piped through formatters to further transform the binding value.
(See: Formatters)
Examples of some expressions and their behavior:
Given:
```
class Greeter {
name:string;
}
```
* `name` : Will result in the value of the `name` property on the `Greeter` class.
* `name.length`: Will result in either the length of the `name` string or `undefined` (`null` in Dart) if `name`
property is `null` or `undefined`. Example of: safe dereference.
* `foo`: Will throw an error because `foo` is not declared on the `Greeter` class. Example of: Must be defined
* `name=1`: Not allowed because of assignment.
* `name; name.length`: Not allowed because of multiple statements.
### Statements
Statements can be used to bind to events only. Statements represent actions to trigger as a response to an event.
Examples of where statements can be used in Angular are:
```
<div (click)="statements">...</div>
<div on-click="statements">...</div>
```
Statements are similar to statements in the language in which you are writing your application. (i.e.
statements follow JS syntax and semantics in JS and Dart syntax and semantics in Dart). Unlike statements in the
language, binding expressions behave differently in the following ways:
* *Unsafe dereference*: Expressions `user.verify()` where `user` is `null` will throw `NullPointerException` in the
language as well as in statements. (In contrast to Safe dereference in Angular expressions.) While Angular protects
you from null dereferencing in expressions due to lazy loading of data, no such protection is required for statements,
and doing so would make it harder to detect typos in statements.
* *Multiple statements OK*: Statements can be composed from more than one statement. (i.e. no `doA(); doB()`)
* *Assignments OK*: Event bindings can have side effects and hence assignments are allowed.
* *No keywords*: Statements can not contain keywords such as: `var`, `if`, and so on.
* *No Formatters*: Angular statements can not contain formatters. (Formatters are only useful for data binding)
## Further Reading
* [Template Syntax Constraints and Reasoning](https://docs.google.com/document/d/1HHy_zPLGqJj0bHMiWPzPCxn1pO5GlOYwmv-qGgl4f_s)
-390
View File
@@ -1,390 +0,0 @@
# Directives
Directives are classes which get instantiated as a response to a particular DOM structure. By controlling the DOM structure, what directives are imported, and their selectors, the developer can use the [composition pattern](http://en.wikipedia.org/wiki/Object_composition) to get a desirable application behavior.
Directives are the cornerstone of an Angular application. We use Directives to break complex problems into smaller more reusable components. Directives allow the developer to turn HTML into a DSL and then control the application assembly process.
Angular applications do not have a main method. Instead they have a root Component. Dependency Injection then assembles the directives into a working Angular application.
Directives with an encapsulated view and an optional injector are called *Components*.
## CSS Selectors
Directives are instantiated whenever the CSS selector matches the DOM structure.
Angular supports these CSS selector constructs:
* Element name: `name`
* Attribute: `[attribute]`
* Attribute has value: `[attribute=value]`
* Attribute contains value: `[attribute*=value]`
* Class: `.class`
* AND operation: `name[attribute]`
* OR operation: `name,.class`
* NOT operation: `:not(.class)`
Angular does not support these (and any CSS selector which crosses element boundaries):
* Descendant: `body div`
* Direct descendant: `body > div`
* Adjacent: `div + table`
* Sibling: `div ~ table`
* Wildcard: `*`
* ID: `#id`
* Pseudo selectors: `:pseudo` other than `:not`
Given this DOM:
```<input type="text" required class="primary">```
These CSS selectors will match:
* `input`: Triggers whenever element name is `input`.
* `[required]`: Triggers whenever element contains a required attribute.
* `[type=text]`: Triggers whenever element contains attribute `type` whose value is `text`.
* `.primary`: Triggers whenever element class contains `primary`.
CSS Selectors can be combined:
* `input[type=text]`: Triggers on element name `input` which is of `type` `text`.
* `input[type=text], textarea`: triggers on element name `input` which is of `type` `text` or element name `textarea`.
## Directives
The simplest kind of directive is a decorator. Directives are useful for encapsulating behavior.
* Multiple decorators can be placed on a single element.
* Directives do not introduce new evaluation context.
* Directives are registered through the `@Directive` meta-data annotation.
Here is a trivial example of a tooltip decorator. The directive will log a tooltip into the console on every time mouse enters a region:
```
@Directive({
selector: '[tooltip]', | CSS Selector which triggers the decorator
properties: [ | List which properties need to be bound
'text: tooltip' | - DOM element tooltip property should be
], | mapped to the directive text property.
host: { | List which events need to be mapped.
'(mouseover)': 'show()' | - Invoke the show() method every time
} | the mouseover event is fired.
}) |
class Form { | Directive controller class, instantiated
| when CSS matches.
text:string; | text property on the Directive Controller.
|
show() { | Show method which implements the show action.
console.log(this.text); |
}
}
```
Example of usage:
```<span tooltip="Tooltip text goes here.">Some text here.</span>```
The developer of an application can now freely use the `tooltip` attribute wherever the behavior is needed. The code above has taught the browser a new reusable and declarative behavior.
Notice that data binding will work with this decorator with no further effort as shown below.
```<span tooltip="Greetings {{user}}!">Some text here.</span>```
## Components
Component is a directive which uses shadow DOM to create encapsulate visual behavior. Components are typically used to create UI widgets or to break up the application into smaller components.
* Only one component can be present per DOM element.
* Component's CSS selectors usually trigger on element names. (Best practice)
* Component has its own shadow view which is attached to the element as a Shadow DOM.
* Shadow view context is the component instance. (i.e. template expressions are evaluated against the component instance.)
>> TODO(misko): Configuring the injector
Example of a component:
```
@Component({ | Component annotation
selector: 'pane', | CSS selector on <pane> element
properties: [ | List which property need to be bound
'title', | - title mapped to component title
'open' | - open attribute mapped to component's open property
], |
}) |
@View({ | View annotation
templateUrl: 'pane.html' | - URL of template HTML
}) |
class Pane { | Component controller class
title:string; | - title property
open:boolean;
constructor() {
this.title = '';
this.open = true;
}
// Public API
toggle() => this.open = !this.open;
open() => this.open = true;
close() => this.open = false;
}
```
`pane.html`:
```
<div class="outer">
<h1>{{title}}</h1>
<div class="inner" [hidden]="!open">
<ng-content></ng-content>
</div>
</div>
```
`pane.css`:
```
.outer, .inner { border: 1px solid blue;}
.h1 {background-color: blue;}
```
Example of usage:
```
<pane #pane title="Example Title" open="true">
Some text to wrap.
</pane>
<button (click)="pane.toggle()">toggle</button>
```
## Directives that use a ViewContainer
Directives that use a ViewContainer can control instantiation of child views which are then inserted into the DOM. (Examples are `ng-if` and `ng-for`.)
* Every `template` element creates a `ProtoView` which can be used to create Views via the ViewContainer.
* The child views show up as siblings of the directive in the DOM.
>> TODO(misko): Relationship with Injection
>> TODO(misko): Instantiator can not be injected into child Views
```
@Directive({
selector: '[if]',
properties: [
'condition: if'
]
})
export class If {
viewContainer: ViewContainerRef;
protoViewRef: ProtoViewRef;
view: View;
constructor(viewContainer: ViewContainerRef, protoViewRef: ProtoViewRef) {
this.viewContainer = viewContainer;
this.protoViewRef = protoViewRef;
this.view = null;
}
set condition(value) {
if (value) {
if (this.view === null) {
this.view = this.viewContainer.create(protoViewRef);
}
} else {
if (this.view !== null) {
this.viewContainer.remove(this.view);
this.view = null;
}
}
}
}
```
## Dependency Injection
Dependency Injection (DI) is a key aspect of directives. DI allows directives to be assembled into different [compositional](http://en.wikipedia.org/wiki/Object_composition) hierarchies. Angular encourages [composition over inheritance](http://en.wikipedia.org/wiki/Composition_over_inheritance) in the application design (but inheritance based approaches are still supported).
When Angular directives are instantiated, the directive can ask for other related directives to be injected into it. By assembling the directives in different order and subtypes the application behavior can be controlled. A good mental model is that the DOM structure controls the directive instantiation graph.
Directive instantiation is triggered by the directive CSS selector matching the DOM structure. In a directive's constructor, it can ask for other directives or application services. When asking for directives, the dependency is attempted to be located by its DOM hierarchy first, then if not found, by using the application level injector.
To better understand the kinds of injections which are supported in Angular we have broken them down into use case examples.
### Injecting Services
Service injection is the most straight forward kind of injection which Angular supports. It involves a component configuring the `bindings` or `viewBindings` and then letting the directive ask for the configured service.
This example illustrates how to inject `MyService` into `House` directive.
```
class MyService {} | Assume a service which needs to be injected
| into a directive.
|
@Component({ | Assume a top level application component which
selector: 'my-app', | configures the services to be injected.
viewBindings: [MyService] |
}) |
@View({ | Assume we have a template that needs to be
templateUrl: 'my_app.html', | configured with directives to be injected.
directives: [House] |
}) |
class MyApp {} |
|
@Directive({ | This is the directive into which we would like
selector: '[house]' | to inject the MyService.
}) |
class House { |
constructor(myService:MyService) { | Notice that in the constructor we can simply
} | ask for MyService.
} |
```
Assume the following DOM structure for `my_app.html`:
```
<div house> | The house attribute triggers the creation of the House directive.
</div> | This is equivalent to:
| new House(injector.get(MyService));
```
### Injecting other Directives
Injecting other directives into directives follows a similar mechanism as injecting services into directives, but with added constraint of visibility governed by DOM structure.
There are five kinds of visibilities:
* (no annotation): Inject dependent directives only if they are on the current element.
* `@SkipSelf()`: Inject a directive if it is at any element above the current element.
* `@child`: Inject a list of direct children which match a given type. (Used with `Query`)
* `@descendant`: Inject a list of any children which match a given type. (Used with `Query`)
NOTE: if the injection constraint can not be satisfied by the current visibility constraint, then it is forwarded to the normal injector which either provides a default value for the directive or throws an error.
Here is an example of the kinds of injections which can be achieved:
```
@Component({ |
selector: 'my-app' |
}) |
@View({ |
templateUrl: 'my_app.html', |
directives: [Form, FieldSet, |
Field, Primary] |
}) |
class MyApp {} |
|
@Directive({ selector: 'form' }) |
class Form { |
constructor( |
@descendant sets:Query<FieldSet> |
) { |
} |
} |
|
@Directive({ selector: 'fieldset' }) |
class FieldSet { |
constructor( |
@child sets:Query<Field> |
) { ... } |
} |
|
@Directive({ selector: 'field' }) |
class Field { |
constructor( |
@SkipSelf() field:Form, |
@SkipSelf() field:FieldSet, |
) { ... } |
} |
|
@Directive({ selector: '[primary]'}) |
class Primary { |
constructor(field:Field ) { ... } |
} |
```
Assume the following DOM structure for `my_app.html`:
```
<form> |
<div> |
<fieldset> |
<field primary></field> |
<field></field> |
</fieldset> |
</div> |
</form> |
```
#### Shadow DOM effects on Directive DI
Shadow DOM provides an encapsulation for components, so as a general rule it does not allow directive injections to cross the shadow DOM boundaries. To remedy this, declaratively specify the required component as an injectable.
```
@Component({
selector: '[kid]'
})
@View({
templateUrl: 'kid.html',
directives: []
})
class Kid {
constructor(
@SkipSelf() dad:Dad,
@Optional() grandpa:Grandpa
) {
this.name = 'Billy';
this.dad = dad.name;
this.grandpa = grandpa.name;
}
}
@Component({
selector: '[dad]'
})
@View({
templateUrl: 'dad.html',
directives: [Kid]
})
class Dad {
constructor(@SkipSelf() dad:Grandpa) {
this.name = 'Joe Jr';
this.dad = dad.name;
}
}
@Component({
selector: '[grandpa]',
viewBindings: []
})
@View({
templateUrl: 'grandpa.html',
directives: [Dad]
})
class Grandpa {
constructor() {
this.name = 'Joe';
}
}
```
Assume the following DOM structure for `grandpa.html`: The Dad has access to the Grandpa.
```
Name: {{name}}: <br> Children: <div dad></div>
```
Assume the following DOM structure for `dad.html`: Here the rendered Kid will also have access to Grandpa.
```
Name: {{name}}: <br> Dad: {{dad}} <br> Children: <div kid></div>
```
## Further Reading
* [Composition](http://en.wikipedia.org/wiki/Object_composition)
* [Composition over Inheritance](http://en.wikipedia.org/wiki/Composition_over_inheritance)
-27
View File
@@ -1,27 +0,0 @@
# Pipes
Pipes can be appended on the end of the expressions to translate the value to a different format. Typically used
to control the stringification of numbers, dates, and other data, but can also be used for ordering, mapping, and
reducing arrays. Pipes can be chained.
NOTE: Pipes are known as filters in Angular v1.
Pipes syntax is:
```
<div class="movie-copy">
<p>
{{ model.getValue('copy') | async | uppercase }}
</p>
<ul>
<li>
<b>Starring</b>: {{ model.getValue('starring') | async }}
</li>
<li>
<b>Genres</b>: {{ model.getValue('genres') | async }}
</li>
<ul>
</div>
```
-5
View File
@@ -1,5 +0,0 @@
# Components
* Different kinds of injections and visibility
* Shadow DOM usage
*
-21
View File
@@ -1,21 +0,0 @@
# HTML Template Compilation
* Process by which a HTML template is converted to a ProtoView
1. DOM parse()
2. Macro
3.
# HTML Template
* https://docs.google.com/document/d/1HHy_zPLGqJj0bHMiWPzPCxn1pO5GlOYwmv-qGgl4f_s
* https://docs.google.com/document/d/1kpuR512G1b0D8egl9245OHaG0cFh0ST0ekhD_g8sxtI
* https://docs.google.com/document/d/1DuFQKElIq293FlhQHvAp__NfP1XV9r8femZFMigm4-k
* Must understand without understanding directives
* IDE support
* local variables
# Binding Philosophy
# Binding to Shadow DOM
-246
View File
@@ -1,246 +0,0 @@
# View
## Overview
This document explains the concept of a View.
A View is a core primitive used by angular to render the DOM tree.
A ViewContainer is location in a View which can accept child Views.
Every ViewContainer has an associated ViewContainerRef than can contain any number of child Views.
Views form a tree structure which mimics the DOM tree.
* View is a core rendering construct. A running application is just a collection of Views which are
nested in a tree like structure. The View tree is a simplified version of the DOM tree. A View can
have a single DOM Element or large DOM structures. The key is that the DOM tree in the View can
not undergo structural changes (only property changes).
* Views represent a running instance of a DOM View. This implies that while elements in a View
can change properties, they can not change structurally. (Structural changes such as, adding or
removing elements requires adding or removing child Views into ViewContainers).
* View can have zero or more ViewContainers. A ViewContainer is a marker in the DOM which allows
the insertion of child Views.
* Views are created from a ProtoView. A ProtoView is a compiled DOM View which is efficient at
creating Views.
* View contains a context object. The context represents the object instance against which all
expressions are evaluated.
* View contains a ChangeDetector for looking for detecting changes to the model.
* View contains ElementInjector for creating Directives.
## Simple View
Let's examine a simple View and all of its parts in detail.
Assume the following Component:
```
class Greeter {
greeting:string;
constructor() {
this.greeting = 'Hello';
}
}
```
And assume following HTML View:
```
<div>
Your name:
<input var="name" type="Text">
<br>
{{greeting}} {{name.value}}!
</div>
```
The above template is compiled by the Compiler to create a ProtoView. The ProtoView is then used to
create an instance of the View. The instantiation process involves cloning the above template and
locating all of the elements which contain bindings and finally instantiating the Directives
associated with the template. (See compilation for more details.)
```
<div> | viewA(greeter)
Your name: | viewA(greeter)
<input var="name" type="Text"> | viewA(greeter): local variable 'name'
<br> | viewA(greeter)
{{greeting}} {{name.value}}! | viewA(greeter): binding expression 'greeting' & 'name.value'
</div> | viewA(greeter)
```
The resulting View instance looks something like this (simplified pseudo code):
```
viewA = new View({
template: ...,
context: new Greeter(),
localVars: ['name'],
watchExp: ['greeting', 'name.value']
});
```
Note:
* View uses instance of `Greeter` as the evaluation context.
* View knows of local variables `name`.
* View knows which expressions need to be watched.
* View knows what needs to be updated if the watched expression changes.
* All DOM elements are owned by single instance of the view.
* The structure of the DOM can not change during runtime. To allow structural changes to the DOM we need
to understand Composed View.
## Composed View
An important part of an application is to be able to change the DOM structure to render data for the
user. In Angular this is done by inserting child views into the ViewContainer.
Let's start with a View such as:
```
<ul>
<li template="ng-for: #person of people">{{person}}</li>
</ul>
```
During the compilation process the Compiler breaks the HTML template into these two ProtoViews:
```
<li>{{person}}</li> | protoViewB(Locals)
```
and
```
<ul> | protoViewA(someContext)
<template></template> | protoViewA(someContext): protoViewB
</ul> | protoViewA(someContext)
```
The next step is to compose these two ProtoViews into an actual view which is rendered to the user.
*Step 1:* Instantiate `viewA`
```
<ul> | viewA(someContext)
<template></template> | viewA(someContext): new NgFor(new ViewContainer(protoViewB))
</ul> | viewA(someContext)
```
*Step2:* Instantiate `NgFor` directive which will receive the `ViewContainerRef`. (The ViewContainerRef
has a reference to `protoViewA`).
*Step3:* As the `NgFor` directive unrolls it asks the `ViewContainerRef` to instantiate `protoViewB` and insert
it after the `ViewContainer` anchor. This is repeated for each `person` in `people`. Notice that
```
<ul> | viewA(someContext)
<template></template> | viewA(someContext): new NgFor(new ViewContainer(protoViewB))
<li>{{person}}</li> | viewB0(locals0(someContext))
<li>{{person}}</li> | viewB1(locals0(someContext))
</ul> | viewA(someContext)
```
*Step4:* All of the bindings in the child Views are updated. Notice that in the case of `NgFor`
the evaluation context for the `viewB0` and `viewB1` are `locals0` and `locals1` respectively.
Locals allow the introduction of new local variables visible only within the scope of the View, and
delegate any unknown references to the parent context.
```
<ul> | viewA
<template></template> | viewA: new NgFor(new ViewContainer(protoViewB))
<li>Alice</li> | viewB0
<li>Bob</li> | viewB1
</ul> | viewA
```
Each View can have zero or more ViewContainers. By inserting and removing child Views to and from the
ViewContainers, the application can mutate the DOM structure to any desirable state. A View may contain
individual nodes or a complex DOM structure. The insertion points for the child Views, known as
ViewContainers, contain a DOM element which acts as an anchor. The anchor is either a `template` or
a `script` element depending on your browser. It is used to identify where the child Views will be
inserted.
## Component Views
A View can also contain Components. Components contain Shadow DOM for encapsulating their internal
rendering state. Unlike ViewContainers which can contain zero or more Views, the Component always contains
exactly one Shadow View.
```
<div> | viewA
<my-component> | viewA
#SHADOW_ROOT | (encapsulation boundary)
<div> | viewB
encapsulated rendering | viewB
</div> | viewB
</my-component> | viewA
</div> | viewA
```
## Evaluation Context
Each View acts as a context for evaluating its expressions. There are two kinds of contexts:
1. A component controller instance and
2. a `Locals` context for introducing local variables into the View.
Let's assume following component:
```
class Greeter {
greeting:string;
constructor() {
this.greeting = 'Hello';
}
}
```
And assume the following HTML View:
```
<div> | viewA(greeter)
Your name: | viewA(greeter)
<input var="name" type="Text"> | viewA(greeter)
<br> | viewA(greeter)
{{greeting}} {{name.value}}! | viewA(greeter)
</div> | viewA(greeter)
```
The above UI is built using a single View, and hence a single context `greeter`. It can be expressed
in this pseudo-code.
```
var greeter = new Greeter();
```
The View contains two bindings:
1. `greeting`: This is bound to the `greeting` property on the `Greeter` instance.
2. `name.value`: This poses a problem. There is no `name` property on the `Greeter` instance. To solve
this we wrap the `Greeter` instance in the `Local` instance like so:
```
var greeter = new Locals(new Greeter(), {name: ref_to_input_element })
```
By wrapping the `Greeter` instance into the `Locals` we allow the view to introduce variables which
are in addition to the `Greeter` instance. During the resolution of the expressions we first check
the locals, and then the `Greeter` instance.
## View LifeCycle (Hydration and Dehydration)
Views transition through a particular set of states:
1. View is created from the ProtoView.
2. View can be attached to an existing ViewContainerRef.
3. Upon attaching View to the ViewContainerRef the View needs to be hydrated. The hydration process
involves instantiating all of the Directives associated with the current View.
4. At this point the view is ready and renderable. Multiple changes can be delivered to the
Directives from the ChangeDetection.
5. At some point the View can be removed. At this point all of the directives are destroyed during
the dehydration process and the view becomes inactive.
6. The View has to wait until it is detached from the DOM. The delay in detaching could be caused
because an animation is animating the view away.
7. After the View is detached from the DOM it is ready to be reused. The view reuse allows the
application to be faster in subsequent renderings.
-108
View File
@@ -1,108 +0,0 @@
# Zones
A Zone is an execution context that persists across async tasks. You can think of it as thread-local storage for
JavaScript. Zones are used to intercept all async operation callbacks in the browser. By intercepting async
callbacks Angular can automatically execute the change detection at the end of the VM turn to update the application
UI bindings. Zones means that in Angular v2 you don't have to remember to call `rootScope.$apply()` in your async call.
## Execution Context
```
zone.inTheZone = false;
zone.fork().run(function () {
zone.inTheZone = true;
setTimeout(function () {
console.log('async in the zone: ' + zone.inTheZone);
}, 0);
});
console.log('sync in the zone: ' + zone.inTheZone);
```
The above will log:
```
sync in the zone: false
async in the zone: true
```
In the above example the `zone` is a global-callback-local variable. To the `zone` we can attach arbitrary properties
such as `inTheZone`. When we enter the zone, we get a new `zone` context (which inherits all properties from the
parent zone), once we leave the zone, the previous `zone` variable is restored. The key part is that when a async
callback is scheduled in the zone, as is the case with `setTimeout`, the current `zone` variable is captured and
restored on the callback. This is why the output of the `inTheZone` property inside the callback of the `setTimeout`
prints `true`.
## Callback Interception
In addition to storing properties on the current `zone`, zones can also allow us to intercept all async callbacks
and notify us before and after the callback executes.
```
zone.fork({
afterTask: function () {
// do some cleanup
}
}).run(function () {
// do stuff
});
```
The above example will execute the `afterTask` function not only after the `run` finishes, but also after any callback
execution which was registered in the `run` block.
## Putting it all together in Angular
In Angular2 it is not necessary to notify Angular of changes manually after async callback, because a relevant
async callbacks are intercepted. The question is how do we know which callbacks are Angular relevant?
// TODO(vicb): outdated, rework.
```
/// Some other code running on page can do async operation
document.addEventListener('mousemove', function () {
console.log('Mouse moved.');
});
var AngularZone = {
afterTask: function () {
console.log('ANGULAR AUTO-DIGEST!');
}
};
var ngZone = zone.fork(AngularZone);
ngZone.run(function() {
console.log('I aware of angular, I should cause digest.');
document.addEventListener('click', function () {
console.log('Mouse clicked.');
});
});
```
Will produce:
```
I aware of angular, I should cause digest.
ANGULAR AUTO-DIGEST!
```
Moving the mouse will produce many:
```
Mouse moved.
```
But clicking will produce:
```
Mouse clicked.
ANGULAR AUTO-DIGEST!
```
Notice how the place where the listener was registered will effect whether or not Angular will be notified of the
async call and cause a change detection to run to update the UI.
Being able to globally intercept the async operation is important to have a seamless integration with all existing
libraries. But it is equally important to be able to differentiate between Angular and non-Angular code running
on the same page concurrently.
-267
View File
@@ -1,267 +0,0 @@
# Dependency Injection (DI): Documentation
This document describes in detail how the DI module works in Angular 2.
## Core Abstractions
The library is built on top of the following core abstractions: `Injector`, `Binding`, and `Dependency`.
* An injector is created from a set of bindings.
* An injector resolves dependencies and creates objects.
* A binding maps a token, such as a string or class, to a factory function and a list of dependencies. So a binding defines how to create an object.
* A dependency points to a token and contains extra information on how the object corresponding to that token should be injected.
```
[Injector]
|
|
|*
[Binding]
|----------|-----------------|
| | |*
[Token] [FactoryFn] [Dependency]
|---------|
| |
[Token] [Flags]
```
## Example
```
class Engine {
}
class Car {
constructor(@Inject(Engine) engine) {
}
}
var inj = Injector.resolveAndCreate([
bind(Car).toClass(Car),
bind(Engine).toClass(Engine)
]);
var car = inj.get(Car);
```
In this example we create two bindings: one for `Car` and one for `Engine`. `@Inject(Engine)` declares a dependency on Engine.
## Injector
An injector instantiates objects lazily, only when asked for, and then caches them.
Compare
```
var car = inj.get(Car); //instantiates both an Engine and a Car
```
with
```
var engine = inj.get(Engine); //instantiates an Engine
var car = inj.get(Car); //instantiates a Car (reuses Engine)
```
and with
```
var car = inj.get(Car); //instantiates both an Engine and a Car
var engine = inj.get(Engine); //reads the Engine from the cache
```
To avoid bugs make sure the registered objects have side-effect-free constructors. In this case, an injector acts like a hash map, where the order in which the objects got created does not matter.
## Child Injectors and Dependencies
Injectors are hierarchical.
```
var parent = Injector.resolveAndCreate([
bind(Engine).toClass(TurboEngine)
]);
var child = parent.resolveAndCreateChild([Car]);
var car = child.get(Car); // uses the Car binding from the child injector and Engine from the parent injector.
```
Injectors form a tree.
```
GrandParentInjector
/ \
Parent1Injector Parent2Injector
|
ChildInjector
```
The dependency resolution algorithm works as follows:
```
// this is pseudocode.
var inj = this;
while (inj) {
if (inj.hasKey(requestedKey)) {
return inj.get(requestedKey);
} else {
inj = inj.parent;
}
}
throw new NoProviderError(requestedKey);
```
So in the following example
```
class Car {
constructor(e: Engine){}
}
```
DI will start resolving `Engine` in the same injector where the `Car` binding is defined. It will check whether that injector has the `Engine` binding. If it is the case, it will return that instance. If not, the injector will ask its parent whether it has an instance of `Engine`. The process continues until either an instance of `Engine` has been found, or we have reached the root of the injector tree.
### Constraints
You can put upper and lower bound constraints on a dependency. For instance, the `@Self` decorator tells DI to look for `Engine` only in the same injector where `Car` is defined. So it will not walk up the tree.
```
class Car {
constructor(@Self() e: Engine){}
}
```
A more realistic example is having two bindings that have to be provided together (e.g., NgModel and NgRequiredValidator.)
The `@Host` decorator tells DI to look for `Engine` in this injector, its parent, until it reaches a host (see the section on hosts.)
```
class Car {
constructor(@Host() e: Engine){}
}
```
The `@SkipSelf` decorator tells DI to look for `Engine` in the whole tree starting from the parent injector.
```
class Car {
constructor(@SkipSelf() e: Engine){}
}
```
### DI Does Not Walk Down
Dependency resolution only walks up the tree. The following will throw because DI will look for an instance of `Engine` starting from `parent`.
```
var parent = Injector.resolveAndCreate([Car]);
var child = parent.resolveAndCreateChild([
bind(Engine).toClass(TurboEngine)
]);
parent.get(Car); // will throw NoProviderError
```
## Bindings
You can bind to a class, a value, or a factory. It is also possible to alias existing bindings.
```
var inj = Injector.resolveAndCreate([
bind(Car).toClass(Car),
bind(Engine).toClass(Engine)
]);
var inj = Injector.resolveAndCreate([
Car, // syntax sugar for bind(Car).toClass(Car)
Engine
]);
var inj = Injector.resolveAndCreate([
bind(Car).toValue(new Car(new Engine()))
]);
var inj = Injector.resolveAndCreate([
bind(Car).toFactory((e) => new Car(e), [Engine]),
bind(Engine).toFactory(() => new Engine())
]);
```
You can bind any token.
```
var inj = Injector.resolveAndCreate([
bind(Car).toFactory((e) => new Car(), ["engine!"]),
bind("engine!").toClass(Engine)
]);
```
If you want to alias an existing binding, you can do so using `toAlias`:
```
var inj = Injector.resolveAndCreate([
bind(Engine).toClass(Engine),
bind("engine!").toAlias(Engine)
]);
```
which implies `inj.get(Engine) === inj.get("engine!")`.
Note that tokens and factory functions are decoupled.
```
bind("some token").toFactory(someFactory);
```
The `someFactory` function does not have to know that it creates an object for `some token`.
### Resolved Bindings
When DI receives `bind(Car).toClass(Car)`, it needs to do a few things before it can create an instance of `Car`:
- It needs to reflect on `Car` to create a factory function.
- It needs to normalize the dependencies (e.g., calculate lower and upper bounds).
The result of these two operations is a `ResolvedBinding`.
The `resolveAndCreate` and `resolveAndCreateChild` functions resolve passed-in bindings before creating an injector. But you can resolve bindings yourself using `Injector.resolve([bind(Car).toClass(Car)])`. Creating an injector from pre-resolved bindings is faster, and may be needed for performance sensitive areas.
You can create an injector using a list of resolved bindings.
```
var listOfResolvingBindings = Injector.resolve([Binding1, Binding2]);
var inj = Injector.fromResolvedBindings(listOfResolvingBindings);
inj.createChildFromResolvedBindings(listOfResolvedBindings);
```
### Transient Dependencies
An injector has only one instance created by each registered binding.
```
inj.get(MyClass) === inj.get(MyClass); //always holds
```
If we need a transient dependency, something that we want a new instance of every single time, we have two options.
We can create a child injector for each new instance:
```
var child = inj.resolveAndCreateChild([MyClass]);
child.get(MyClass);
```
Or we can register a factory function:
```
var inj = Injector.resolveAndCreate([
bind('MyClassFactory').toFactory(dep => () => new MyClass(dep), [SomeDependency])
]);
var factory = inj.get('MyClassFactory');
var instance1 = factory(), instance2 = factory();
// Depends on the implementation of MyClass, but generally holds.
expect(instance1).not.toBe(instance2);
```
-237
View File
@@ -1,237 +0,0 @@
# Dependency Injection (DI): Documentation (Advanced Topics)
This document talks about advanced topics related to the DI module and how it is used in Angular. You don't have to know this to use DI in Angular or independently.
### Key
Most of the time we do not have to deal with keys.
```
var inj = Injector.resolveAndCreate([
bind(Engine).toFactory(() => new TurboEngine()) //the passed in token Engine gets mapped to a key
]);
var engine = inj.get(Engine); //the passed in token Engine gets mapped to a key
```
Now, the same example, but with keys.
```
var ENGINE_KEY = Key.get(Engine);
var inj = Injector.resolveAndCreate([
bind(ENGINE_KEY).toFactory(() => new TurboEngine()) // no mapping
]);
var engine = inj.get(ENGINE_KEY); // no mapping
```
Every key has an id, which we utilize to store bindings and instances. So Injector uses keys internally for performance reasons.
### ProtoInjector and Injector
Often there is a need to create multiple instances of essentially the same injector. In Angular 2, for example, every component element type gets an injector configured in the same way.
Doing the following would be very inefficient.
```
function createComponetInjector(parent, bindings: Binding[]) {
return parent.resolveAndCreateChild(bindings);
}
```
This would require us to resolve and store bindings for every single component instance. Instead, we want to resolve and store the bindings for every component type, and create a set of instances for every component. To enable that DI separates the meta information about injectables (Bindings and their dependencies), which are stored in `ProtoInjector`, and injectables themselves, which are stored in `Injector`.
```
var proto = new ProtoInjector(bindings); // done once
function createComponentInjector(parent, proto) {
return new Injector(proto, parent);
}
```
`Injector.resolveAndCreate` creates both a `ProtoInjector` and an `Injector`.
### Host & Visibility
An injector can have a parent. The parent relationship can be marked as a "host" as follows:
```
var child = new Injector(proto, parent, true /* host */);
```
Hosts are used to constraint dependency resolution. For instance, in the following example, DI will stop looking for `Engine` after reaching the host.
```
class Car {
constructor(@Host() e: Engine) {}
}
```
Imagine the following scenario:
```
ParentInjector
/ \
/ \ host
Child1 Child2
```
Here both Child1 and Child2 are children of ParentInjector. Child2 marks this relationship as host. ParentInjector might want to expose two different sets of bindings for its "regular" children and its "host" children. Bindings visible to "regular" children are called "public" and bindings visible to "host" children are called "private". This is an advanced use case used by Angular, where components can provide different sets of bindings for their children and their view.
Let's look at this example.
```
class Car {
constructor(@Host() e: Engine) {}
}
var parentProto = new ProtoInjector([
new BindingWithVisibility(Engine, Visibility.Public),
new BindingWithVisibility(Car, Visibility.Public)
]);
var parent = new Injector(parentProto);
var hostChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
var hostChild = new Injector(hostChildProto, parent, true);
var regularChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
var regularChild = new Injector(regularChildProto, parent, false);
hostChild.get(Car); // will throw because public dependencies declared at the host cannot be seen by child injectors
parent.get(Car); // this works
regularChild.get(Car); // this works
```
Now, let's mark `Engine` as private:
```
class Car {
constructor(@Host() e: Engine) {}
}
var parentProto = new ProtoInjector([
new BindingWithVisibility(Engine, Visibility.Private),
new BindingWithVisibility(Car, Visibility.Public)
]);
var parent = new Injector(parentProto);
var hostChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
var hostChild = new Injector(hostChildProto, parent, true);
var regularChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
var regularChild = new Injector(regularChildProto, parent, false);
hostChild.get(Car); // this works
parent.get(Car); // this throws
regularChild.get(Car); // this throws
```
Now, let's mark `Engine` as both public and private:
```
class Car {
constructor(@Host() e: Engine) {}
}
var parentProto = new ProtoInjector([
new BindingWithVisibility(Engine, Visibility.PublicAndPrivate),
new BindingWithVisibility(Car, Visibility.Public)
]);
var parent = new Injector(parentProto);
var hostChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
var hostChild = new Injector(hostChildProto, parent, true);
var regularChildProto = new ProtoInjector([new BindingWithVisibility(Car, Visibility.Public)]);
var regularChild = new Injector(regularChildProto, parent, false);
hostChild.get(Car); // this works
parent.get(Car); // this works
regularChild.get(Car); // this works
```
## Angular 2 and DI
Now let's see how Angular 2 uses DI behind the scenes.
The right mental model is to think that every DOM element has an Injector. (In practice, only interesting elements containing directives will have an injector, but this is a performance optimization)
There are two properties that can be used to configure DI: bindings and viewBindings.
- `bindings` affects the element and its children.
- `viewBindings` affects the component's view.
Every directive can declare injectables via `bindings`, but only components can declare `viewBindings`.
Let's look at a complex example that shows how the injector tree gets created.
```
<my-component my-directive>
<needs-service></needs-service>
</my-component>
```
Both `MyComponent` and `MyDirective` are created on the same element.
```
@Component({
selector: 'my-component',
bindings: [
bind('componentService').toValue('Host_MyComponentService')
],
viewBindings: [
bind('viewService').toValue('View_MyComponentService')
]
})
@View({
template: `<needs-view-service></needs-view-service>`,
directives: [NeedsViewService]
})
class MyComponent {}
@Directive({
selector: '[my-directive]',
bindings: [
bind('directiveService').toValue('MyDirectiveService')
]
})
class MyDirective {
}
```
`NeedsService` and `NeedsViewService` look like this:
```
@Directive({
selector: 'needs-view-service'
})
class NeedsViewService {
constructor(@Host() @Inject('viewService') viewService) {}
}
@Directive({
selector: 'needs-service'
})
class NeedsService {
constructor(@Host() @Inject('componentService') service1,
@Host() @Inject('directiveService') service2) {}
}
```
This will create the following injector tree.
```
Injector1 [
{binding: MyComponent, visibility: Visibility.PublicAndPrivate},
{binding: 'componentService', visibility: Visibility.PublicAndPrivate},
{binding: 'viewService', visibility: Visibility.Private},
{binding: MyDirective visibility: Visibility.Public},
{binding: 'directiveService', visibility: Visibility.Public}
]
/ \
| \ host
Injector2 [ Injector3 [
{binding: NeedsService, visibility: Visibility.Public} {binding: NeedsViewService, visibility: Visibility.Public}
] ]
```
As you can see the component and its bindings can be seen by its children and its view. The view bindings can be seen only by the view. And the bindings of other directives can be seen only their children.
-479
View File
@@ -1,479 +0,0 @@
# WebWorkers in Angular 2: Documentation
Angular 2 includes native support for writing applications which live in a
WebWorker. This document describes how to write applications that take advantage
of this feature.
It also provides a detailed description of the underlying messaging
infrastructure that angular uses to communicate between the main process and the
worker. This infrastructure can be modified by an application developer to
enable driving an angular 2 application from an iFrame, different window / tab,
server, etc..
## Introduction
WebWorker support in Angular2 is designed to make it easy to leverage parallelization in your web application.
When you choose to run your application in a WebWorker angular runs both your application's logic and the
majority of the core angular framework in a WebWorker.
By offloading as much code as possible to the WebWorker we keep the UI thread
free to handle events, manipulate the DOM, and run animations. This provides a
better framerate and UX for applications.
## Bootstrapping a WebWorker Application
Bootstrapping a WebWorker application is not much different than bootstrapping a normal application.
The primary difference is that you don't pass your root component directly to ```bootstrap```.
Instead you pass the name of a background script that calls ```bootstrapWebWorker``` with your root component.
### Example
To bootstrap Hello World in a WebWorker we do the following in TypeScript
```HTML
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.33.3/es6-shim.js"></script>
<script src="https://jspm.io/system@0.16.js"></script>
<script src="angular2/web_worker/ui.js"></script>
</head>
<body>
<hello-world></hello-world>
<script>System.import("index")</script>
</body>
</html>
```
```TypeScript
// index.js
import {bootstrap} from "angular2/web_worker/ui";
bootstrap("loader.js");
```
```JavaScript
// loader.js
importScripts("https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.33.3/es6-shim.js", "https://jspm.io/system@0.16.js", "angular2/web_worker/worker.js");
System.import("app");
```
```TypeScript
// app.ts
import {Component, View, bootstrapWebWorker} from "angular2/web_worker/worker";
@Component({
selector: "hello-world"
})
@View({
template: "<h1>Hello {{name}}</h1>
})
export class HelloWorld {
name: string = "Jane";
}
bootstrapWebWorker(HelloWorld);
```
There's a few important things to note here:
* On the UI side we import all angular types from `angular2/web_worker/ui` and on the worker side we import from
`angular2/web_worker/worker`. These modules include all the typings in the WebWorker bundle. By importing from
these URLs instead of `angular2/angular2` we can statically ensure that our app does not reference a type that
doesn't exist in the context it's mean to execute in. For example, if we tried to import DomRenderer in the Worker
or NgFor on the UI we would get a compiler error.
* The UI loads angular from the file `angular2/web_worker/ui.js` and the Worker loads angular from
`angular2/web_worker/worker.js`. These bundles are created specifically for using WebWorkers and should be used
instead of the normal angular2.js file. Both files contain subsets of the angular2 codebase that is designed to
run specifically on the UI or Worker. Additionally, they contain the core messaging infrastructure used to
communicate between the Worker and the UI. This messaging code is not in the standard angular2.js file.
* We pass `loader.js` to bootstrap and not `app.ts`. You can think of `loader.js` as the `index.html` of the
Worker. Since WebWorkers share no memory with the UI we need to reload the angular2 dependencies before
bootstrapping our application. We do this with `importScripts`. Additionally, we need to do this in a different
file than `app.ts` because our module loader (System.js in this example) has not been loaded yet, and `app.ts`
will be compiled with a `System.define` call at the top.
* The HelloWorld Component looks exactly like a normal Angular2 HelloWorld Component! The goal of WebWorker
support was to allow as much of Angular to live in the worker as possible.
As such, *most* angular2 components can be bootstrapped in a WebWorker with minimal to no changes required.
For reference, here's the same HelloWorld example in Dart.
```HTML
<html>
<body>
<script type="application/dart" src="index.dart"></script>
<script src="packages/browser.dart.js"></script>
</body>
</html>
```
```Dart
// index.dart
import "package:angular2/web_worker/ui.dart";
import "package:angular2/src/core/reflection/reflection.dart";
import "package:angular2/src/core/reflection/reflection_capabilities.dart";
main() {
reflector.reflectionCapabilities = new ReflectionCabilities();
bootstrap("app.dart");
}
```
```Dart
import "package:angular2/web_worker/worker.dart";
import "package:angular2/src/core/reflection/reflection.dart";
import "package:angular2/src/core/reflection/reflection_capabilities.dart";
@Component(
selector: "hello-world"
)
@View(
template: "<h1>Hello {{name}}</h1>"
)
class HelloWorld {
String name = "Jane";
}
main(List<String> args, SendPort replyTo) {
reflector.reflectionCapabilities = new ReflectionCapabilities();
bootstrapWebWorker(replyTo, HelloWorld);
}
```
This code is nearly the same as the TypeScript version with just a couple key differences:
* We don't have a `loader.js` file. Dart applications don't need this file because you don't need a module loader.
* We pass a `SendPort` to `bootstrapWebWorker`. Dart applications use the Isolate API, which communicates via
Dart's Port abstraction. When you call `bootstrap` from the UI thread, angular starts a new Isolate to run
your application logic. When Dart starts a new Isolate it passes a `SendPort` to that Isolate so that it
can communicate with the Isolate that spawned it. You need to pass this `SendPort` to `bootstrapWebWorker`
so that Angular can communicate with the UI.
* You need to set up `ReflectionCapabilities` on both the UI and Worker. Just like writing non-concurrent
Angular2 Dart applications you need to set up the reflector. You should not use Reflection in production,
but should use the angular 2 transformer to remove it in your final JS code. Note there's currently a bug
with running the transformer on your UI code (#3971). You can (and should) pass the file where you call
`bootstrapWebWorker` as an entry point to the transformer, but you should not pass your UI index file
to the transformer until that bug is fixed.
## Writing WebWorker Compatible Components
You can do almost everything in a WebWorker component that you can do in a typical Angular 2 Component.
The main exception is that there is **no** DOM access from a WebWorker component. In Dart this means you can't
import anything from `dart:html` and in JavaScript it means you can't use `document` or `window`. Instead you
should use data bindings and if needed you can inject the `Renderer` along with your component's `ElementRef`
directly into your component and use methods such as `setElementProperty`, `setElementAttribute`,
`setElementClass`, `setElementStyle`, `invokeElementMethod`, and `setText`. Note that you **cannot** call
`getNativeElementSync`. Doing so will always return `null` when running in a WebWorker.
If you need DOM access see [Running Code on the UI](#running-code-on-the-ui).
## WebWorker Design Overview
When running your application in a WebWorker, the majority of the angular core along with your application logic
runs on the worker. The two main components that run on the UI are the `Renderer` and the `RenderCompiler`. When
running angular in a WebWorker the bindings for these two components are replaced by the `WebWorkerRenderer` and
the `WebWorkerRenderCompiler`. When these components are used at runtime, they pass messages through the
[MessageBroker](#messagebroker) instructing the UI to run the actual method and return the result. The
[MessageBroker](#messagebroker) abstraction allows either side of the WebWorker boundary to schedule code to run
on the opposite side and receive the result. You can use the [MessageBroker](#messagebroker)
Additionally, the [MessageBroker](#messagebroker) sits on top of the [MessageBus](#messagebus).
MessageBus is a low level abstraction that provides a language agnostic API for communicating with angular components across any runtime boundary such as `WebWorker <--> UI` communication, `UI <--> Server` communication,
or `Window <--> Window` communication.
See the diagram below for a high level overview of how this code is structured:
![WebWorker Diagram](http://stanford.edu/~jteplitz/ng_2_worker.png)
## Running Code on the UI
If your application needs to run code on the UI, there are a few options. The easiest way is to use a
CustomElement in your view. You can then register this custom element from your html file and run code in response
to the element's lifecycle hooks. Note, Custom Elements are still experimental. See
[MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements) for the latest details on how
to use them.
If you require more robust communication between the WebWorker and the UI you can use the [MessageBroker](#using-the-messagebroker-in-your-application) or
[MessageBus](#using-the-messagebus-in-your-application) directly.
## MessageBus
The MessageBus is a low level abstraction that provides a language agnostic API for communicating with angular components across any runtime boundary. It supports multiplex communication through the use of a channel
abstraction.
Angular currently includes two stable MessageBus implementations, which are used by default when you run your
application inside a WebWorker.
1. The `PostMessageBus` is used by JavaScript applications to communicate between a WebWorker and the UI.
2. The `IsolateMessageBus` is used by Dart applications to communicate between a background Isolate and the UI.
Angular also includes three experimental MessageBus implementations:
1. The `WebSocketMessageBus` is a Dart MessageBus that lives on the UI and communicates with an angular
application running on a server. It's intended to be used with either the `SingleClientServerMessageBus` or the
`MultiClientServerMessageBus`.
2. The `SingleClientServerMessageBus` is a Dart MessageBus that lives on a Dart Server. It allows an angular
application to run on a server and communicate with a single browser that's running the `WebSocketMessageBus`.
3. The `MultiClientServerMessageBus` is like the `SingleClientServerMessageBus` except it allows an arbitrary
number of clients to connect to the server. It keeps all connected browsers in sync and if an event fires in
any connected browser it propagates the result to all connected clients. This can be especially useful as a
debugging tool, by allowing you to connect multiple browsers / devices to the same angular application,
change the state of that application, and ensure that all the clients render the view correctly. Using these tools
can make it easy to catch tricky browser compatibility issues.
### Using the MessageBus in Your Application
**Note**: If you want to pass custom messages between the UI and WebWorker, it's recommended you use the
[MessageBroker](#using-the-messagebroker-in-your-application). However, if you want to control the messaging
protocol yourself you can use the MessageBus directly.
To use the MessageBus you need to initialize a new channel on both the UI and WebWorker.
In TypeScript that would look like this:
```TypeScript
// index.ts, which is running on the UI.
var instance = bootstrap("loader.js");
var bus = instance.bus;
bus.initChannel("My Custom Channel");
```
```TypeScript
// background_index.ts, which is running on the WebWorker
import {MessageBus} from 'angular2/web_worker/worker';
@Component({...})
@View({...})
export class MyComponent {
constructor (bus: MessageBus) {
bus.initChannel("My Custom Channel");
}
}
```
Once the channel has been initialized either side can use the `from` and `to` methods on the MessageBus to send
and receive messages. Both methods return EventEmitter. Expanding on the example from earlier:
```TypeScript
// index.ts, which is running on the UI.
import {bootstrap} from 'angular2/web_worker/ui';
var instance = bootstrap("loader.js");
var bus = instance.bus;
bus.initChannel("My Custom Channel");
bus.to("My Custom Channel").next("hello from the UI");
```
```TypeScript
// background_index.ts, which is running on the WebWorker
import {MessageBus, Component, View} from 'angular2/web_worker/worker';
@Component({...})
@View({...})
export class MyComponent {
constructor (bus: MessageBus) {
bus.initChannel("My Custom Channel");
bus.from("My Custom Channel").observer((message) => {
console.log(message); // will print "hello from the UI"
});
}
}
```
This example is nearly identical in Dart, and is included below for reference:
```Dart
// index.dart, which is running on the UI.
import 'package:angular2/web_workers/ui.dart';
main() {
var instance = bootstrap("background_index.dart");
var bus = instance.bus;
bus.initChannel("My Custom Channel");
bus.to("My Custom Channel").add("hello from the UI");
}
```
```Dart
// background_index.dart, which is running on the WebWorker
import 'package:angular2/web_worker/worker.dart';
@Component(...)
@View(...)
class MyComponent {
MyComponent (MessageBus bus) {
bus.initChannel("My Custom Channel");
bus.from("My Custom Channel").listen((message) {
print(message); // will print "hello from the UI"
});
}
}
```
The only substantial difference between these APIs in Dart and TypeScript is the different APIs for the
`EventEmitter`.
**Note:** Because the messages passed through the MessageBus cross a WebWorker boundary, they must be serializable.
If you use the MessageBus directly, you are responsible for serializing your messages.
In JavaScript / TypeScript this means they must be serializable via JavaScript's
[structured cloning algorithim](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).
In Dart this means they must be valid messages that can be passed through a
[SendPort](https://api.dartlang.org/1.12.1/dart-isolate/SendPort/send.html).
### MessageBus and Zones
The MessageBus API includes support for [zones](http://www.github.com/angular/zone.js).
A MessageBus can be attached to a specific zone (by calling `attachToZone`). Then specific channels can be
specified to run in the zone when they are initialized.
If a channel is running in the zone, that means that any events emitted from that channel will be executed within
the given zone. For example, by default angular runs the EventDispatch channel inside the angular zone. That means
when an event is fired from the DOM and received on the WebWorker the event handler automatically runs inside the
angular zone. This is desired because after the event handler exits we want to exit the zone so that we trigger
change detection. Generally, you want your channels to run inside the zone unless you have a good reason for why
they need to run outside the zone.
### Implementing and Using a Custom MessageBus
**Note:** Implementing and using a Custom MessageBus is experimental and requires importing from private APIs.
If you want to drive your application from something other than a WebWorker you can implement a custom message
bus. Implementing a custom message bus just means creating a class that fulfills the API specified by the
abstract MessageBus class.
If you're implementing your MessageBus in Dart you can extend the `GenericMessageBus` class included in angular.
if you do this, you don't need to implement zone or channel support yourself. You only need to implement a
`MessageBusSink` that extends `GenericMessageBusSink` and a `MessageBusSource` that extends
`GenericMessageBusSource`. The `MessageBusSink` must override the `sendMessages` method. This method is
given a list of serialized messages that it is required to send through the sink.
The `MessageBusSource` needs to provide a [Stream](https://api.dartlang.org/1.12.1/dart-async/Stream-class.html)
of incoming messages (either by passing the stream to `GenericMessageBusSource's` constructor or by calling
attachTo() with the stream). It also needs to override the abstract `decodeMessages` method. This method is
given a List of serialized messages received by the source and should perform any decoding work that needs to be
done before the application can read the messages.
For example, if your MessageBus sends and receives JSON data you would do the following:
```Dart
import 'package:angular2/src/web_workers/shared/generic_message_bus.dart';
import 'dart:convert';
class JsonMessageBusSink extends GenericMessageBusSink {
@override
void sendMessages(List<dynamic> messages) {
String encodedMessages = JSON.encode(messages);
// Send encodedMessages here
}
}
class JsonMessageBusSource extends GenericMessageBuSource {
JsonMessageBusSource(Stream incomingMessages) : super (incomingMessages);
@override
List<dynamic> decodeMessages(dynamic messages) {
return JSON.decode(messages);
}
}
```
Once you've implemented your custom MessageBus in either TypeScript or Dart, you can tell angular to use it like
so:
In TypeScript:
```TypeScript
// index.ts, running on the UI side
import {bootstrapUICommon} from 'angular2/src/web_workers/ui/impl';
var bus = new MyAwesomeMessageBus();
bootstrapUICommon(bus);
```
```TypeScript
// background_index.ts, running on the application side
import {bootstrapWebWorkerCommon} from 'angular2/src/web_workers/worker/application_common';
import {MyApp} from './app';
var bus = new MyAwesomeMessageBus();
bootstrapWebWorkerCommon(MyApp, bus);
```
In Dart:
```Dart
// index.dart, running on the UI side
import 'package:angular2/src/web_workers/ui/impl.dart' show bootstrapUICommon;
import "package:angular2/src/core/reflection/reflection.dart";
import "package:angular2/src/core/reflection/reflection_capabilities.dart";
main() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
var bus = new MyAwesomeMessageBus();
bootstrapUiCommon(bus);
}
```
```Dart
// background_index.dart, running on the application side
import "package:angular2/src/web_workers/worker/application_common.dart" show bootstrapWebWorkerCommon;
import "package:angular2/src/core/reflection/reflection.dart";
import "package:angular2/src/core/reflection/reflection_capabilities.dart";
import "./app.dart" show MyApp;
main() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
var bus = new MyAwesomeMessageBus();
bootstrapWebWorkerCommon(MyApp, bus);
}
```
Notice how we call `bootstrapUICommon` instead of `bootstrap` from the UI side. `bootstrap` spans a new WebWorker
/ Isolate and attaches the default angular MessageBus to it. If you're using a custom MessageBus you are
responsible for setting up the application side and initiating communication with it. `bootstrapUICommon` assumes
that the given MessageBus is already set up and can communicate with the application.
Similarly, we call `bootstrapWebWorkerCommon` instead of `boostrapWebWorker` from the application side. This is
because `bootstrapWebWorker` assumes you're using the default angular MessageBus and initializes a new one for you.
## MessageBroker
The MessageBroker is a higher level messaging abstraction that sits on top of the MessageBus. It is used when you
want to execute code on the other side of a runtime boundary and may want to receive the result.
There are two types of MessageBrokers:
1. The `ServiceMessageBroker` is used by the side that actually performs
an operation and may return a result;
2. The `ClientMessageBroker` is used by the side that requests that
an operation be performed and may want to receive the result.
### Using the MessageBroker In Your Application
To use MessageBrokers in your application you must initialize both a `ClientMessageBroker` and a
`ServiceMessageBroker` on the same channel. You can then register methods with the `ServiceMessageBroker` and
instruct the `ClientMessageBroker` to run those methods. Below is a lightweight example of using
MessageBrokers in an application. For a more complete example, check out the `WebWorkerRenderer` and
`MessageBasedRenderer` inside the Angular WebWorker code.
#### Using the MessageBroker in TypeScript
```TypeScript
// index.ts, which is running on the UI with a method that we want to expose to a WebWorker
import {bootstrap} from 'angular2/web_worker/ui';
var instance = bootstrap("loader.js");
var broker = instance.app.createServiceMessageBroker("My Broker Channel");
// assume we have some function doCoolThings that takes a string argument and returns a Promise<string>
broker.registerMethod("awesomeMethod", [PRIMITIVE], (arg1: string) => doCoolThing(arg1), PRIMITIVE);
```
```TypeScript
// background.ts, which is running on a WebWorker and wants to execute a method on the UI
import {Component, View, ClientMessageBrokerFactory, PRIMITIVE, UiArguments, FnArgs}
from 'angular2/web_worker/worker';
@Component(...)
@View(...)
export class MyComponent {
constructor(brokerFactory: ClientMessageBrokerFactory) {
var broker = brokerFactory.createMessageBroker("My Broker Channel");
var arguments = [new FnArg(value, PRIMITIVE)];
var methodInfo = new UiArguments("awesomeMethod", arguments);
broker.runOnService(methodInfo, PRIMTIVE).then((result: string) => {
// result will be equal to the return value of doCoolThing(value) that ran on the UI.
});
}
}
```
#### Using the MessageBroker in Dart
```Dart
// index.dart, which is running on the UI with a method that we want to expose to a WebWorker
import 'package:angular2/web_worker/ui.dart';
main() {
var instance = bootstrap("background.dart");
var broker = instance.app.createServiceMessageBroker("My Broker Channel");
// assume we have some function doCoolThings that takes a String argument and returns a Future<String>
broker.registerMethod("awesomeMethod", [PRIMITIVE], (String arg1) => doCoolThing(arg1), PRIMITIVE);
}
```
```Dart
// background.dart, which is running on a WebWorker and wants to execute a method on the UI
import 'package:angular2/web_worker/worker.dart';
@Component(...)
@View(...)
class MyComponent {
MyComponent(ClientMessageBrokerFactory brokerFactory) {
var broker = brokerFactory.createMessageBroker("My Broker Channel");
var arguments = [new FnArg(value, PRIMITIVE)];
var methodInfo = new UiArguments("awesomeMethod", arguments);
broker.runOnService(methodInfo, PRIMTIVE).then((String result) {
// result will be equal to the return value of doCoolThing(value) that ran on the UI.
});
}
}
```
Both the client and the service create new MessageBrokers and attach them to the same channel.
The service then calls `registerMethod` to register the method that it wants to listen to. Register method takes
four arguments. The first is the name of the method, the second is the Types of that method's parameters, the
third is the method itself, and the fourth (which is optional) is the return Type of that method.
The MessageBroker handles serializing / deserializing your parameters and return types using angular's serializer.
However, at the moment the serializer only knows how to serialize angular classes like those used by the Renderer.
If you're passing anything other than those types around in your application you can handle serialization yourself
and then use the `PRIMITIVE` type to tell the MessageBroker to avoid serializing your data.
The last thing that happens is that the client calls `runOnService` with the name of the method it wants to run,
a list of that method's arguments and their types, and (optionally) the expected return type.
+15
View File
@@ -0,0 +1,15 @@
Angular2
=========
The sources for this package are in the main [Angular2](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo. This is the repository for the upcoming 2.0 version. If you're looking for the current official version of Angular you should go to [angular/angular.js](https://github.com/angular/angular.js)
This package contains different sources for different users:
1. The files located in the root folder can be consumed using CommonJS.
2. The files under `/es6` are es6 compatible files that can be transpiled to
es5 using any transpiler. This contains:
* `dev/`: a development version that includes runtime type assertions
* `prod/`: a production version that does not include runtime type assertions
3. The files under `/ts` are the TypeScript source files.
License: Apache MIT 2.0
+8
View File
@@ -0,0 +1,8 @@
export * from './common';
export * from './core';
export * from './profile';
export * from './lifecycle_hooks';
export * from './platform/browser';
export * from './upgrade';
export { UrlResolver, AppRootUrl } from './compiler';
//# sourceMappingURL=angular2.js.map
+16
View File
@@ -0,0 +1,16 @@
import * as ng from './angular2';
import * as router from './router';
import * as http from './http';
var _prevNg = window.ng;
window.ng = ng;
window.ngRouter = router;
window.ngHttp = http;
/**
* Calling noConflict will restore window.angular to its pre-angular loading state
* and return the angular module object.
*/
ng.noConflict = function () {
window.ng = _prevNg;
return ng;
};
//# sourceMappingURL=angular2_sfx.js.map
+6
View File
@@ -0,0 +1,6 @@
export { Animation } from './src/animate/animation';
export { AnimationBuilder } from './src/animate/animation_builder';
export { BrowserDetails } from './src/animate/browser_details';
export { CssAnimationBuilder } from './src/animate/css_animation_builder';
export { CssAnimationOptions } from './src/animate/css_animation_options';
//# sourceMappingURL=animate.js.map
+6
View File
@@ -0,0 +1,6 @@
/**
* See {@link bootstrap} for more information.
* @deprecated
*/
export { bootstrap } from 'angular2/platform/browser';
//# sourceMappingURL=bootstrap.js.map
+6
View File
@@ -0,0 +1,6 @@
/**
* See {@link bootstrap} for more information.
* @deprecated
*/
export { bootstrapStatic } from 'angular2/platform/browser_static';
//# sourceMappingURL=bootstrap_static.js.map
+5
View File
@@ -0,0 +1,5 @@
export * from './src/common/pipes';
export * from './src/common/directives';
export * from './src/common/forms';
export * from './src/common/common_directives';
//# sourceMappingURL=common.js.map
+10
View File
@@ -0,0 +1,10 @@
/**
* @module
* @description
* Starting point to import all compiler APIs.
*/
export * from './src/compiler/url_resolver';
export * from './src/compiler/xhr';
export * from './src/compiler/compiler';
export * from './src/compiler/app_root_url';
//# sourceMappingURL=compiler.js.map
+27
View File
@@ -0,0 +1,27 @@
/**
* @module
* @description
* Starting point to import all public core APIs.
*/
export * from './src/core/metadata';
export * from './src/core/util';
export * from './src/core/di';
export * from './src/common/pipes';
export * from './src/facade/facade';
export * from './src/core/linker';
export { platform, createNgZone, PlatformRef, ApplicationRef } from './src/core/application_ref';
export { APP_ID, APP_COMPONENT } from './src/core/application_tokens';
export * from './src/core/zone';
export * from './src/core/render';
export * from './src/common/directives';
export * from './src/common/forms';
export { DebugElement, Scope, inspectElement, asNativeElements } from './src/core/debug/debug_element';
export * from './src/core/testability/testability';
export * from './src/core/change_detection';
export * from './src/core/platform_directives_and_pipes';
export * from './src/core/dev_mode';
export * from './src/core/reflection/reflection';
export * from './src/core/application_common_providers';
export * from './src/core/platform_common_providers';
export * from './src/core/dom/dom_adapter';
//# sourceMappingURL=core.js.map
@@ -0,0 +1,74 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Component, Observable } from 'angular2/angular2';
import { bootstrap } from 'angular2/bootstrap';
// #docregion AsyncPipe
export let AsyncPipeExample = class {
constructor() {
this.resolved = false;
this.promise = null;
this.resolve = null;
this.reset();
}
reset() {
this.resolved = false;
this.promise = new Promise((resolve, reject) => { this.resolve = resolve; });
}
clicked() {
if (this.resolved) {
this.reset();
}
else {
this.resolve("resolved!");
this.resolved = true;
}
}
};
AsyncPipeExample = __decorate([
Component({
selector: 'async-example',
template: `<div>
<p>Wait for it... {{promise | async}}</p>
<button (click)="clicked()">{{resolved ? 'Reset' : 'Resolve'}}</button>
</div>`
}),
__metadata('design:paramtypes', [])
], AsyncPipeExample);
// #enddocregion
// #docregion AsyncPipeObservable
let Task = class {
constructor() {
this.time = new Observable(observer => { setInterval(_ => observer.next(new Date().getTime()), 500); });
}
};
Task = __decorate([
Component({ selector: "task-cmp", template: "Time: {{ time | async }}" }),
__metadata('design:paramtypes', [])
], Task);
// #enddocregion
export let AppCmp = class {
};
AppCmp = __decorate([
Component({
selector: 'example-app',
directives: [AsyncPipeExample],
template: `
<h1>AsyncPipe Example</h1>
<async-example></async-example>
`
}),
__metadata('design:paramtypes', [])
], AppCmp);
export function main() {
bootstrap(AppCmp);
}
//# sourceMappingURL=async_pipe_example.js.map
@@ -0,0 +1,48 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Component } from 'angular2/angular2';
import { bootstrap } from 'angular2/bootstrap';
// #docregion DatePipe
export let DatePipeExample = class {
constructor() {
this.today = Date.now();
}
};
DatePipeExample = __decorate([
Component({
selector: 'date-example',
template: `<div>
<p>Today is {{today | date}}</p>
<p>Or if you prefer, {{today | date:'fullDate'}}</p>
<p>The time is {{today | date:'jmZ'}}</p>
</div>`
}),
__metadata('design:paramtypes', [])
], DatePipeExample);
// #enddocregion
export let AppCmp = class {
};
AppCmp = __decorate([
Component({
selector: 'example-app',
directives: [DatePipeExample],
template: `
<h1>DatePipe Example</h1>
<date-example></date-example>
`
}),
__metadata('design:paramtypes', [])
], AppCmp);
export function main() {
bootstrap(AppCmp);
}
//# sourceMappingURL=date_pipe_example.js.map
@@ -0,0 +1,49 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Component } from 'angular2/angular2';
import { bootstrap } from 'angular2/bootstrap';
// #docregion JsonPipe
export let JsonPipeExample = class {
constructor() {
this.object = { foo: 'bar', baz: 'qux', nested: { xyz: 3, numbers: [1, 2, 3, 4, 5] } };
}
};
JsonPipeExample = __decorate([
Component({
selector: 'json-example',
template: `<div>
<p>Without JSON pipe:</p>
<pre>{{object}}</pre>
<p>With JSON pipe:</p>
<pre>{{object | json}}</pre>
</div>`
}),
__metadata('design:paramtypes', [])
], JsonPipeExample);
// #enddocregion
export let AppCmp = class {
};
AppCmp = __decorate([
Component({
selector: 'example-app',
directives: [JsonPipeExample],
template: `
<h1>JsonPipe Example</h1>
<json-example></json-example>
`
}),
__metadata('design:paramtypes', [])
], AppCmp);
export function main() {
bootstrap(AppCmp);
}
//# sourceMappingURL=json_pipe_example.js.map
@@ -0,0 +1,46 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Component } from 'angular2/angular2';
import { bootstrap } from 'angular2/bootstrap';
// #docregion LowerUpperPipe
export let LowerUpperPipeExample = class {
change(value) { this.value = value; }
};
LowerUpperPipeExample = __decorate([
Component({
selector: 'lowerupper-example',
template: `<div>
<label>Name: </label><input #name (keyup)="change(name.value)" type="text"></input>
<p>In lowercase: <pre>'{{value | lowercase}}'</pre></p>
<p>In uppercase: <pre>'{{value | uppercase}}'</pre></p>
</div>`
}),
__metadata('design:paramtypes', [])
], LowerUpperPipeExample);
// #enddocregion
export let AppCmp = class {
};
AppCmp = __decorate([
Component({
selector: 'example-app',
directives: [LowerUpperPipeExample],
template: `
<h1>LowercasePipe &amp; UppercasePipe Example</h1>
<lowerupper-example></lowerupper-example>
`
}),
__metadata('design:paramtypes', [])
], AppCmp);
export function main() {
bootstrap(AppCmp);
}
//# sourceMappingURL=lowerupper_pipe_example.js.map
@@ -0,0 +1,91 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Component } from 'angular2/angular2';
import { bootstrap } from 'angular2/bootstrap';
// #docregion NumberPipe
export let NumberPipeExample = class {
constructor() {
this.pi = 3.141;
this.e = 2.718281828459045;
}
};
NumberPipeExample = __decorate([
Component({
selector: 'number-example',
template: `<div>
<p>e (no formatting): {{e}}</p>
<p>e (3.1-5): {{e | number:'3.1-5'}}</p>
<p>pi (no formatting): {{pi}}</p>
<p>pi (3.5-5): {{pi | number:'3.5-5'}}</p>
</div>`
}),
__metadata('design:paramtypes', [])
], NumberPipeExample);
// #enddocregion
// #docregion PercentPipe
export let PercentPipeExample = class {
constructor() {
this.a = 0.259;
this.b = 1.3495;
}
};
PercentPipeExample = __decorate([
Component({
selector: 'percent-example',
template: `<div>
<p>A: {{a | percent}}</p>
<p>B: {{b | percent:'4.3-5'}}</p>
</div>`
}),
__metadata('design:paramtypes', [])
], PercentPipeExample);
// #enddocregion
// #docregion CurrencyPipe
export let CurrencyPipeExample = class {
constructor() {
this.a = 0.259;
this.b = 1.3495;
}
};
CurrencyPipeExample = __decorate([
Component({
selector: 'currency-example',
template: `<div>
<p>A: {{a | currency:'USD':false}}</p>
<p>B: {{b | currency:'USD':true:'4.2-2'}}</p>
</div>`
}),
__metadata('design:paramtypes', [])
], CurrencyPipeExample);
// #enddocregion
export let AppCmp = class {
};
AppCmp = __decorate([
Component({
selector: 'example-app',
directives: [NumberPipeExample, PercentPipeExample, CurrencyPipeExample],
template: `
<h1>Numeric Pipe Examples</h1>
<h2>NumberPipe Example</h2>
<number-example></number-example>
<h2>PercentPipe Example</h2>
<percent-example></percent-example>
<h2>CurrencyPipeExample</h2>
<currency-example></currency-example>
`
}),
__metadata('design:paramtypes', [])
], AppCmp);
export function main() {
bootstrap(AppCmp);
}
//# sourceMappingURL=number_pipe_example.js.map
@@ -0,0 +1,68 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Component } from 'angular2/angular2';
import { bootstrap } from 'angular2/bootstrap';
// #docregion SlicePipe_string
export let SlicePipeStringExample = class {
constructor() {
this.str = 'abcdefghij';
}
};
SlicePipeStringExample = __decorate([
Component({
selector: 'slice-string-example',
template: `<div>
<p>{{str}}[0:4]: '{{str | slice:0:4}}' - output is expected to be 'abcd'</p>
<p>{{str}}[4:0]: '{{str | slice:4:0}}' - output is expected to be ''</p>
<p>{{str}}[-4]: '{{str | slice:-4}}' - output is expected to be 'ghij'</p>
<p>{{str}}[-4:-2]: '{{str | slice:-4:-2}}' - output is expected to be 'gh'</p>
<p>{{str}}[-100]: '{{str | slice:-100}}' - output is expected to be 'abcdefghij'</p>
<p>{{str}}[100]: '{{str | slice:100}}' - output is expected to be ''</p>
</div>`
}),
__metadata('design:paramtypes', [])
], SlicePipeStringExample);
// #enddocregion
// #docregion SlicePipe_list
export let SlicePipeListExample = class {
constructor() {
this.collection = ['a', 'b', 'c', 'd'];
}
};
SlicePipeListExample = __decorate([
Component({
selector: 'slice-list-example',
template: `<div>
<li *ng-for="var i of collection | slice:1:3">{{i}}</li>
</div>`
}),
__metadata('design:paramtypes', [])
], SlicePipeListExample);
// #enddocregion
export let AppCmp = class {
};
AppCmp = __decorate([
Component({
selector: 'example-app',
directives: [SlicePipeListExample, SlicePipeStringExample],
template: `
<h1>SlicePipe Examples</h1>
<slice-list-example></slice-list-example>
<slice-string-example></slice-string-example>
`
}),
__metadata('design:paramtypes', [])
], AppCmp);
export function main() {
bootstrap(AppCmp);
}
//# sourceMappingURL=slice_pipe_example.js.map
@@ -0,0 +1,6 @@
import { bootstrap, enableDevMode } from 'angular2/angular2';
import { MyComponent } from 'my_component';
enableDevMode();
bootstrap(MyComponent);
// #enddocregion
//# sourceMappingURL=dev_mode_example.js.map
@@ -0,0 +1,19 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Component } from 'angular2/core';
export let MyComponent = class {
};
MyComponent = __decorate([
Component({ selector: 'my-component', template: '<h1>My Component</h1>' }),
__metadata('design:paramtypes', [])
], MyComponent);
//# sourceMappingURL=my_component.js.map
@@ -0,0 +1,62 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { bootstrap, provide, Component } from 'angular2/angular2';
import { CanActivate, RouteConfig, APP_BASE_HREF, ROUTER_DIRECTIVES } from 'angular2/router';
function checkIfWeHavePermission(instruction) {
return instruction.params['id'] == '1';
}
// #docregion canActivate
let ControlPanelCmp = class {
};
ControlPanelCmp = __decorate([
Component({ selector: 'control-panel-cmp', template: `<div>Settings: ...</div>` }),
CanActivate(checkIfWeHavePermission),
__metadata('design:paramtypes', [])
], ControlPanelCmp);
// #enddocregion
let HomeCmp = class {
};
HomeCmp = __decorate([
Component({
selector: 'home-cmp',
template: `
<h1>Welcome Home!</h1>
<div>
Edit <a [router-link]="['/ControlPanelCmp', {id: 1}]" id="user-1-link">User 1</a> |
Edit <a [router-link]="['/ControlPanelCmp', {id: 2}]" id="user-2-link">User 2</a>
</div>
`,
directives: [ROUTER_DIRECTIVES]
}),
__metadata('design:paramtypes', [])
], HomeCmp);
let AppCmp = class {
};
AppCmp = __decorate([
Component({
selector: 'example-app',
template: `
<h1>My App</h1>
<router-outlet></router-outlet>
`,
directives: [ROUTER_DIRECTIVES]
}),
RouteConfig([
{ path: '/user-settings/:id', component: ControlPanelCmp, name: 'ControlPanelCmp' },
{ path: '/', component: HomeCmp, name: 'HomeCmp' }
]),
__metadata('design:paramtypes', [])
], AppCmp);
export function main() {
return bootstrap(AppCmp, [provide(APP_BASE_HREF, { useValue: '/angular2/examples/router/ts/can_activate' })]);
}
//# sourceMappingURL=can_activate_example.js.map
@@ -0,0 +1,26 @@
import { verifyNoBrowserErrors } from 'angular2/src/testing/e2e_util';
function waitForElement(selector) {
var EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to be present on the dom.
browser.wait(EC.presenceOf($(selector)), 20000);
}
describe('reuse example app', function () {
afterEach(verifyNoBrowserErrors);
var URL = 'angular2/examples/router/ts/can_activate/';
it('should navigate to user 1', function () {
browser.get(URL);
waitForElement('home-cmp');
element(by.css('#user-1-link')).click();
waitForElement('control-panel-cmp');
expect(browser.getCurrentUrl()).toMatch(/\/user-settings\/1$/);
expect(element(by.css('control-panel-cmp')).getText()).toContain('Settings');
});
it('should not navigate to user 2', function () {
browser.get(URL);
waitForElement('home-cmp');
element(by.css('#user-2-link')).click();
waitForElement('home-cmp');
expect(element(by.css('home-cmp')).getText()).toContain('Welcome Home!');
});
});
//# sourceMappingURL=can_activate_spec.js.map
@@ -0,0 +1,71 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { provide, bootstrap, Component } from 'angular2/angular2';
import { RouteConfig, RouteParams, ROUTER_DIRECTIVES, APP_BASE_HREF } from 'angular2/router';
// #docregion canDeactivate
let NoteCmp = class {
constructor(params) {
this.id = params.get('id');
}
canDeactivate(next, prev) {
return confirm('Are you sure you want to leave?');
}
};
NoteCmp = __decorate([
Component({
selector: 'note-cmp',
template: `
<div>
<h2>id: {{id}}</h2>
<textarea cols="40" rows="10"></textarea>
</div>`
}),
__metadata('design:paramtypes', [RouteParams])
], NoteCmp);
// #enddocregion
let NoteIndexCmp = class {
};
NoteIndexCmp = __decorate([
Component({
selector: 'note-index-cmp',
template: `
<h1>Your Notes</h1>
<div>
Edit <a [router-link]="['/NoteCmp', {id: 1}]" id="note-1-link">Note 1</a> |
Edit <a [router-link]="['/NoteCmp', {id: 2}]" id="note-2-link">Note 2</a>
</div>
`,
directives: [ROUTER_DIRECTIVES]
}),
__metadata('design:paramtypes', [])
], NoteIndexCmp);
let AppCmp = class {
};
AppCmp = __decorate([
Component({
selector: 'example-app',
template: `
<h1>My App</h1>
<router-outlet></router-outlet>
`,
directives: [ROUTER_DIRECTIVES]
}),
RouteConfig([
{ path: '/note/:id', component: NoteCmp, name: 'NoteCmp' },
{ path: '/', component: NoteIndexCmp, name: 'NoteIndexCmp' }
]),
__metadata('design:paramtypes', [])
], AppCmp);
export function main() {
return bootstrap(AppCmp, [provide(APP_BASE_HREF, { useValue: '/angular2/examples/router/ts/can_deactivate' })]);
}
//# sourceMappingURL=can_deactivate_example.js.map
@@ -0,0 +1,36 @@
import { verifyNoBrowserErrors } from 'angular2/src/testing/e2e_util';
function waitForElement(selector) {
var EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to be present on the dom.
browser.wait(EC.presenceOf($(selector)), 20000);
}
function waitForAlert() {
var EC = protractor.ExpectedConditions;
browser.wait(EC.alertIsPresent(), 1000);
}
describe('can deactivate example app', function () {
afterEach(verifyNoBrowserErrors);
var URL = 'angular2/examples/router/ts/can_deactivate/';
it('should not navigate away when prompt is cancelled', function () {
browser.get(URL);
waitForElement('note-index-cmp');
element(by.css('#note-1-link')).click();
waitForElement('note-cmp');
browser.navigate().back();
waitForAlert();
browser.switchTo().alert().dismiss(); // Use to simulate cancel button
expect(element(by.css('note-cmp')).getText()).toContain('id: 1');
});
it('should navigate away when prompt is confirmed', function () {
browser.get(URL);
waitForElement('note-index-cmp');
element(by.css('#note-1-link')).click();
waitForElement('note-cmp');
browser.navigate().back();
waitForAlert();
browser.switchTo().alert().accept();
waitForElement('note-index-cmp');
expect(element(by.css('note-index-cmp')).getText()).toContain('Your Notes');
});
});
//# sourceMappingURL=can_deactivate_spec.js.map
@@ -0,0 +1,52 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Component, provide, bootstrap } from 'angular2/angular2';
import { RouteConfig, ROUTER_DIRECTIVES, APP_BASE_HREF } from 'angular2/router';
// #docregion onActivate
let MyCmp = class {
constructor() {
this.log = '';
}
onActivate(next, prev) {
this.log = `Finished navigating from "${prev ? prev.urlPath : 'null'}" to "${next.urlPath}"`;
}
};
MyCmp = __decorate([
Component({ selector: 'my-cmp', template: `<div>onActivate: {{log}}</div>` }),
__metadata('design:paramtypes', [])
], MyCmp);
// #enddocregion
let AppCmp = class {
};
AppCmp = __decorate([
Component({
selector: 'example-app',
template: `
<h1>My App</h1>
<nav>
<a [router-link]="['/HomeCmp']" id="home-link">Navigate Home</a> |
<a [router-link]="['/ParamCmp', {param: 1}]" id="param-link">Navigate with a Param</a>
</nav>
<router-outlet></router-outlet>
`,
directives: [ROUTER_DIRECTIVES]
}),
RouteConfig([
{ path: '/', component: MyCmp, name: 'HomeCmp' },
{ path: '/:param', component: MyCmp, name: 'ParamCmp' }
]),
__metadata('design:paramtypes', [])
], AppCmp);
export function main() {
return bootstrap(AppCmp, [provide(APP_BASE_HREF, { useValue: '/angular2/examples/router/ts/on_activate' })]);
}
//# sourceMappingURL=on_activate_example.js.map
@@ -0,0 +1,25 @@
import { verifyNoBrowserErrors } from 'angular2/src/testing/e2e_util';
function waitForElement(selector) {
var EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to be present on the dom.
browser.wait(EC.presenceOf($(selector)), 20000);
}
describe('on activate example app', function () {
afterEach(verifyNoBrowserErrors);
var URL = 'angular2/examples/router/ts/on_activate/';
it('should update the text when navigating between routes', function () {
browser.get(URL);
waitForElement('my-cmp');
expect(element(by.css('my-cmp')).getText())
.toContain('onActivate: Finished navigating from "null" to ""');
element(by.css('#param-link')).click();
waitForElement('my-cmp');
expect(element(by.css('my-cmp')).getText())
.toContain('onActivate: Finished navigating from "" to "1"');
browser.navigate().back();
waitForElement('my-cmp');
expect(element(by.css('my-cmp')).getText())
.toContain('onActivate: Finished navigating from "1" to ""');
});
});
//# sourceMappingURL=on_activate_spec.js.map
@@ -0,0 +1,72 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Component, Injectable, NgFor, provide, bootstrap } from 'angular2/angular2';
import { RouteConfig, ROUTER_DIRECTIVES, APP_BASE_HREF } from 'angular2/router';
let LogService = class {
constructor() {
this.logs = [];
}
addLog(message) { this.logs.push(message); }
};
LogService = __decorate([
Injectable(),
__metadata('design:paramtypes', [])
], LogService);
// #docregion onDeactivate
let MyCmp = class {
constructor(logService) {
this.logService = logService;
}
onDeactivate(next, prev) {
this.logService.addLog(`Navigating from "${prev ? prev.urlPath : 'null'}" to "${next.urlPath}"`);
}
};
MyCmp = __decorate([
Component({ selector: 'my-cmp', template: `<div>hello</div>` }),
__metadata('design:paramtypes', [LogService])
], MyCmp);
// #enddocregion
let AppCmp = class {
constructor(logService) {
this.logService = logService;
}
};
AppCmp = __decorate([
Component({
selector: 'example-app',
template: `
<h1>My App</h1>
<nav>
<a [router-link]="['/HomeCmp']" id="home-link">Navigate Home</a> |
<a [router-link]="['/ParamCmp', {param: 1}]" id="param-link">Navigate with a Param</a>
</nav>
<router-outlet></router-outlet>
<div id="log">
<h2>Log:</h2>
<p *ng-for="#logItem of logService.logs">{{ logItem }}</p>
</div>
`,
directives: [ROUTER_DIRECTIVES, NgFor]
}),
RouteConfig([
{ path: '/', component: MyCmp, name: 'HomeCmp' },
{ path: '/:param', component: MyCmp, name: 'ParamCmp' }
]),
__metadata('design:paramtypes', [LogService])
], AppCmp);
export function main() {
return bootstrap(AppCmp, [
provide(APP_BASE_HREF, { useValue: '/angular2/examples/router/ts/on_deactivate' }),
LogService
]);
}
//# sourceMappingURL=on_deactivate_example.js.map
@@ -0,0 +1,23 @@
import { verifyNoBrowserErrors } from 'angular2/src/testing/e2e_util';
function waitForElement(selector) {
var EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to be present on the dom.
browser.wait(EC.presenceOf($(selector)), 20000);
}
describe('on activate example app', function () {
afterEach(verifyNoBrowserErrors);
var URL = 'angular2/examples/router/ts/on_deactivate/';
it('should update the text when navigating between routes', function () {
browser.get(URL);
waitForElement('my-cmp');
expect(element(by.css('#log')).getText()).toEqual('Log:');
element(by.css('#param-link')).click();
waitForElement('my-cmp');
expect(element(by.css('#log')).getText()).toEqual('Log:\nNavigating from "" to "1"');
browser.navigate().back();
waitForElement('my-cmp');
expect(element(by.css('#log')).getText())
.toEqual('Log:\nNavigating from "" to "1"\nNavigating from "1" to ""');
});
});
//# sourceMappingURL=on_deactivate_spec.js.map
@@ -0,0 +1,57 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc);
switch (arguments.length) {
case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);
case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);
case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);
}
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { bootstrap, Component, provide } from 'angular2/angular2';
import { RouteConfig, ROUTER_DIRECTIVES, APP_BASE_HREF, RouteParams } from 'angular2/router';
// #docregion reuseCmp
let MyCmp = class {
constructor(params) {
this.name = params.get('name') || 'NOBODY';
}
canReuse(next, prev) { return true; }
onReuse(next, prev) {
this.name = next.params['name'];
}
};
MyCmp = __decorate([
Component({
selector: 'my-cmp',
template: `
<div>hello {{name}}!</div>
<div>message: <input id="message"></div>
`
}),
__metadata('design:paramtypes', [RouteParams])
], MyCmp);
// #enddocregion
let AppCmp = class {
};
AppCmp = __decorate([
Component({
selector: 'example-app',
template: `
<h1>Say hi to...</h1>
<a [router-link]="['/HomeCmp', {name: 'naomi'}]" id="naomi-link">Naomi</a> |
<a [router-link]="['/HomeCmp', {name: 'brad'}]" id="brad-link">Brad</a>
<router-outlet></router-outlet>
`,
directives: [ROUTER_DIRECTIVES]
}),
RouteConfig([
{ path: '/', component: MyCmp, name: 'HomeCmp' },
{ path: '/:name', component: MyCmp, name: 'HomeCmp' }
]),
__metadata('design:paramtypes', [])
], AppCmp);
export function main() {
return bootstrap(AppCmp, [provide(APP_BASE_HREF, { useValue: '/angular2/examples/router/ts/reuse' })]);
}
//# sourceMappingURL=reuse_example.js.map
@@ -0,0 +1,26 @@
import { verifyNoBrowserErrors } from 'angular2/src/testing/e2e_util';
function waitForElement(selector) {
var EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to be present on the dom.
browser.wait(EC.presenceOf($(selector)), 20000);
}
describe('reuse example app', function () {
afterEach(verifyNoBrowserErrors);
var URL = 'angular2/examples/router/ts/reuse/';
it('should build a link which points to the detail page', function () {
browser.get(URL);
waitForElement('my-cmp');
element(by.css('#naomi-link')).click();
waitForElement('my-cmp');
expect(browser.getCurrentUrl()).toMatch(/\/naomi$/);
// type something into input
element(by.css('#message')).sendKeys('long time no see!');
// navigate to Brad
element(by.css('#brad-link')).click();
waitForElement('my-cmp');
expect(browser.getCurrentUrl()).toMatch(/\/brad$/);
// check that typed input is the same
expect(element(by.css('#message')).getAttribute('value')).toEqual('long time no see!');
});
});
//# sourceMappingURL=reuse_spec.js.map
+268
View File
@@ -0,0 +1,268 @@
import { provide } from 'angular2/angular2';
import { Http, Jsonp } from './src/http/http';
import { XHRBackend } from './src/http/backends/xhr_backend';
import { JSONPBackend, JSONPBackend_ } from './src/http/backends/jsonp_backend';
import { BrowserXhr } from './src/http/backends/browser_xhr';
import { BrowserJsonp } from './src/http/backends/browser_jsonp';
import { BaseRequestOptions, RequestOptions } from './src/http/base_request_options';
import { BaseResponseOptions, ResponseOptions } from './src/http/base_response_options';
export { MockConnection, MockBackend } from './src/http/backends/mock_backend';
export { Request } from './src/http/static_request';
export { Response } from './src/http/static_response';
export { Connection, ConnectionBackend } from './src/http/interfaces';
export { BrowserXhr } from './src/http/backends/browser_xhr';
export { BaseRequestOptions, RequestOptions } from './src/http/base_request_options';
export { BaseResponseOptions, ResponseOptions } from './src/http/base_response_options';
export { XHRBackend, XHRConnection } from './src/http/backends/xhr_backend';
export { JSONPBackend, JSONPConnection } from './src/http/backends/jsonp_backend';
export { Http, Jsonp } from './src/http/http';
export { Headers } from './src/http/headers';
export { ResponseTypes, ReadyStates, RequestMethods } from './src/http/enums';
export { URLSearchParams } from './src/http/url_search_params';
/**
* Provides a basic set of injectables to use the {@link Http} service in any application.
*
* The `HTTP_PROVIDERS` should be included either in a component's injector,
* or in the root injector when bootstrapping an application.
*
* ### Example ([live demo](http://plnkr.co/edit/snj7Nv?p=preview))
*
* ```
* import {bootstrap, Component, NgFor, View} from 'angular2/angular2';
* import {HTTP_PROVIDERS, Http} from 'angular2/http';
*
* @Component({
* selector: 'app',
* providers: [HTTP_PROVIDERS],
* template: `
* <div>
* <h1>People</h1>
* <ul>
* <li *ng-for="#person of people">
* {{person.name}}
* </li>
* </ul>
* </div>
* `,
* directives: [NgFor]
* })
* export class App {
* people: Object[];
* constructor(http:Http) {
* http.get('people.json').subscribe(res => {
* this.people = res.json();
* });
* }
* active:boolean = false;
* toggleActiveState() {
* this.active = !this.active;
* }
* }
*
* bootstrap(App)
* .catch(err => console.error(err));
* ```
*
* The primary public API included in `HTTP_PROVIDERS` is the {@link Http} class.
* However, other providers required by `Http` are included,
* which may be beneficial to override in certain cases.
*
* The providers included in `HTTP_PROVIDERS` include:
* * {@link Http}
* * {@link XHRBackend}
* * `BrowserXHR` - Private factory to create `XMLHttpRequest` instances
* * {@link RequestOptions} - Bound to {@link BaseRequestOptions} class
* * {@link ResponseOptions} - Bound to {@link BaseResponseOptions} class
*
* There may be cases where it makes sense to extend the base request options,
* such as to add a search string to be appended to all URLs.
* To accomplish this, a new provider for {@link RequestOptions} should
* be added in the same injector as `HTTP_PROVIDERS`.
*
* ### Example ([live demo](http://plnkr.co/edit/aCMEXi?p=preview))
*
* ```
* import {provide, bootstrap} from 'angular2/angular2';
* import {HTTP_PROVIDERS, BaseRequestOptions, RequestOptions} from 'angular2/http';
*
* class MyOptions extends BaseRequestOptions {
* search: string = 'coreTeam=true';
* }
*
* bootstrap(App, [HTTP_PROVIDERS, provide(RequestOptions, {useClass: MyOptions})])
* .catch(err => console.error(err));
* ```
*
* Likewise, to use a mock backend for unit tests, the {@link XHRBackend}
* provider should be bound to {@link MockBackend}.
*
* ### Example ([live demo](http://plnkr.co/edit/7LWALD?p=preview))
*
* ```
* import {provide, Injector} from 'angular2/angular2';
* import {HTTP_PROVIDERS, Http, Response, XHRBackend, MockBackend} from 'angular2/http';
*
* var people = [{name: 'Jeff'}, {name: 'Tobias'}];
*
* var injector = Injector.resolveAndCreate([
* HTTP_PROVIDERS,
* MockBackend,
* provide(XHRBackend, {useExisting: MockBackend})
* ]);
* var http = injector.get(Http);
* var backend = injector.get(MockBackend);
*
* // Listen for any new requests
* backend.connections.observer({
* next: connection => {
* var response = new Response({body: people});
* setTimeout(() => {
* // Send a response to the request
* connection.mockRespond(response);
* });
* });
*
* http.get('people.json').observer({
* next: res => {
* // Response came from mock backend
* console.log('first person', res.json()[0].name);
* }
* });
* ```
*/
export const HTTP_PROVIDERS = [
// TODO(pascal): use factory type annotations once supported in DI
// issue: https://github.com/angular/angular/issues/3183
provide(Http, {
useFactory: (xhrBackend, requestOptions) => new Http(xhrBackend, requestOptions),
deps: [XHRBackend, RequestOptions]
}),
BrowserXhr,
provide(RequestOptions, { useClass: BaseRequestOptions }),
provide(ResponseOptions, { useClass: BaseResponseOptions }),
XHRBackend
];
/**
* @deprecated
*/
export const HTTP_BINDINGS = HTTP_PROVIDERS;
/**
* Provides a basic set of providers to use the {@link Jsonp} service in any application.
*
* The `JSONP_PROVIDERS` should be included either in a component's injector,
* or in the root injector when bootstrapping an application.
*
* ### Example ([live demo](http://plnkr.co/edit/vmeN4F?p=preview))
*
* ```
* import {Component, NgFor, View} from 'angular2/angular2';
* import {JSONP_PROVIDERS, Jsonp} from 'angular2/http';
*
* @Component({
* selector: 'app',
* providers: [JSONP_PROVIDERS],
* template: `
* <div>
* <h1>People</h1>
* <ul>
* <li *ng-for="#person of people">
* {{person.name}}
* </li>
* </ul>
* </div>
* `,
* directives: [NgFor]
* })
* export class App {
* people: Array<Object>;
* constructor(jsonp:Jsonp) {
* jsonp.request('people.json').subscribe(res => {
* this.people = res.json();
* })
* }
* }
* ```
*
* The primary public API included in `JSONP_PROVIDERS` is the {@link Jsonp} class.
* However, other providers required by `Jsonp` are included,
* which may be beneficial to override in certain cases.
*
* The providers included in `JSONP_PROVIDERS` include:
* * {@link Jsonp}
* * {@link JSONPBackend}
* * `BrowserJsonp` - Private factory
* * {@link RequestOptions} - Bound to {@link BaseRequestOptions} class
* * {@link ResponseOptions} - Bound to {@link BaseResponseOptions} class
*
* There may be cases where it makes sense to extend the base request options,
* such as to add a search string to be appended to all URLs.
* To accomplish this, a new provider for {@link RequestOptions} should
* be added in the same injector as `JSONP_PROVIDERS`.
*
* ### Example ([live demo](http://plnkr.co/edit/TFug7x?p=preview))
*
* ```
* import {provide, bootstrap} from 'angular2/angular2';
* import {JSONP_PROVIDERS, BaseRequestOptions, RequestOptions} from 'angular2/http';
*
* class MyOptions extends BaseRequestOptions {
* search: string = 'coreTeam=true';
* }
*
* bootstrap(App, [JSONP_PROVIDERS, provide(RequestOptions, {useClass: MyOptions})])
* .catch(err => console.error(err));
* ```
*
* Likewise, to use a mock backend for unit tests, the {@link JSONPBackend}
* provider should be bound to {@link MockBackend}.
*
* ### Example ([live demo](http://plnkr.co/edit/HDqZWL?p=preview))
*
* ```
* import {provide, Injector} from 'angular2/angular2';
* import {JSONP_PROVIDERS, Jsonp, Response, JSONPBackend, MockBackend} from 'angular2/http';
*
* var people = [{name: 'Jeff'}, {name: 'Tobias'}];
* var injector = Injector.resolveAndCreate([
* JSONP_PROVIDERS,
* MockBackend,
* provide(JSONPBackend, {useExisting: MockBackend})
* ]);
* var jsonp = injector.get(Jsonp);
* var backend = injector.get(MockBackend);
*
* // Listen for any new requests
* backend.connections.observer({
* next: connection => {
* var response = new Response({body: people});
* setTimeout(() => {
* // Send a response to the request
* connection.mockRespond(response);
* });
* });
* jsonp.get('people.json').observer({
* next: res => {
* // Response came from mock backend
* console.log('first person', res.json()[0].name);
* }
* });
* ```
*/
export const JSONP_PROVIDERS = [
// TODO(pascal): use factory type annotations once supported in DI
// issue: https://github.com/angular/angular/issues/3183
provide(Jsonp, {
useFactory: (jsonpBackend, requestOptions) => new Jsonp(jsonpBackend, requestOptions),
deps: [JSONPBackend, RequestOptions]
}),
BrowserJsonp,
provide(RequestOptions, { useClass: BaseRequestOptions }),
provide(ResponseOptions, { useClass: BaseResponseOptions }),
provide(JSONPBackend, { useClass: JSONPBackend_ })
];
/**
* @deprecated
*/
export const JSON_BINDINGS = JSONP_PROVIDERS;
//# sourceMappingURL=http.js.map
+7
View File
@@ -0,0 +1,7 @@
/**
* @module
* @description
* Defines interfaces to be implemented by directives when they need to hook into the change
* detection mechanism.
*/
//# sourceMappingURL=lifecycle_hooks.js.map
+5
View File
@@ -0,0 +1,5 @@
export * from './src/mock/mock_location_strategy';
export { LocationStrategy } from './src/router/location_strategy';
export { MockViewResolver } from 'angular2/src/mock/view_resolver_mock';
export { MockXHR } from 'angular2/src/compiler/xhr_mock';
//# sourceMappingURL=mock.js.map
+17
View File
@@ -0,0 +1,17 @@
{
"name": "angular2",
"version": "<%= packageJson.version %>",
"description": "Angular 2 - a web framework for modern web apps",
"homepage": "<%= packageJson.homepage %>",
"bugs": "<%= packageJson.bugs %>",
"contributors": <%= JSON.stringify(packageJson.contributors) %>,
"license": "<%= packageJson.license %>",
"repository": <%= JSON.stringify(packageJson.repository) %>,
"dependencies": {
"reflect-metadata": "<%= packageJson.dependencies['reflect-metadata'] %>",
"@reactivex/rxjs": "<%= packageJson.dependencies['@reactivex/rxjs'] %>",
"zone.js": "<%= packageJson.dependencies['zone.js'] %>"
},
"devDependencies": <%= JSON.stringify(packageJson.defaultDevDependencies) %>,
"typings": "./angular2.d.ts"
}
+108
View File
@@ -0,0 +1,108 @@
export { BROWSER_PROVIDERS, ELEMENT_PROBE_BINDINGS, ELEMENT_PROBE_PROVIDERS, inspectNativeElement, BrowserDomAdapter, By, Title, DOCUMENT } from 'angular2/src/platform/browser_common';
import { isPresent, CONST_EXPR } from 'angular2/src/facade/lang';
import { BROWSER_PROVIDERS, BROWSER_APP_COMMON_PROVIDERS, initDomAdapter } from 'angular2/src/platform/browser_common';
import { COMPILER_PROVIDERS } from 'angular2/compiler';
import { platform, reflector } from 'angular2/core';
import { ReflectionCapabilities } from 'angular2/src/core/reflection/reflection_capabilities';
import { XHRImpl } from "angular2/src/platform/browser/xhr_impl";
import { XHR } from 'angular2/compiler';
import { Provider } from 'angular2/src/core/di';
/**
* An array of providers that should be passed into `application()` when bootstrapping a component.
*/
export const BROWSER_APP_PROVIDERS = CONST_EXPR([
BROWSER_APP_COMMON_PROVIDERS,
COMPILER_PROVIDERS,
new Provider(XHR, { useClass: XHRImpl }),
]);
/**
* Bootstrapping for Angular applications.
*
* You instantiate an Angular application by explicitly specifying a component to use
* as the root component for your application via the `bootstrap()` method.
*
* ## Simple Example
*
* Assuming this `index.html`:
*
* ```html
* <html>
* <!-- load Angular script tags here. -->
* <body>
* <my-app>loading...</my-app>
* </body>
* </html>
* ```
*
* An application is bootstrapped inside an existing browser DOM, typically `index.html`.
* Unlike Angular 1, Angular 2 does not compile/process providers in `index.html`. This is
* mainly for security reasons, as well as architectural changes in Angular 2. This means
* that `index.html` can safely be processed using server-side technologies such as
* providers. Bindings can thus use double-curly `{{ syntax }}` without collision from
* Angular 2 component double-curly `{{ syntax }}`.
*
* We can use this script code:
*
* ```
* @Component({
* selector: 'my-app',
* template: 'Hello {{ name }}!'
* })
* class MyApp {
* name:string;
*
* constructor() {
* this.name = 'World';
* }
* }
*
* main() {
* return bootstrap(MyApp);
* }
* ```
*
* When the app developer invokes `bootstrap()` with the root component `MyApp` as its
* argument, Angular performs the following tasks:
*
* 1. It uses the component's `selector` property to locate the DOM element which needs
* to be upgraded into the angular component.
* 2. It creates a new child injector (from the platform injector). Optionally, you can
* also override the injector configuration for an app by invoking `bootstrap` with the
* `componentInjectableBindings` argument.
* 3. It creates a new `Zone` and connects it to the angular application's change detection
* domain instance.
* 4. It creates an emulated or shadow DOM on the selected component's host element and loads the
* template into it.
* 5. It instantiates the specified component.
* 6. Finally, Angular performs change detection to apply the initial data providers for the
* application.
*
*
* ## Bootstrapping Multiple Applications
*
* When working within a browser window, there are many singleton resources: cookies, title,
* location, and others. Angular services that represent these resources must likewise be
* shared across all Angular applications that occupy the same browser window. For this
* reason, Angular creates exactly one global platform object which stores all shared
* services, and each angular application injector has the platform injector as its parent.
*
* Each application has its own private injector as well. When there are multiple
* applications on a page, Angular treats each application injector's services as private
* to that application.
*
* ## API
*
* - `appComponentType`: The root component which should act as the application. This is
* a reference to a `Type` which is annotated with `@Component(...)`.
* - `customProviders`: An additional set of providers that can be added to the
* app injector to override default injection behavior.
*
* Returns a `Promise` of {@link ComponentRef}.
*/
export function bootstrap(appComponentType, customProviders) {
reflector.reflectionCapabilities = new ReflectionCapabilities();
initDomAdapter();
let appProviders = isPresent(customProviders) ? [BROWSER_APP_PROVIDERS, customProviders] : BROWSER_APP_PROVIDERS;
return platform(BROWSER_PROVIDERS).application(appProviders).bootstrap(appComponentType);
}
//# sourceMappingURL=browser.js.map
+22
View File
@@ -0,0 +1,22 @@
export { BROWSER_PROVIDERS, ELEMENT_PROBE_BINDINGS, ELEMENT_PROBE_PROVIDERS, inspectNativeElement, BrowserDomAdapter, By, Title } from 'angular2/src/platform/browser_common';
import { isPresent } from 'angular2/src/facade/lang';
import { BROWSER_PROVIDERS, BROWSER_APP_COMMON_PROVIDERS, initDomAdapter } from 'angular2/src/platform/browser_common';
import { platform } from 'angular2/core';
/**
* An array of providers that should be passed into `application()` when bootstrapping a component
* when all templates
* have been precompiled offline.
*/
export const BROWSER_APP_PROVIDERS = BROWSER_APP_COMMON_PROVIDERS;
/**
* See {@link bootstrap} for more information.
*/
export function bootstrapStatic(appComponentType, customProviders, initReflector) {
initDomAdapter();
if (isPresent(initReflector)) {
initReflector();
}
let appProviders = isPresent(customProviders) ? [BROWSER_APP_PROVIDERS, customProviders] : BROWSER_APP_PROVIDERS;
return platform(BROWSER_PROVIDERS).application(appProviders).bootstrap(appComponentType);
}
//# sourceMappingURL=browser_static.js.map
+8
View File
@@ -0,0 +1,8 @@
/**
* This is a set of classes and objects that can be used both in the browser and on the server.
*/
export { DomRenderer } from 'angular2/src/platform/dom/dom_renderer';
export { DOCUMENT } from 'angular2/src/platform/dom/dom_tokens';
export { SharedStylesHost, DomSharedStylesHost } from 'angular2/src/platform/dom/shared_styles_host';
export { DomEventsPlugin } from 'angular2/src/platform/dom/events/dom_events';
//# sourceMappingURL=common_dom.js.map
+3
View File
@@ -0,0 +1,3 @@
// TODO: vsavkin add SERVER_PROVIDERS and SERVER_APP_PROVIDERS
export { Parse5DomAdapter } from 'angular2/src/platform/server/parse5_adapter';
//# sourceMappingURL=server.js.map
+2
View File
@@ -0,0 +1,2 @@
export { wtfCreateScope, wtfLeave, wtfStartTimeRange, wtfEndTimeRange } from './src/core/profile/profile';
//# sourceMappingURL=profile.js.map
+5
View File
@@ -0,0 +1,5 @@
/**
* @deprecated import angular2/render/dom instead
*/
export * from './src/core/render';
//# sourceMappingURL=render.js.map
+128
View File
@@ -0,0 +1,128 @@
/**
* @module
* @description
* Maps application URLs into application states, to support deep-linking and navigation.
*/
export { Router } from './src/router/router';
export { RouterOutlet } from './src/router/router_outlet';
export { RouterLink } from './src/router/router_link';
export { RouteParams, RouteData } from './src/router/instruction';
export { RouteRegistry } from './src/router/route_registry';
export { LocationStrategy, APP_BASE_HREF } from './src/router/location_strategy';
export { HashLocationStrategy } from './src/router/hash_location_strategy';
export { PathLocationStrategy } from './src/router/path_location_strategy';
export { Location } from './src/router/location';
export * from './src/router/route_config_decorator';
export * from './src/router/route_definition';
export { CanActivate } from './src/router/lifecycle_annotations';
export { Instruction, ComponentInstruction } from './src/router/instruction';
export { OpaqueToken } from 'angular2/angular2';
import { LocationStrategy } from './src/router/location_strategy';
import { PathLocationStrategy } from './src/router/path_location_strategy';
import { Router, RootRouter } from './src/router/router';
import { RouterOutlet } from './src/router/router_outlet';
import { RouterLink } from './src/router/router_link';
import { RouteRegistry } from './src/router/route_registry';
import { Location } from './src/router/location';
import { ApplicationRef, OpaqueToken, Provider } from 'angular2/angular2';
import { CONST_EXPR } from './src/facade/lang';
import { BaseException } from 'angular2/src/facade/exceptions';
/**
* Token used to bind the component with the top-level {@link RouteConfig}s for the
* application.
*
* ### Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
*
* ```
* import {Component} from 'angular2/angular2';
* import {
* ROUTER_DIRECTIVES,
* ROUTER_PROVIDERS,
* RouteConfig
* } from 'angular2/router';
*
* @Component({directives: [ROUTER_DIRECTIVES]})
* @RouteConfig([
* {...},
* ])
* class AppCmp {
* // ...
* }
*
* bootstrap(AppCmp, [ROUTER_PROVIDERS]);
* ```
*/
export const ROUTER_PRIMARY_COMPONENT = CONST_EXPR(new OpaqueToken('RouterPrimaryComponent'));
/**
* A list of directives. To use the router directives like {@link RouterOutlet} and
* {@link RouterLink}, add this to your `directives` array in the {@link View} decorator of your
* component.
*
* ### Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
*
* ```
* import {Component} from 'angular2/angular2';
* import {ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig} from 'angular2/router';
*
* @Component({directives: [ROUTER_DIRECTIVES]})
* @RouteConfig([
* {...},
* ])
* class AppCmp {
* // ...
* }
*
* bootstrap(AppCmp, [ROUTER_PROVIDERS]);
* ```
*/
export const ROUTER_DIRECTIVES = CONST_EXPR([RouterOutlet, RouterLink]);
/**
* A list of {@link Provider}s. To use the router, you must add this to your application.
*
* ### Example ([live demo](http://plnkr.co/edit/iRUP8B5OUbxCWQ3AcIDm))
*
* ```
* import {Component} from 'angular2/angular2';
* import {
* ROUTER_DIRECTIVES,
* ROUTER_PROVIDERS,
* RouteConfig
* } from 'angular2/router';
*
* @Component({directives: [ROUTER_DIRECTIVES]})
* @RouteConfig([
* {...},
* ])
* class AppCmp {
* // ...
* }
*
* bootstrap(AppCmp, [ROUTER_PROVIDERS]);
* ```
*/
export const ROUTER_PROVIDERS = CONST_EXPR([
RouteRegistry,
CONST_EXPR(new Provider(LocationStrategy, { useClass: PathLocationStrategy })),
Location,
CONST_EXPR(new Provider(Router, {
useFactory: routerFactory,
deps: CONST_EXPR([RouteRegistry, Location, ROUTER_PRIMARY_COMPONENT, ApplicationRef])
})),
CONST_EXPR(new Provider(ROUTER_PRIMARY_COMPONENT, { useFactory: routerPrimaryComponentFactory, deps: CONST_EXPR([ApplicationRef]) }))
]);
/**
* @deprecated
*/
export const ROUTER_BINDINGS = ROUTER_PROVIDERS;
function routerFactory(registry, location, primaryComponent, appRef) {
var rootRouter = new RootRouter(registry, location, primaryComponent);
appRef.registerDisposeListener(() => rootRouter.dispose());
return rootRouter;
}
function routerPrimaryComponentFactory(app) {
if (app.componentTypes.length == 0) {
throw new BaseException("Bootstrap at least one component before injecting Router.");
}
return app.componentTypes[0];
}
//# sourceMappingURL=router.js.map
+173
View File
@@ -0,0 +1,173 @@
import { DateWrapper, StringWrapper, RegExpWrapper, NumberWrapper, isPresent } from 'angular2/src/facade/lang';
import { Math } from 'angular2/src/facade/math';
import { camelCaseToDashCase } from 'angular2/src/platform/dom/util';
import { StringMapWrapper } from 'angular2/src/facade/collection';
import { DOM } from 'angular2/src/core/dom/dom_adapter';
export class Animation {
/**
* Stores the start time and starts the animation
* @param element
* @param data
* @param browserDetails
*/
constructor(element, data, browserDetails) {
this.element = element;
this.data = data;
this.browserDetails = browserDetails;
/** functions to be called upon completion */
this.callbacks = [];
/** functions for removing event listeners */
this.eventClearFunctions = [];
/** flag used to track whether or not the animation has finished */
this.completed = false;
this._stringPrefix = '';
this.startTime = DateWrapper.toMillis(DateWrapper.now());
this._stringPrefix = DOM.getAnimationPrefix();
this.setup();
this.wait(timestamp => this.start());
}
/** total amount of time that the animation should take including delay */
get totalTime() {
let delay = this.computedDelay != null ? this.computedDelay : 0;
let duration = this.computedDuration != null ? this.computedDuration : 0;
return delay + duration;
}
wait(callback) {
// Firefox requires 2 frames for some reason
this.browserDetails.raf(callback, 2);
}
/**
* Sets up the initial styles before the animation is started
*/
setup() {
if (this.data.fromStyles != null)
this.applyStyles(this.data.fromStyles);
if (this.data.duration != null)
this.applyStyles({ 'transitionDuration': this.data.duration.toString() + 'ms' });
if (this.data.delay != null)
this.applyStyles({ 'transitionDelay': this.data.delay.toString() + 'ms' });
}
/**
* After the initial setup has occurred, this method adds the animation styles
*/
start() {
this.addClasses(this.data.classesToAdd);
this.addClasses(this.data.animationClasses);
this.removeClasses(this.data.classesToRemove);
if (this.data.toStyles != null)
this.applyStyles(this.data.toStyles);
var computedStyles = DOM.getComputedStyle(this.element);
this.computedDelay =
Math.max(this.parseDurationString(computedStyles.getPropertyValue(this._stringPrefix + 'transition-delay')), this.parseDurationString(this.element.style.getPropertyValue(this._stringPrefix + 'transition-delay')));
this.computedDuration = Math.max(this.parseDurationString(computedStyles.getPropertyValue(this._stringPrefix + 'transition-duration')), this.parseDurationString(this.element.style.getPropertyValue(this._stringPrefix + 'transition-duration')));
this.addEvents();
}
/**
* Applies the provided styles to the element
* @param styles
*/
applyStyles(styles) {
StringMapWrapper.forEach(styles, (value, key) => {
var dashCaseKey = camelCaseToDashCase(key);
if (isPresent(DOM.getStyle(this.element, dashCaseKey))) {
DOM.setStyle(this.element, dashCaseKey, value.toString());
}
else {
DOM.setStyle(this.element, this._stringPrefix + dashCaseKey, value.toString());
}
});
}
/**
* Adds the provided classes to the element
* @param classes
*/
addClasses(classes) {
for (let i = 0, len = classes.length; i < len; i++)
DOM.addClass(this.element, classes[i]);
}
/**
* Removes the provided classes from the element
* @param classes
*/
removeClasses(classes) {
for (let i = 0, len = classes.length; i < len; i++)
DOM.removeClass(this.element, classes[i]);
}
/**
* Adds events to track when animations have finished
*/
addEvents() {
if (this.totalTime > 0) {
this.eventClearFunctions.push(DOM.onAndCancel(this.element, DOM.getTransitionEnd(), (event) => this.handleAnimationEvent(event)));
}
else {
this.handleAnimationCompleted();
}
}
handleAnimationEvent(event) {
let elapsedTime = Math.round(event.elapsedTime * 1000);
if (!this.browserDetails.elapsedTimeIncludesDelay)
elapsedTime += this.computedDelay;
event.stopPropagation();
if (elapsedTime >= this.totalTime)
this.handleAnimationCompleted();
}
/**
* Runs all animation callbacks and removes temporary classes
*/
handleAnimationCompleted() {
this.removeClasses(this.data.animationClasses);
this.callbacks.forEach(callback => callback());
this.callbacks = [];
this.eventClearFunctions.forEach(fn => fn());
this.eventClearFunctions = [];
this.completed = true;
}
/**
* Adds animation callbacks to be called upon completion
* @param callback
* @returns {Animation}
*/
onComplete(callback) {
if (this.completed) {
callback();
}
else {
this.callbacks.push(callback);
}
return this;
}
/**
* Converts the duration string to the number of milliseconds
* @param duration
* @returns {number}
*/
parseDurationString(duration) {
var maxValue = 0;
// duration must have at least 2 characters to be valid. (number + type)
if (duration == null || duration.length < 2) {
return maxValue;
}
else if (duration.substring(duration.length - 2) == 'ms') {
let value = NumberWrapper.parseInt(this.stripLetters(duration), 10);
if (value > maxValue)
maxValue = value;
}
else if (duration.substring(duration.length - 1) == 's') {
let ms = NumberWrapper.parseFloat(this.stripLetters(duration)) * 1000;
let value = Math.floor(ms);
if (value > maxValue)
maxValue = value;
}
return maxValue;
}
/**
* Strips the letters from the duration string
* @param str
* @returns {string}
*/
stripLetters(str) {
return StringWrapper.replaceAll(str, RegExpWrapper.create('[^0-9]+$', ''), '');
}
}
//# sourceMappingURL=animation.js.map

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