refactor(di): removed @Parent
BREAKING CHANGE The @Parent annotation has been removed. Use @Ancestor instead. @Parent was used to enforce a particular DOM structure (e.g., a pane component is a direct child of the tabs component). DI is not the right mechanism to do it. We should enforce it using schema instead.
This commit is contained in:
parent
a472eacc07
commit
6f4a39c337
|
@ -10,7 +10,6 @@ export {
|
||||||
InjectableMetadata,
|
InjectableMetadata,
|
||||||
VisibilityMetadata,
|
VisibilityMetadata,
|
||||||
SelfMetadata,
|
SelfMetadata,
|
||||||
ParentMetadata,
|
|
||||||
AncestorMetadata,
|
AncestorMetadata,
|
||||||
UnboundedMetadata,
|
UnboundedMetadata,
|
||||||
DependencyMetadata,
|
DependencyMetadata,
|
||||||
|
@ -24,12 +23,12 @@ export {forwardRef, resolveForwardRef, ForwardRefFn} from './src/di/forward_ref'
|
||||||
export {
|
export {
|
||||||
Injector,
|
Injector,
|
||||||
ProtoInjector,
|
ProtoInjector,
|
||||||
|
BindingWithVisibility,
|
||||||
DependencyProvider,
|
DependencyProvider,
|
||||||
PUBLIC_AND_PRIVATE,
|
PUBLIC_AND_PRIVATE,
|
||||||
PUBLIC,
|
PUBLIC,
|
||||||
PRIVATE,
|
PRIVATE,
|
||||||
undefinedValue
|
undefinedValue
|
||||||
|
|
||||||
} from './src/di/injector';
|
} from './src/di/injector';
|
||||||
export {Binding, BindingBuilder, ResolvedBinding, Dependency, bind} from './src/di/binding';
|
export {Binding, BindingBuilder, ResolvedBinding, Dependency, bind} from './src/di/binding';
|
||||||
export {Key, KeyRegistry, TypeLiteral} from './src/di/key';
|
export {Key, KeyRegistry, TypeLiteral} from './src/di/key';
|
||||||
|
|
|
@ -262,7 +262,6 @@ There are five kinds of visibilities:
|
||||||
|
|
||||||
* (no annotation): Inject dependent directives only if they are on the current element.
|
* (no annotation): Inject dependent directives only if they are on the current element.
|
||||||
* `@ancestor`: Inject a directive if it is at any element above the current element.
|
* `@ancestor`: Inject a directive if it is at any element above the current element.
|
||||||
* `@parent`: Inject a directive which is a direct parent of the current element.
|
|
||||||
* `@child`: Inject a list of direct children which match a given type. (Used with `Query`)
|
* `@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`)
|
* `@descendant`: Inject a list of any children which match a given type. (Used with `Query`)
|
||||||
|
|
||||||
|
@ -301,7 +300,7 @@ class FieldSet { |
|
||||||
class Field { |
|
class Field { |
|
||||||
constructor( |
|
constructor( |
|
||||||
@ancestor field:Form, |
|
@ancestor field:Form, |
|
||||||
@parent field:FieldSet, |
|
@ancestor field:FieldSet, |
|
||||||
) { ... } |
|
) { ... } |
|
||||||
} |
|
} |
|
||||||
|
|
|
|
||||||
|
@ -337,7 +336,7 @@ Shadow DOM provides an encapsulation for components, so as a general rule it doe
|
||||||
})
|
})
|
||||||
class Kid {
|
class Kid {
|
||||||
constructor(
|
constructor(
|
||||||
@Parent() dad:Dad,
|
@Ancestor() dad:Dad,
|
||||||
@Optional() grandpa:Grandpa
|
@Optional() grandpa:Grandpa
|
||||||
) {
|
) {
|
||||||
this.name = 'Billy';
|
this.name = 'Billy';
|
||||||
|
@ -354,7 +353,7 @@ class Kid {
|
||||||
directives: [Kid]
|
directives: [Kid]
|
||||||
})
|
})
|
||||||
class Dad {
|
class Dad {
|
||||||
constructor(@Parent() dad:Grandpa) {
|
constructor(@Ancestor() dad:Grandpa) {
|
||||||
this.name = 'Joe Jr';
|
this.name = 'Joe Jr';
|
||||||
this.dad = dad.name;
|
this.dad = dad.name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,8 +58,6 @@ import {DEFAULT} from 'angular2/change_detection';
|
||||||
* Shadow DOM root. Current element is not included in the resolution, therefore even if it could
|
* Shadow DOM root. Current element is not included in the resolution, therefore even if it could
|
||||||
* resolve it, it will
|
* resolve it, it will
|
||||||
* be ignored.
|
* be ignored.
|
||||||
* - `@Parent() directive:DirectiveType`: any directive that matches the type on a direct parent
|
|
||||||
* element only.
|
|
||||||
* - `@Query(DirectiveType) query:QueryList<DirectiveType>`: A live collection of direct child
|
* - `@Query(DirectiveType) query:QueryList<DirectiveType>`: A live collection of direct child
|
||||||
* directives.
|
* directives.
|
||||||
* - `@QueryDescendants(DirectiveType) query:QueryList<DirectiveType>`: A live collection of any
|
* - `@QueryDescendants(DirectiveType) query:QueryList<DirectiveType>`: A live collection of any
|
||||||
|
@ -163,27 +161,6 @@ import {DEFAULT} from 'angular2/change_detection';
|
||||||
* This directive would be instantiated with `Dependency` declared at the same element, in this case
|
* This directive would be instantiated with `Dependency` declared at the same element, in this case
|
||||||
* `dependency="3"`.
|
* `dependency="3"`.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* ### Injecting a directive from a direct parent element
|
|
||||||
*
|
|
||||||
* Directives can inject other directives declared on a direct parent element. By definition, a
|
|
||||||
* directive with a
|
|
||||||
* `@Parent` annotation does not attempt to resolve dependencies for the current element, even if
|
|
||||||
* this would satisfy
|
|
||||||
* the dependency.
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* @Directive({ selector: '[my-directive]' })
|
|
||||||
* class MyDirective {
|
|
||||||
* constructor(@Parent() dependency: Dependency) {
|
|
||||||
* expect(dependency.id).toEqual(2);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
* This directive would be instantiated with `Dependency` declared at the parent element, in this
|
|
||||||
* case `dependency="2"`.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* ### Injecting a directive from any ancestor elements
|
* ### Injecting a directive from any ancestor elements
|
||||||
*
|
*
|
||||||
* Directives can inject other directives declared on any ancestor element (in the current Shadow
|
* Directives can inject other directives declared on any ancestor element (in the current Shadow
|
||||||
|
@ -201,8 +178,8 @@ import {DEFAULT} from 'angular2/change_detection';
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* Unlike the `@Parent` which only checks the parent, `@Ancestor` checks the parent, as well as its
|
* `@Ancestor` checks the parent, as well as its parents recursively. If `dependency="2"` didn't
|
||||||
* parents recursively. If `dependency="2"` didn't exist on the direct parent, this injection would
|
* exist on the direct parent, this injection would
|
||||||
* have returned
|
* have returned
|
||||||
* `dependency="1"`.
|
* `dependency="1"`.
|
||||||
*
|
*
|
||||||
|
|
|
@ -397,7 +397,7 @@ export class ProtoElementInjector {
|
||||||
public directiveVariableBindings: Map<string, number>) {
|
public directiveVariableBindings: Map<string, number>) {
|
||||||
var length = bwv.length;
|
var length = bwv.length;
|
||||||
|
|
||||||
this.protoInjector = new ProtoInjector(bwv, distanceToParent);
|
this.protoInjector = new ProtoInjector(bwv);
|
||||||
|
|
||||||
this.eventEmitterAccessors = ListWrapper.createFixedSize(length);
|
this.eventEmitterAccessors = ListWrapper.createFixedSize(length);
|
||||||
this.hostActionAccessors = ListWrapper.createFixedSize(length);
|
this.hostActionAccessors = ListWrapper.createFixedSize(length);
|
||||||
|
|
|
@ -31,13 +31,6 @@ class Self extends SelfMetadata {
|
||||||
const Self(): super();
|
const Self(): super();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link ParentMetadata}.
|
|
||||||
*/
|
|
||||||
class Parent extends ParentMetadata {
|
|
||||||
const Parent({bool self}): super(self:self);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link AncestorMetadata}.
|
* {@link AncestorMetadata}.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,7 +4,6 @@ import {
|
||||||
InjectableMetadata,
|
InjectableMetadata,
|
||||||
SelfMetadata,
|
SelfMetadata,
|
||||||
VisibilityMetadata,
|
VisibilityMetadata,
|
||||||
ParentMetadata,
|
|
||||||
AncestorMetadata,
|
AncestorMetadata,
|
||||||
UnboundedMetadata
|
UnboundedMetadata
|
||||||
} from './metadata';
|
} from './metadata';
|
||||||
|
@ -42,14 +41,6 @@ export interface SelfFactory {
|
||||||
new (): SelfMetadata;
|
new (): SelfMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory for creating {@link ParentMetadata}.
|
|
||||||
*/
|
|
||||||
export interface ParentFactory {
|
|
||||||
(visibility?: {self: boolean}): any;
|
|
||||||
new (visibility?: {self: boolean}): ParentMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory for creating {@link AncestorMetadata}.
|
* Factory for creating {@link AncestorMetadata}.
|
||||||
*/
|
*/
|
||||||
|
@ -86,11 +77,6 @@ export var Injectable: InjectableFactory = <InjectableFactory>makeDecorator(Inje
|
||||||
*/
|
*/
|
||||||
export var Self: SelfFactory = makeParamDecorator(SelfMetadata);
|
export var Self: SelfFactory = makeParamDecorator(SelfMetadata);
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory for creating {@link ParentMetadata}.
|
|
||||||
*/
|
|
||||||
export var Parent: ParentFactory = makeParamDecorator(ParentMetadata);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory for creating {@link AncestorMetadata}.
|
* Factory for creating {@link AncestorMetadata}.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
import {FunctionWrapper, Type, isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
|
import {FunctionWrapper, Type, isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
|
||||||
import {Key} from './key';
|
import {Key} from './key';
|
||||||
import {resolveForwardRef} from './forward_ref';
|
import {resolveForwardRef} from './forward_ref';
|
||||||
import {VisibilityMetadata, DEFAULT_VISIBILITY} from './metadata';
|
import {VisibilityMetadata, DEFAULT_VISIBILITY, SelfMetadata, AncestorMetadata} from './metadata';
|
||||||
|
|
||||||
const _constructing = CONST_EXPR(new Object());
|
const _constructing = CONST_EXPR(new Object());
|
||||||
const _notFound = CONST_EXPR(new Object());
|
const _notFound = CONST_EXPR(new Object());
|
||||||
|
@ -175,7 +175,7 @@ export class ProtoInjectorDynamicStrategy implements ProtoInjectorStrategy {
|
||||||
export class ProtoInjector {
|
export class ProtoInjector {
|
||||||
_strategy: ProtoInjectorStrategy;
|
_strategy: ProtoInjectorStrategy;
|
||||||
|
|
||||||
constructor(bwv: BindingWithVisibility[], public distanceToParent: number) {
|
constructor(bwv: BindingWithVisibility[]) {
|
||||||
this._strategy = bwv.length > _MAX_CONSTRUCTION_COUNTER ?
|
this._strategy = bwv.length > _MAX_CONSTRUCTION_COUNTER ?
|
||||||
new ProtoInjectorDynamicStrategy(this, bwv) :
|
new ProtoInjectorDynamicStrategy(this, bwv) :
|
||||||
new ProtoInjectorInlineStrategy(this, bwv);
|
new ProtoInjectorInlineStrategy(this, bwv);
|
||||||
|
@ -459,7 +459,7 @@ export class Injector {
|
||||||
static fromResolvedBindings(bindings: List<ResolvedBinding>,
|
static fromResolvedBindings(bindings: List<ResolvedBinding>,
|
||||||
depProvider: DependencyProvider = null): Injector {
|
depProvider: DependencyProvider = null): Injector {
|
||||||
var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC));
|
var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC));
|
||||||
var proto = new ProtoInjector(bd, 0);
|
var proto = new ProtoInjector(bd);
|
||||||
var inj = new Injector(proto, null, depProvider);
|
var inj = new Injector(proto, null, depProvider);
|
||||||
return inj;
|
return inj;
|
||||||
}
|
}
|
||||||
|
@ -542,7 +542,7 @@ export class Injector {
|
||||||
createChildFromResolved(bindings: List<ResolvedBinding>,
|
createChildFromResolved(bindings: List<ResolvedBinding>,
|
||||||
depProvider: DependencyProvider = null): Injector {
|
depProvider: DependencyProvider = null): Injector {
|
||||||
var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC));
|
var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC));
|
||||||
var proto = new ProtoInjector(bd, 1);
|
var proto = new ProtoInjector(bd);
|
||||||
var inj = new Injector(proto, null, depProvider);
|
var inj = new Injector(proto, null, depProvider);
|
||||||
inj._parent = this;
|
inj._parent = this;
|
||||||
return inj;
|
return inj;
|
||||||
|
@ -678,49 +678,79 @@ export class Injector {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
var inj = this;
|
if (depVisibility instanceof SelfMetadata) {
|
||||||
var lastInjector = false;
|
return this._getByKeySelf(key, optional, bindingVisibility);
|
||||||
var depth = depVisibility.depth;
|
|
||||||
|
|
||||||
if (!depVisibility.includeSelf) {
|
} else if (depVisibility instanceof AncestorMetadata) {
|
||||||
depth -= inj._proto.distanceToParent;
|
return this._getByKeyAncestor(key, optional, bindingVisibility, depVisibility.includeSelf);
|
||||||
|
|
||||||
if (inj._isBoundary) {
|
|
||||||
if (depVisibility.crossBoundaries) {
|
|
||||||
bindingVisibility = PUBLIC_AND_PRIVATE;
|
|
||||||
} else {
|
} else {
|
||||||
bindingVisibility = PRIVATE;
|
return this._getByKeyUnbounded(key, optional, bindingVisibility, depVisibility.includeSelf);
|
||||||
lastInjector = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inj = inj._parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (inj != null && depth >= 0) {
|
|
||||||
var obj = inj._strategy.getObjByKeyId(key.id, bindingVisibility);
|
|
||||||
if (obj !== undefinedValue) return obj;
|
|
||||||
|
|
||||||
depth -= inj._proto.distanceToParent;
|
|
||||||
|
|
||||||
if (lastInjector) break;
|
|
||||||
|
|
||||||
if (inj._isBoundary) {
|
|
||||||
if (depVisibility.crossBoundaries) {
|
|
||||||
bindingVisibility = PUBLIC_AND_PRIVATE;
|
|
||||||
} else {
|
|
||||||
bindingVisibility = PRIVATE;
|
|
||||||
lastInjector = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inj = inj._parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
_throwOrNull(key: Key, optional: boolean): any {
|
||||||
if (optional) {
|
if (optional) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
throw new NoBindingError(key);
|
throw new NoBindingError(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getByKeySelf(key: Key, optional: boolean, bindingVisibility: number): any {
|
||||||
|
var obj = this._strategy.getObjByKeyId(key.id, bindingVisibility);
|
||||||
|
return (obj !== undefinedValue) ? obj : this._throwOrNull(key, optional);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getByKeyAncestor(key: Key, optional: boolean, bindingVisibility: number,
|
||||||
|
includeSelf: boolean): any {
|
||||||
|
var inj = this;
|
||||||
|
|
||||||
|
if (!includeSelf) {
|
||||||
|
if (inj._isBoundary) {
|
||||||
|
return this._getPrivateDependency(key, optional, inj);
|
||||||
|
} else {
|
||||||
|
inj = inj._parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (inj != null) {
|
||||||
|
var obj = inj._strategy.getObjByKeyId(key.id, bindingVisibility);
|
||||||
|
if (obj !== undefinedValue) return obj;
|
||||||
|
|
||||||
|
if (isPresent(inj._parent) && inj._isBoundary) {
|
||||||
|
return this._getPrivateDependency(key, optional, inj);
|
||||||
|
} else {
|
||||||
|
inj = inj._parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._throwOrNull(key, optional);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getPrivateDependency(key: Key, optional: boolean, inj: Injector): any {
|
||||||
|
var obj = inj._parent._strategy.getObjByKeyId(key.id, PRIVATE);
|
||||||
|
return (obj !== undefinedValue) ? obj : this._throwOrNull(key, optional);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getByKeyUnbounded(key: Key, optional: boolean, bindingVisibility: number,
|
||||||
|
includeSelf: boolean): any {
|
||||||
|
var inj = this;
|
||||||
|
if (!includeSelf) {
|
||||||
|
bindingVisibility = inj._isBoundary ? PUBLIC_AND_PRIVATE : PUBLIC;
|
||||||
|
inj = inj._parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (inj != null) {
|
||||||
|
var obj = inj._strategy.getObjByKeyId(key.id, bindingVisibility);
|
||||||
|
if (obj !== undefinedValue) return obj;
|
||||||
|
|
||||||
|
bindingVisibility = inj._isBoundary ? PUBLIC_AND_PRIVATE : PUBLIC;
|
||||||
|
inj = inj._parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._throwOrNull(key, optional);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var INJECTOR_KEY = Key.get(Injector);
|
var INJECTOR_KEY = Key.get(Injector);
|
||||||
|
|
|
@ -42,21 +42,21 @@ export class OptionalMetadata {
|
||||||
* For example:
|
* For example:
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* class Parent extends DependencyMetadata {}
|
* class Exclude extends DependencyMetadata {}
|
||||||
* class NotDependencyProperty {}
|
* class NotDependencyProperty {}
|
||||||
*
|
*
|
||||||
* class AComponent {
|
* class AComponent {
|
||||||
* constructor(@Parent @NotDependencyProperty aService:AService) {}
|
* constructor(@Exclude @NotDependencyProperty aService:AService) {}
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* will create the following dependency:
|
* will create the following dependency:
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* new Dependency(Key.get(AService), [new Parent()])
|
* new Dependency(Key.get(AService), [new Exclude()])
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* The framework can use `new Parent()` to handle the `aService` dependency
|
* The framework can use `new Exclude()` to handle the `aService` dependency
|
||||||
* in a specific way.
|
* in a specific way.
|
||||||
*/
|
*/
|
||||||
@CONST()
|
@CONST()
|
||||||
|
@ -85,17 +85,16 @@ export class InjectableMetadata {
|
||||||
/**
|
/**
|
||||||
* Specifies how injector should resolve a dependency.
|
* Specifies how injector should resolve a dependency.
|
||||||
*
|
*
|
||||||
* See {@link Self}, {@link Parent}, {@link Ancestor}, {@link Unbounded}.
|
* See {@link Self}, {@link Ancestor}, {@link Unbounded}.
|
||||||
*/
|
*/
|
||||||
@CONST()
|
@CONST()
|
||||||
export class VisibilityMetadata {
|
export class VisibilityMetadata {
|
||||||
constructor(public depth: number, public crossBoundaries: boolean, public _includeSelf: boolean) {
|
constructor(public crossBoundaries: boolean, public _includeSelf: boolean) {}
|
||||||
}
|
|
||||||
|
|
||||||
get includeSelf(): boolean { return isBlank(this._includeSelf) ? false : this._includeSelf; }
|
get includeSelf(): boolean { return isBlank(this._includeSelf) ? false : this._includeSelf; }
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return `@Visibility(depth: ${this.depth}, crossBoundaries: ${this.crossBoundaries}, includeSelf: ${this.includeSelf}})`;
|
return `@Visibility(crossBoundaries: ${this.crossBoundaries}, includeSelf: ${this.includeSelf}})`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,46 +118,10 @@ export class VisibilityMetadata {
|
||||||
*/
|
*/
|
||||||
@CONST()
|
@CONST()
|
||||||
export class SelfMetadata extends VisibilityMetadata {
|
export class SelfMetadata extends VisibilityMetadata {
|
||||||
constructor() { super(0, false, true); }
|
constructor() { super(false, true); }
|
||||||
toString(): string { return `@Self()`; }
|
toString(): string { return `@Self()`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies that an injector should retrieve a dependency from the direct parent.
|
|
||||||
*
|
|
||||||
* ## Example
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* class Dependency {
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* class NeedsDependency {
|
|
||||||
* constructor(public @Parent() dependency:Dependency) {}
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* var parent = Injector.resolveAndCreate([
|
|
||||||
* bind(Dependency).toClass(ParentDependency)
|
|
||||||
* ]);
|
|
||||||
* var child = parent.resolveAndCreateChild([NeedsDependency, Depedency]);
|
|
||||||
* var nd = child.get(NeedsDependency);
|
|
||||||
* expect(nd.dependency).toBeAnInstanceOf(ParentDependency);
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* You can make an injector to retrive a dependency either from itself or its direct parent by
|
|
||||||
* setting self to true.
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* class NeedsDependency {
|
|
||||||
* constructor(public @Parent({self:true}) dependency:Dependency) {}
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
@CONST()
|
|
||||||
export class ParentMetadata extends VisibilityMetadata {
|
|
||||||
constructor({self}: {self?: boolean} = {}) { super(1, false, self); }
|
|
||||||
toString(): string { return `@Parent(self: ${this.includeSelf}})`; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies that an injector should retrieve a dependency from any ancestor from the same boundary.
|
* Specifies that an injector should retrieve a dependency from any ancestor from the same boundary.
|
||||||
*
|
*
|
||||||
|
@ -192,7 +155,7 @@ export class ParentMetadata extends VisibilityMetadata {
|
||||||
*/
|
*/
|
||||||
@CONST()
|
@CONST()
|
||||||
export class AncestorMetadata extends VisibilityMetadata {
|
export class AncestorMetadata extends VisibilityMetadata {
|
||||||
constructor({self}: {self?: boolean} = {}) { super(999999, false, self); }
|
constructor({self}: {self?: boolean} = {}) { super(false, self); }
|
||||||
toString(): string { return `@Ancestor(self: ${this.includeSelf}})`; }
|
toString(): string { return `@Ancestor(self: ${this.includeSelf}})`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +192,7 @@ export class AncestorMetadata extends VisibilityMetadata {
|
||||||
*/
|
*/
|
||||||
@CONST()
|
@CONST()
|
||||||
export class UnboundedMetadata extends VisibilityMetadata {
|
export class UnboundedMetadata extends VisibilityMetadata {
|
||||||
constructor({self}: {self?: boolean} = {}) { super(999999, true, self); }
|
constructor({self}: {self?: boolean} = {}) { super(true, self); }
|
||||||
toString(): string { return `@Unbounded(self: ${this.includeSelf}})`; }
|
toString(): string { return `@Unbounded(self: ${this.includeSelf}})`; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {Directive} from 'angular2/annotations';
|
import {Directive} from 'angular2/annotations';
|
||||||
import {Parent} from 'angular2/di';
|
import {Ancestor} from 'angular2/di';
|
||||||
import {ViewContainerRef, TemplateRef} from 'angular2/core';
|
import {ViewContainerRef, TemplateRef} from 'angular2/core';
|
||||||
import {isPresent, isBlank, normalizeBlank} from 'angular2/src/facade/lang';
|
import {isPresent, isBlank, normalizeBlank} from 'angular2/src/facade/lang';
|
||||||
import {ListWrapper, List, MapWrapper, Map} from 'angular2/src/facade/collection';
|
import {ListWrapper, List, MapWrapper, Map} from 'angular2/src/facade/collection';
|
||||||
|
@ -157,7 +157,7 @@ export class NgSwitchWhen {
|
||||||
_view: SwitchView;
|
_view: SwitchView;
|
||||||
|
|
||||||
constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef,
|
constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef,
|
||||||
@Parent() sswitch: NgSwitch) {
|
@Ancestor() sswitch: NgSwitch) {
|
||||||
// `_whenDefault` is used as a marker for a not yet initialized value
|
// `_whenDefault` is used as a marker for a not yet initialized value
|
||||||
this._value = _whenDefault;
|
this._value = _whenDefault;
|
||||||
this._switch = sswitch;
|
this._switch = sswitch;
|
||||||
|
@ -187,7 +187,7 @@ export class NgSwitchWhen {
|
||||||
@Directive({selector: '[ng-switch-default]'})
|
@Directive({selector: '[ng-switch-default]'})
|
||||||
export class NgSwitchDefault {
|
export class NgSwitchDefault {
|
||||||
constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef,
|
constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef,
|
||||||
@Parent() sswitch: NgSwitch) {
|
@Ancestor() sswitch: NgSwitch) {
|
||||||
sswitch._registerView(_whenDefault, new SwitchView(viewContainer, templateRef));
|
sswitch._registerView(_whenDefault, new SwitchView(viewContainer, templateRef));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ import {
|
||||||
Directive,
|
Directive,
|
||||||
LifecycleEvent
|
LifecycleEvent
|
||||||
} from 'angular2/annotations';
|
} from 'angular2/annotations';
|
||||||
import {bind, Injector, Binding, Optional, Inject, Injectable, Self, Parent, Ancestor, Unbounded, InjectMetadata, ParentMetadata} from 'angular2/di';
|
import {bind, Injector, Binding, Optional, Inject, Injectable, Self, Ancestor, Unbounded, InjectMetadata, AncestorMetadata} from 'angular2/di';
|
||||||
import {AppProtoView, AppView} from 'angular2/src/core/compiler/view';
|
import {AppProtoView, AppView} from 'angular2/src/core/compiler/view';
|
||||||
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
|
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
|
||||||
import {TemplateRef} from 'angular2/src/core/compiler/template_ref';
|
import {TemplateRef} from 'angular2/src/core/compiler/template_ref';
|
||||||
|
@ -102,18 +102,6 @@ class OptionallyNeedsDirective {
|
||||||
constructor(@Self() @Optional() dependency: SimpleDirective) { this.dependency = dependency; }
|
constructor(@Self() @Optional() dependency: SimpleDirective) { this.dependency = dependency; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
class NeedsDirectiveFromParent {
|
|
||||||
dependency: SimpleDirective;
|
|
||||||
constructor(@Parent() dependency: SimpleDirective) { this.dependency = dependency; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
class NeedsDirectiveFromParentOrSelf {
|
|
||||||
dependency: SimpleDirective;
|
|
||||||
constructor(@Parent({self: true}) dependency: SimpleDirective) { this.dependency = dependency; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class NeedsDirectiveFromAncestor {
|
class NeedsDirectiveFromAncestor {
|
||||||
dependency: SimpleDirective;
|
dependency: SimpleDirective;
|
||||||
|
@ -609,7 +597,7 @@ export function main() {
|
||||||
bind('injectable2')
|
bind('injectable2')
|
||||||
.toFactory(
|
.toFactory(
|
||||||
(val) => `${val}-injectable2`,
|
(val) => `${val}-injectable2`,
|
||||||
[[new InjectMetadata('injectable1'), new ParentMetadata()]])
|
[[new InjectMetadata('injectable1'), new AncestorMetadata()]])
|
||||||
]
|
]
|
||||||
}))]);
|
}))]);
|
||||||
expect(childInj.get('injectable2')).toEqual('injectable1-injectable2');
|
expect(childInj.get('injectable2')).toEqual('injectable1-injectable2');
|
||||||
|
@ -775,31 +763,6 @@ export function main() {
|
||||||
expect(inj.get(NeedsTemplateRef).templateRef).toEqual(templateRef);
|
expect(inj.get(NeedsTemplateRef).templateRef).toEqual(templateRef);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should get directives from parent", () => {
|
|
||||||
var child = parentChildInjectors(ListWrapper.concat([SimpleDirective], extraBindings),
|
|
||||||
[NeedsDirectiveFromParent]);
|
|
||||||
|
|
||||||
var d = child.get(NeedsDirectiveFromParent);
|
|
||||||
|
|
||||||
expect(d).toBeAnInstanceOf(NeedsDirectiveFromParent);
|
|
||||||
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not return parent's directives on self by default", () => {
|
|
||||||
expect(() => {
|
|
||||||
injector(ListWrapper.concat([SimpleDirective, NeedsDirectiveFromParent], extraBindings));
|
|
||||||
}).toThrowError(containsRegexp(`No provider for ${stringify(SimpleDirective) }`));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return parent's directives on self when explicitly specified", () => {
|
|
||||||
var inj = injector(ListWrapper.concat([SimpleDirective, NeedsDirectiveFromParentOrSelf], extraBindings));
|
|
||||||
|
|
||||||
var d = inj.get(NeedsDirectiveFromParentOrSelf);
|
|
||||||
|
|
||||||
expect(d).toBeAnInstanceOf(NeedsDirectiveFromParentOrSelf);
|
|
||||||
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should get directives from ancestor", () => {
|
it("should get directives from ancestor", () => {
|
||||||
var child = parentChildInjectors(ListWrapper.concat([SimpleDirective], extraBindings),
|
var child = parentChildInjectors(ListWrapper.concat([SimpleDirective], extraBindings),
|
||||||
[NeedsDirectiveFromAncestor]);
|
[NeedsDirectiveFromAncestor]);
|
||||||
|
@ -822,9 +785,9 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should throw when a dependency cannot be resolved", () => {
|
it("should throw when a dependency cannot be resolved", () => {
|
||||||
expect(() => injector(ListWrapper.concat([NeedsDirectiveFromParent], extraBindings)))
|
expect(() => injector(ListWrapper.concat([NeedsDirectiveFromAncestor], extraBindings)))
|
||||||
.toThrowError(containsRegexp(
|
.toThrowError(containsRegexp(
|
||||||
`No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirectiveFromParent) } -> ${stringify(SimpleDirective) })`));
|
`No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirectiveFromAncestor) } -> ${stringify(SimpleDirective) })`));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should inject null when an optional dependency cannot be resolved", () => {
|
it("should inject null when an optional dependency cannot be resolved", () => {
|
||||||
|
@ -857,10 +820,10 @@ export function main() {
|
||||||
var directiveBinding =
|
var directiveBinding =
|
||||||
DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component());
|
DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component());
|
||||||
var shadow = hostShadowInjectors(ListWrapper.concat([directiveBinding], extraBindings),
|
var shadow = hostShadowInjectors(ListWrapper.concat([directiveBinding], extraBindings),
|
||||||
[NeedsDirective]);
|
[NeedsDirectiveFromAncestor]);
|
||||||
|
|
||||||
var d = shadow.get(NeedsDirective);
|
var d = shadow.get(NeedsDirectiveFromAncestor);
|
||||||
expect(d).toBeAnInstanceOf(NeedsDirective);
|
expect(d).toBeAnInstanceOf(NeedsDirectiveFromAncestor);
|
||||||
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,6 @@ import {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
OpaqueToken,
|
OpaqueToken,
|
||||||
Inject,
|
Inject,
|
||||||
Parent,
|
|
||||||
Ancestor,
|
Ancestor,
|
||||||
Unbounded,
|
Unbounded,
|
||||||
UnboundedMetadata
|
UnboundedMetadata
|
||||||
|
@ -423,8 +422,8 @@ export function main() {
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
tcb.overrideView(MyComp, new viewAnn.View({
|
tcb.overrideView(MyComp, new viewAnn.View({
|
||||||
template:
|
template:
|
||||||
'<some-directive><toolbar><template toolbarpart var-toolbar-prop="toolbarProp">{{ctxProp}},{{toolbarProp}},<cmp-with-parent></cmp-with-parent></template></toolbar></some-directive>',
|
'<some-directive><toolbar><template toolbarpart var-toolbar-prop="toolbarProp">{{ctxProp}},{{toolbarProp}},<cmp-with-ancestor></cmp-with-ancestor></template></toolbar></some-directive>',
|
||||||
directives: [SomeDirective, CompWithParent, ToolbarComponent, ToolbarPart]
|
directives: [SomeDirective, CompWithAncestor, ToolbarComponent, ToolbarPart]
|
||||||
}))
|
}))
|
||||||
.createAsync(MyComp)
|
.createAsync(MyComp)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
|
@ -433,7 +432,7 @@ export function main() {
|
||||||
|
|
||||||
expect(rootTC.nativeElement)
|
expect(rootTC.nativeElement)
|
||||||
.toHaveText(
|
.toHaveText(
|
||||||
'TOOLBAR(From myComp,From toolbar,Component with an injected parent)');
|
'TOOLBAR(From myComp,From toolbar,Component with an injected ancestor)');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -663,25 +662,6 @@ export function main() {
|
||||||
})}));
|
})}));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a component that injects a @Parent',
|
|
||||||
inject(
|
|
||||||
[TestComponentBuilder, AsyncTestCompleter],
|
|
||||||
(tcb: TestComponentBuilder, async) => {
|
|
||||||
tcb.overrideView(MyComp, new viewAnn.View({
|
|
||||||
template:
|
|
||||||
'<some-directive><cmp-with-parent #child></cmp-with-parent></some-directive>',
|
|
||||||
directives: [SomeDirective, CompWithParent]
|
|
||||||
}))
|
|
||||||
|
|
||||||
.createAsync(MyComp)
|
|
||||||
.then((rootTC) => {
|
|
||||||
|
|
||||||
var childComponent = rootTC.componentViewChildren[0].getLocal('child');
|
|
||||||
expect(childComponent.myParent).toBeAnInstanceOf(SomeDirective);
|
|
||||||
|
|
||||||
async.done();
|
|
||||||
})}));
|
|
||||||
|
|
||||||
it('should create a component that injects an @Ancestor',
|
it('should create a component that injects an @Ancestor',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter],
|
inject([TestComponentBuilder, AsyncTestCompleter],
|
||||||
(tcb: TestComponentBuilder, async) => {
|
(tcb: TestComponentBuilder, async) => {
|
||||||
|
@ -1497,14 +1477,6 @@ class SomeDirective {
|
||||||
|
|
||||||
class SomeDirectiveMissingAnnotation {}
|
class SomeDirectiveMissingAnnotation {}
|
||||||
|
|
||||||
@Component({selector: 'cmp-with-parent'})
|
|
||||||
@View({template: '<p>Component with an injected parent</p>', directives: [SomeDirective]})
|
|
||||||
@Injectable()
|
|
||||||
class CompWithParent {
|
|
||||||
myParent: SomeDirective;
|
|
||||||
constructor(@Parent() someComp: SomeDirective) { this.myParent = someComp; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({selector: 'cmp-with-ancestor'})
|
@Component({selector: 'cmp-with-ancestor'})
|
||||||
@View({template: '<p>Component with an injected ancestor</p>', directives: [SomeDirective]})
|
@View({template: '<p>Component with an injected ancestor</p>', directives: [SomeDirective]})
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -1673,7 +1645,7 @@ class PrivateImpl extends PublicApi {
|
||||||
@Directive({selector: '[needs-public-api]'})
|
@Directive({selector: '[needs-public-api]'})
|
||||||
@Injectable()
|
@Injectable()
|
||||||
class NeedsPublicApi {
|
class NeedsPublicApi {
|
||||||
constructor(@Parent() api: PublicApi) { expect(api instanceof PrivateImpl).toBe(true); }
|
constructor(@Ancestor() api: PublicApi) { expect(api instanceof PrivateImpl).toBe(true); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Directive({selector: '[toolbarpart]'})
|
@Directive({selector: '[toolbarpart]'})
|
||||||
|
|
|
@ -10,19 +10,27 @@ import {
|
||||||
} from 'angular2/test_lib';
|
} from 'angular2/test_lib';
|
||||||
import {
|
import {
|
||||||
Injector,
|
Injector,
|
||||||
|
ProtoInjector,
|
||||||
bind,
|
bind,
|
||||||
ResolvedBinding,
|
ResolvedBinding,
|
||||||
Key,
|
Key,
|
||||||
forwardRef,
|
forwardRef,
|
||||||
DependencyMetadata,
|
DependencyMetadata,
|
||||||
Injectable,
|
Injectable,
|
||||||
InjectMetadata
|
InjectMetadata,
|
||||||
|
SelfMetadata,
|
||||||
|
AncestorMetadata,
|
||||||
|
UnboundedMetadata,
|
||||||
|
Optional,
|
||||||
|
Inject,
|
||||||
|
BindingWithVisibility,
|
||||||
|
PUBLIC,
|
||||||
|
PRIVATE,
|
||||||
|
PUBLIC_AND_PRIVATE
|
||||||
} from 'angular2/di';
|
} from 'angular2/di';
|
||||||
|
|
||||||
import {InjectorInlineStrategy, InjectorDynamicStrategy} from 'angular2/src/di/injector';
|
import {InjectorInlineStrategy, InjectorDynamicStrategy} from 'angular2/src/di/injector';
|
||||||
|
|
||||||
import {Optional, Inject} from 'angular2/src/di/decorators';
|
|
||||||
|
|
||||||
class CustomDependencyMetadata extends DependencyMetadata {}
|
class CustomDependencyMetadata extends DependencyMetadata {}
|
||||||
|
|
||||||
class Engine {}
|
class Engine {}
|
||||||
|
@ -362,13 +370,144 @@ export function main() {
|
||||||
expect(engineFromChild).toBeAnInstanceOf(TurboEngine);
|
expect(engineFromChild).toBeAnInstanceOf(TurboEngine);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should give access to direct parent", () => {
|
it("should give access to parent", () => {
|
||||||
var parent = Injector.resolveAndCreate([]);
|
var parent = Injector.resolveAndCreate([]);
|
||||||
var child = parent.resolveAndCreateChild([]);
|
var child = parent.resolveAndCreateChild([]);
|
||||||
expect(child.parent).toBe(parent);
|
expect(child.parent).toBe(parent);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe("depedency resolution", () => {
|
||||||
|
describe("@Self()", () => {
|
||||||
|
it("should return a dependency from self", () => {
|
||||||
|
var inj = Injector.resolveAndCreate(
|
||||||
|
[Engine, bind(Car).toFactory((e) => new Car(e), [[Engine, new SelfMetadata()]])]);
|
||||||
|
|
||||||
|
expect(inj.get(Car)).toBeAnInstanceOf(Car);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw when not requested binding on self", () => {
|
||||||
|
var parent = Injector.resolveAndCreate([Engine]);
|
||||||
|
var child = parent.resolveAndCreateChild(
|
||||||
|
[bind(Car).toFactory((e) => new Car(e), [[Engine, new SelfMetadata()]])]);
|
||||||
|
|
||||||
|
expect(() => child.get(Car))
|
||||||
|
.toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("@Ancestor()", () => {
|
||||||
|
it("should return a dependency from same boundary", () => {
|
||||||
|
var parent = Injector.resolveAndCreate([Engine]);
|
||||||
|
var child = parent.resolveAndCreateChild(
|
||||||
|
[bind(Car).toFactory((e) => new Car(e), [[Engine, new AncestorMetadata()]])]);
|
||||||
|
|
||||||
|
expect(child.get(Car)).toBeAnInstanceOf(Car);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return a private dependency declared at the boundary", () => {
|
||||||
|
var engine = Injector.resolve([Engine])[0];
|
||||||
|
var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PRIVATE)]);
|
||||||
|
var parent = new Injector(protoParent);
|
||||||
|
|
||||||
|
var child = Injector.resolveAndCreate(
|
||||||
|
[bind(Car).toFactory((e) => new Car(e), [[Engine, new AncestorMetadata()]])]);
|
||||||
|
|
||||||
|
child.internalStrategy.attach(parent, true); // boundary
|
||||||
|
|
||||||
|
expect(child.get(Car)).toBeAnInstanceOf(Car);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not return a public dependency declared at the boundary", () => {
|
||||||
|
var engine = Injector.resolve([Engine])[0];
|
||||||
|
var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PUBLIC)]);
|
||||||
|
var parent = new Injector(protoParent);
|
||||||
|
|
||||||
|
var child = Injector.resolveAndCreate(
|
||||||
|
[bind(Car).toFactory((e) => new Car(e), [[Engine, new AncestorMetadata()]])]);
|
||||||
|
|
||||||
|
child.internalStrategy.attach(parent, true); // boundary
|
||||||
|
|
||||||
|
expect(() => child.get(Car))
|
||||||
|
.toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return a dependency from self when explicitly specified", () => {
|
||||||
|
var parent = Injector.resolveAndCreate([Engine]);
|
||||||
|
var child = parent.resolveAndCreateChild([
|
||||||
|
bind(Engine)
|
||||||
|
.toClass(TurboEngine),
|
||||||
|
bind(Car)
|
||||||
|
.toFactory((e) => new Car(e), [[Engine, new AncestorMetadata({self: true})]])
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(child.get(Car).engine).toBeAnInstanceOf(TurboEngine);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("@Unboudned()", () => {
|
||||||
|
it("should return a private dependency declared at the boundary", () => {
|
||||||
|
var engine = Injector.resolve([Engine])[0];
|
||||||
|
var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PRIVATE)]);
|
||||||
|
var parent = new Injector(protoParent);
|
||||||
|
|
||||||
|
var child = Injector.resolveAndCreate([
|
||||||
|
bind(Engine)
|
||||||
|
.toClass(BrokenEngine),
|
||||||
|
bind(Car).toFactory((e) => new Car(e), [[Engine, new UnboundedMetadata()]])
|
||||||
|
]);
|
||||||
|
child.internalStrategy.attach(parent, true); // boundary
|
||||||
|
|
||||||
|
expect(child.get(Car)).toBeAnInstanceOf(Car);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return a public dependency declared at the boundary", () => {
|
||||||
|
var engine = Injector.resolve([Engine])[0];
|
||||||
|
var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PUBLIC)]);
|
||||||
|
var parent = new Injector(protoParent);
|
||||||
|
|
||||||
|
var child = Injector.resolveAndCreate([
|
||||||
|
bind(Engine)
|
||||||
|
.toClass(BrokenEngine),
|
||||||
|
bind(Car).toFactory((e) => new Car(e), [[Engine, new UnboundedMetadata()]])
|
||||||
|
]);
|
||||||
|
child.internalStrategy.attach(parent, true); // boundary
|
||||||
|
|
||||||
|
expect(child.get(Car)).toBeAnInstanceOf(Car);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not return a private dependency declared NOT at the boundary", () => {
|
||||||
|
var engine = Injector.resolve([Engine])[0];
|
||||||
|
var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PRIVATE)]);
|
||||||
|
var parent = new Injector(protoParent);
|
||||||
|
|
||||||
|
var child = Injector.resolveAndCreate([
|
||||||
|
bind(Engine)
|
||||||
|
.toClass(BrokenEngine),
|
||||||
|
bind(Car).toFactory((e) => new Car(e), [[Engine, new UnboundedMetadata()]])
|
||||||
|
]);
|
||||||
|
child.internalStrategy.attach(parent, false);
|
||||||
|
|
||||||
|
expect(() => child.get(Car))
|
||||||
|
.toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return a dependency from self when explicitly specified", () => {
|
||||||
|
var parent = Injector.resolveAndCreate([Engine]);
|
||||||
|
var child = parent.resolveAndCreateChild([
|
||||||
|
bind(Engine)
|
||||||
|
.toClass(TurboEngine),
|
||||||
|
bind(Car)
|
||||||
|
.toFactory((e) => new Car(e), [[Engine, new UnboundedMetadata({self: true})]])
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(child.get(Car).engine).toBeAnInstanceOf(TurboEngine);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('resolve', () => {
|
describe('resolve', () => {
|
||||||
it('should resolve and flatten', () => {
|
it('should resolve and flatten', () => {
|
||||||
var bindings = Injector.resolve([Engine, [BrokenEngine]]);
|
var bindings = Injector.resolve([Engine, [BrokenEngine]]);
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {
|
||||||
Component,
|
Component,
|
||||||
Directive,
|
Directive,
|
||||||
View,
|
View,
|
||||||
Parent,
|
Ancestor,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
DynamicComponentLoader,
|
DynamicComponentLoader,
|
||||||
ComponentRef,
|
ComponentRef,
|
||||||
|
@ -243,7 +243,7 @@ class MdDialogContainer {
|
||||||
*/
|
*/
|
||||||
@Directive({selector: 'md-dialog-content'})
|
@Directive({selector: 'md-dialog-content'})
|
||||||
class MdDialogContent {
|
class MdDialogContent {
|
||||||
constructor(@Parent() dialogContainer: MdDialogContainer, elementRef: ElementRef) {
|
constructor(@Ancestor() dialogContainer: MdDialogContainer, elementRef: ElementRef) {
|
||||||
dialogContainer.contentRef = elementRef;
|
dialogContainer.contentRef = elementRef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {Component, View, Parent, LifecycleEvent} from 'angular2/angular2';
|
import {Component, View, Ancestor, LifecycleEvent} from 'angular2/angular2';
|
||||||
|
|
||||||
import {ListWrapper} from 'angular2/src/facade/collection';
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||||
import {StringWrapper, isPresent, isString, NumberWrapper} from 'angular2/src/facade/lang';
|
import {StringWrapper, isPresent, isString, NumberWrapper} from 'angular2/src/facade/lang';
|
||||||
|
@ -238,7 +238,7 @@ export class MdGridTile {
|
||||||
|
|
||||||
isRegisteredWithGridList: boolean;
|
isRegisteredWithGridList: boolean;
|
||||||
|
|
||||||
constructor(@Parent() gridList: MdGridList) {
|
constructor(@Ancestor() gridList: MdGridList) {
|
||||||
this.gridList = gridList;
|
this.gridList = gridList;
|
||||||
|
|
||||||
// Tiles default to 1x1, but rowspan and colspan can be changed via binding.
|
// Tiles default to 1x1, but rowspan and colspan can be changed via binding.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {Directive, LifecycleEvent, Attribute, Parent} from 'angular2/angular2';
|
import {Directive, LifecycleEvent, Attribute, Ancestor} from 'angular2/angular2';
|
||||||
|
|
||||||
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
|
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ export class MdInput {
|
||||||
mdChange: EventEmitter;
|
mdChange: EventEmitter;
|
||||||
mdFocusChange: EventEmitter;
|
mdFocusChange: EventEmitter;
|
||||||
|
|
||||||
constructor(@Attribute('value') value: string, @Parent() container: MdInputContainer,
|
constructor(@Attribute('value') value: string, @Ancestor() container: MdInputContainer,
|
||||||
@Attribute('id') id: string) {
|
@Attribute('id') id: string) {
|
||||||
// TODO(jelbourn): Remove this when #1402 is done.
|
// TODO(jelbourn): Remove this when #1402 is done.
|
||||||
this.yes = true;
|
this.yes = true;
|
||||||
|
@ -111,7 +111,7 @@ export class MdInput {
|
||||||
export class MdTextarea extends MdInput {
|
export class MdTextarea extends MdInput {
|
||||||
constructor(
|
constructor(
|
||||||
@Attribute('value') value: string,
|
@Attribute('value') value: string,
|
||||||
@Parent() container: MdInputContainer,
|
@Ancestor() container: MdInputContainer,
|
||||||
@Attribute('id') id: string) {
|
@Attribute('id') id: string) {
|
||||||
super(value, container, id);
|
super(value, container, id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,4 @@
|
||||||
import {
|
import {Component, View, LifecycleEvent, Ancestor, Attribute, Optional} from 'angular2/angular2';
|
||||||
Component,
|
|
||||||
View,
|
|
||||||
LifecycleEvent,
|
|
||||||
Parent,
|
|
||||||
Ancestor,
|
|
||||||
Attribute,
|
|
||||||
Optional
|
|
||||||
} from 'angular2/angular2';
|
|
||||||
|
|
||||||
import {isPresent, StringWrapper, NumberWrapper} from 'angular2/src/facade/lang';
|
import {isPresent, StringWrapper, NumberWrapper} from 'angular2/src/facade/lang';
|
||||||
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
|
import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async';
|
||||||
|
@ -225,7 +217,7 @@ export class MdRadioButton {
|
||||||
|
|
||||||
role: string;
|
role: string;
|
||||||
|
|
||||||
constructor(@Optional() @Parent() radioGroup: MdRadioGroup, @Attribute('id') id: string,
|
constructor(@Optional() @Ancestor() radioGroup: MdRadioGroup, @Attribute('id') id: string,
|
||||||
@Attribute('tabindex') tabindex: string, radioDispatcher: MdRadioDispatcher) {
|
@Attribute('tabindex') tabindex: string, radioDispatcher: MdRadioDispatcher) {
|
||||||
// Assertions. Ideally these should be stripped out by the compiler.
|
// Assertions. Ideally these should be stripped out by the compiler.
|
||||||
// TODO(jelbourn): Assert that there's no name binding AND a parent radio group.
|
// TODO(jelbourn): Assert that there's no name binding AND a parent radio group.
|
||||||
|
|
Loading…
Reference in New Issue