refactor(di): unified di injector and core injector

BREAKING CHANGES:

* InjectAsync and InjectLazy have been removed
* toAsyncFactory has been removed
This commit is contained in:
vsavkin
2015-06-26 15:59:18 -07:00
parent b688dee4c8
commit 22d3943831
49 changed files with 1211 additions and 1669 deletions

View File

@ -1,6 +1,5 @@
library angular2.core.decorators;
export '../annotations_impl/annotations.dart';
export '../annotations_impl/visibility.dart';
export '../annotations_impl/view.dart';
export '../annotations_impl/di.dart';

View File

@ -5,12 +5,6 @@ import {
DirectiveArgs
} from './annotations';
import {ViewAnnotation, ViewArgs} from './view';
import {
SelfAnnotation,
ParentAnnotation,
AncestorAnnotation,
UnboundedAnnotation
} from './visibility';
import {AttributeAnnotation, QueryAnnotation} from './di';
import {makeDecorator, makeParamDecorator, TypeDecorator, Class} from '../../util/decorators';
import {Type} from 'angular2/src/facade/lang';
@ -46,12 +40,6 @@ export var Directive = <Directive>makeDecorator(DirectiveAnnotation);
/* from view */
export var View = <View>makeDecorator(ViewAnnotation, (fn: any) => fn.View = View);
/* from visibility */
export var Self = makeParamDecorator(SelfAnnotation);
export var Parent = makeParamDecorator(ParentAnnotation);
export var Ancestor = makeParamDecorator(AncestorAnnotation);
export var Unbounded = makeParamDecorator(UnboundedAnnotation);
/* from di */
export var Attribute = makeParamDecorator(AttributeAnnotation);
export var Query = makeParamDecorator(QueryAnnotation);

View File

@ -1,3 +0,0 @@
library angular2.core.annotations.visibility;
export "../annotations_impl/visibility.dart";

View File

@ -1,6 +0,0 @@
export {
Self as SelfAnnotation,
Ancestor as AncestorAnnotation,
Parent as ParentAnnotation,
Unbounded as UnboundedAnnotation
} from '../annotations_impl/visibility';

View File

@ -1,6 +1,6 @@
import {CONST, CONST_EXPR} from 'angular2/src/facade/lang';
import {List} from 'angular2/src/facade/collection';
import {Injectable} from 'angular2/src/di/annotations_impl';
import {Injectable, self} from 'angular2/src/di/annotations_impl';
import {DEFAULT} from 'angular2/change_detection';
// type StringMap = {[idx: string]: string};
@ -788,7 +788,7 @@ export class Directive extends Injectable {
selector, properties, events, host, lifecycle, hostInjector, exportAs,
compileChildren = true,
}: DirectiveArgs = {}) {
super();
super(self);
this.selector = selector;
this.properties = properties;
this.events = events;

View File

@ -1,213 +0,0 @@
import {CONST, CONST_EXPR, isBlank} from 'angular2/src/facade/lang';
import {DependencyAnnotation} from 'angular2/src/di/annotations_impl';
@CONST()
export class Visibility extends DependencyAnnotation {
constructor(public depth: number, public crossComponentBoundaries: boolean,
public _includeSelf: boolean) {
super();
}
get includeSelf(): boolean { return isBlank(this._includeSelf) ? false : this._includeSelf; }
toString() {
return `@Visibility(depth: ${this.depth}, crossComponentBoundaries: ${this.crossComponentBoundaries}, includeSelf: ${this.includeSelf}})`;
}
}
/**
* Specifies that an injector should retrieve a dependency from its element.
*
* ## Example
*
* Here is a simple directive that retrieves a dependency from its element.
*
* ```
* @Directive({
* selector: '[dependency]',
* properties: [
* 'id: dependency'
* ]
* })
* class Dependency {
* id:string;
* }
*
*
* @Directive({
* selector: '[my-directive]'
* })
* class Dependency {
* constructor(@Self() dependency:Dependency) {
* expect(dependency.id).toEqual(1);
* };
* }
* ```
*
* We use this with the following HTML template:
*
* ```
*<div dependency="1" my-directive></div>
* ```
*
* @exportedAs angular2/annotations
*/
@CONST()
export class Self extends Visibility {
constructor() { super(0, false, true); }
toString() { return `@Self()`; }
}
// make constants after switching to ts2dart
export var self = new Self();
/**
* Specifies that an injector should retrieve a dependency from the direct parent.
*
* ## Example
*
* Here is a simple directive that retrieves a dependency from its parent element.
*
* ```
* @Directive({
* selector: '[dependency]',
* properties: [
* 'id: dependency'
* ]
* })
* class Dependency {
* id:string;
* }
*
*
* @Directive({
* selector: '[my-directive]'
* })
* class Dependency {
* constructor(@Parent() dependency:Dependency) {
* expect(dependency.id).toEqual(1);
* };
* }
* ```
*
* We use this with the following HTML template:
*
* ```
* <div dependency="1">
* <div dependency="2" my-directive></div>
* </div>
* ```
* The `@Parent()` annotation in our constructor forces the injector to retrieve the dependency from
* the
* parent element (even thought the current element could resolve it): Angular injects
* `dependency=1`.
*
* @exportedAs angular2/annotations
*/
@CONST()
export class Parent extends Visibility {
constructor({self}: {self?: boolean} = {}) { super(1, false, self); }
toString() { return `@Parent(self: ${this.includeSelf}})`; }
}
/**
* Specifies that an injector should retrieve a dependency from any ancestor element within the same
* shadow boundary.
*
* An ancestor is any element between the parent element and the shadow root.
*
* Use {@link Unbounded} if you need to cross upper shadow boundaries.
*
* ## Example
*
* Here is a simple directive that retrieves a dependency from an ancestor element.
*
* ```
* @Directive({
* selector: '[dependency]',
* properties: [
* 'id: dependency'
* ]
* })
* class Dependency {
* id:string;
* }
*
*
* @Directive({
* selector: '[my-directive]'
* })
* class Dependency {
* constructor(@Ancestor() dependency:Dependency) {
* expect(dependency.id).toEqual(2);
* };
* }
* ```
*
* We use this with the following HTML template:
*
* ```
* <div dependency="1">
* <div dependency="2">
* <div>
* <div dependency="3" my-directive></div>
* </div>
* </div>
* </div>
* ```
*
* The `@Ancestor()` annotation in our constructor forces the injector to retrieve the dependency
* from the
* nearest ancestor element:
* - The current element `dependency="3"` is skipped because it is not an ancestor.
* - Next parent has no directives `<div>`
* - Next parent has the `Dependency` directive and so the dependency is satisfied.
*
* Angular injects `dependency=2`.
*
* @exportedAs angular2/annotations
*/
@CONST()
export class Ancestor extends Visibility {
constructor({self}: {self?: boolean} = {}) { super(999999, false, self); }
toString() { return `@Ancestor(self: ${this.includeSelf}})`; }
}
/**
* Specifies that an injector should retrieve a dependency from any ancestor element, crossing
* component boundaries.
*
* Use {@link Ancestor} to look for ancestors within the current shadow boundary only.
*
* ## Example
*
* Here is a simple directive that retrieves a dependency from an ancestor element.
*
* ```
* @Directive({
* selector: '[dependency]',
* properties: [
* 'id: dependency'
* ]
* })
* class Dependency {
* id:string;
* }
*
*
* @Directive({
* selector: '[my-directive]'
* })
* class Dependency {
* constructor(@Unbounded() dependency:Dependency) {
* expect(dependency.id).toEqual(2);
* };
* }
* ```
*
* @exportedAs angular2/annotations
*/
@CONST()
export class Unbounded extends Visibility {
constructor({self}: {self?: boolean} = {}) { super(999999, true, self); }
toString() { return `@Unbounded(self: ${this.includeSelf}})`; }
}

View File

@ -79,20 +79,19 @@ function _injectorBindings(appComponentType): List<Type | Binding | List<any>> {
.toValue(DOM.defaultDoc()),
bind(appComponentTypeToken).toValue(appComponentType),
bind(appComponentRefToken)
.toAsyncFactory(
.toFactory(
(dynamicComponentLoader, injector, testability, registry) => {
// TODO(rado): investigate whether to support bindings on root component.
return dynamicComponentLoader.loadAsRoot(appComponentType, null, injector)
.then((componentRef) => {
registry.registerApplication(componentRef.location.nativeElement, testability);
return componentRef;
});
},
[DynamicComponentLoader, Injector, Testability, TestabilityRegistry]),
bind(appComponentType).toFactory((ref) => ref.instance, [appComponentRefToken]),
bind(appComponentType)
.toFactory((p: Promise<any>) => p.then(ref => ref.instance), [appComponentRefToken]),
bind(LifeCycle)
.toFactory((exceptionHandler) => new LifeCycle(exceptionHandler, null, assertionsEnabled()),
[ExceptionHandler]),
@ -293,20 +292,19 @@ export function bootstrap(appComponentType: Type,
// index.html and main.js are possible.
var appInjector = _createAppInjector(appComponentType, componentInjectableBindings, zone);
var compRefToken: Promise<any> =
PromiseWrapper.wrap(() => appInjector.get(appComponentRefToken));
var tick = (componentRef) => {
var appChangeDetector = internalView(componentRef.hostView).changeDetector;
// retrieve life cycle: may have already been created if injected in root component
var lc = appInjector.get(LifeCycle);
lc.registerWith(zone, appChangeDetector);
lc.tick(); // the first tick that will bootstrap the app
PromiseWrapper.then(
appInjector.asyncGet(appComponentRefToken),
(componentRef) => {
var appChangeDetector = internalView(componentRef.hostView).changeDetector;
// retrieve life cycle: may have already been created if injected in root component
var lc = appInjector.get(LifeCycle);
lc.registerWith(zone, appChangeDetector);
lc.tick(); // the first tick that will bootstrap the app
bootstrapProcess.resolve(new ApplicationRef(componentRef, appComponentType, appInjector));
},
(err, stackTrace) => {bootstrapProcess.reject(err, stackTrace)});
bootstrapProcess.resolve(new ApplicationRef(componentRef, appComponentType, appInjector));
};
PromiseWrapper.then(compRefToken, tick,
(err, stackTrace) => {bootstrapProcess.reject(err, stackTrace)});
});
return bootstrapProcess.promise;

File diff suppressed because it is too large Load Diff