feat(di): added hostInjector and viewInjector to the Directive annotation
This commit is contained in:
parent
7b511462af
commit
b066b8d15a
|
@ -8,7 +8,7 @@
|
|||
export * from './src/di/annotations';
|
||||
export * from './src/di/decorators';
|
||||
export * from './src/di/forward_ref';
|
||||
export {Injector} from './src/di/injector';
|
||||
export {resolveBindings, Injector} from './src/di/injector';
|
||||
export {Binding, ResolvedBinding, Dependency, bind} from './src/di/binding';
|
||||
export {Key, KeyRegistry, TypeLiteral} from './src/di/key';
|
||||
export {
|
||||
|
|
|
@ -660,6 +660,37 @@ export class Directive extends Injectable {
|
|||
//TODO(vsavkin): This would better fall under the Macro directive concept.
|
||||
compileChildren: boolean;
|
||||
|
||||
/**
|
||||
* Defines the set of injectable objects that are visible to a Directive and its light dom children.
|
||||
*
|
||||
* ## Simple Example
|
||||
*
|
||||
* Here is an example of a class that can be injected:
|
||||
*
|
||||
* ```
|
||||
* class Greeter {
|
||||
* greet(name:string) {
|
||||
* return 'Hello ' + name + '!';
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @Directive({
|
||||
* selector: 'greet',
|
||||
* hostInjector: [
|
||||
* Greeter
|
||||
* ]
|
||||
* })
|
||||
* class HelloWorld {
|
||||
* greeter:Greeter;
|
||||
*
|
||||
* constructor(greeter:Greeter) {
|
||||
* this.greeter = greeter;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
hostInjector:List;
|
||||
|
||||
@CONST()
|
||||
constructor({
|
||||
selector,
|
||||
|
@ -670,6 +701,7 @@ export class Directive extends Injectable {
|
|||
hostAttributes,
|
||||
hostActions,
|
||||
lifecycle,
|
||||
hostInjector,
|
||||
compileChildren = true,
|
||||
}:{
|
||||
selector:string,
|
||||
|
@ -680,6 +712,7 @@ export class Directive extends Injectable {
|
|||
hostAttributes: any,
|
||||
hostActions: any,
|
||||
lifecycle:List,
|
||||
hostInjector:List,
|
||||
compileChildren:boolean
|
||||
}={})
|
||||
{
|
||||
|
@ -693,6 +726,7 @@ export class Directive extends Injectable {
|
|||
this.hostActions = hostActions;
|
||||
this.lifecycle = lifecycle;
|
||||
this.compileChildren = compileChildren;
|
||||
this.hostInjector = hostInjector;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -845,6 +879,48 @@ export class Component extends Directive {
|
|||
*/
|
||||
appInjector:List;
|
||||
|
||||
/**
|
||||
* Defines the set of injectable objects that are visible to its view dom children.
|
||||
*
|
||||
* ## Simple Example
|
||||
*
|
||||
* Here is an example of a class that can be injected:
|
||||
*
|
||||
* ```
|
||||
* class Greeter {
|
||||
* greet(name:string) {
|
||||
* return 'Hello ' + name + '!';
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @Directive({
|
||||
* selector: 'needs-greeter'
|
||||
* })
|
||||
* class NeedsGreeter {
|
||||
* greeter:Greeter;
|
||||
*
|
||||
* constructor(greeter:Greeter) {
|
||||
* this.greeter = greeter;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @Component({
|
||||
* selector: 'greet',
|
||||
* viewInjector: [
|
||||
* Greeter
|
||||
* ]
|
||||
* })
|
||||
* @View({
|
||||
* template: `<needs-greeter></needs-greeter>`,
|
||||
* directives: [NeedsGreeter]
|
||||
* })
|
||||
* class HelloWorld {
|
||||
* }
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
viewInjector:List;
|
||||
|
||||
@CONST()
|
||||
constructor({
|
||||
selector,
|
||||
|
@ -856,6 +932,8 @@ export class Component extends Directive {
|
|||
hostActions,
|
||||
appInjector,
|
||||
lifecycle,
|
||||
hostInjector,
|
||||
viewInjector,
|
||||
changeDetection = DEFAULT,
|
||||
compileChildren = true
|
||||
}:{
|
||||
|
@ -868,6 +946,8 @@ export class Component extends Directive {
|
|||
hostActions:any,
|
||||
appInjector:List,
|
||||
lifecycle:List,
|
||||
hostInjector:List,
|
||||
viewInjector:List,
|
||||
changeDetection:string,
|
||||
compileChildren:boolean
|
||||
}={})
|
||||
|
@ -880,12 +960,14 @@ export class Component extends Directive {
|
|||
hostProperties: hostProperties,
|
||||
hostAttributes: hostAttributes,
|
||||
hostActions: hostActions,
|
||||
hostInjector: hostInjector,
|
||||
lifecycle: lifecycle,
|
||||
compileChildren: compileChildren
|
||||
});
|
||||
|
||||
this.changeDetection = changeDetection;
|
||||
this.appInjector = appInjector;
|
||||
this.viewInjector = viewInjector;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,66 @@
|
|||
import {CONST} from 'angular2/src/facade/lang';
|
||||
import {DependencyAnnotation} from 'angular2/src/di/annotations_impl';
|
||||
|
||||
export class Visibility extends DependencyAnnotation {
|
||||
depth: number;
|
||||
crossComponentBoundaries: boolean;
|
||||
|
||||
@CONST()
|
||||
constructor(depth:number, crossComponentBoundaries:boolean) {
|
||||
super();
|
||||
this.depth = depth;
|
||||
this.crossComponentBoundaries = crossComponentBoundaries;
|
||||
}
|
||||
|
||||
shouldIncludeSelf():boolean {
|
||||
return this.depth === 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
export class Self extends Visibility {
|
||||
@CONST()
|
||||
constructor() {
|
||||
super(0, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that an injector should retrieve a dependency from the direct parent.
|
||||
*
|
||||
|
@ -42,15 +102,15 @@ import {DependencyAnnotation} from 'angular2/src/di/annotations_impl';
|
|||
*
|
||||
* @exportedAs angular2/annotations
|
||||
*/
|
||||
export class Parent extends DependencyAnnotation {
|
||||
export class Parent extends Visibility {
|
||||
@CONST()
|
||||
constructor() {
|
||||
super();
|
||||
super(1, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that an injector should retrieve a dependency from any ancestor element.
|
||||
* 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 shadow root.
|
||||
*
|
||||
|
@ -103,9 +163,50 @@ export class Parent extends DependencyAnnotation {
|
|||
*
|
||||
* @exportedAs angular2/annotations
|
||||
*/
|
||||
export class Ancestor extends DependencyAnnotation {
|
||||
export class Ancestor extends Visibility {
|
||||
@CONST()
|
||||
constructor() {
|
||||
super();
|
||||
super(999999, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that an injector should retrieve a dependency from any ancestor element.
|
||||
*
|
||||
* An ancestor is any element between the parent element and shadow root.
|
||||
*
|
||||
*
|
||||
* ## 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
|
||||
*/
|
||||
export class Unbounded extends Visibility {
|
||||
@CONST()
|
||||
constructor() {
|
||||
super(999999, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import {isPresent, isBlank, Type, int, BaseException, stringify} from 'angular2/src/facade/lang';
|
||||
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import {Math} from 'angular2/src/facade/math';
|
||||
import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {Injector, Key, Dependency, bind, Binding, ResolvedBinding, NoBindingError,
|
||||
AbstractBindingError, CyclicDependencyError, resolveForwardRef} from 'angular2/di';
|
||||
import {Parent, Ancestor} from 'angular2/src/core/annotations_impl/visibility';
|
||||
AbstractBindingError, CyclicDependencyError, resolveForwardRef, resolveBindings} from 'angular2/di';
|
||||
import {Visibility, Self} from 'angular2/src/core/annotations_impl/visibility';
|
||||
import {Attribute, Query} from 'angular2/src/core/annotations_impl/di';
|
||||
import * as viewModule from './view';
|
||||
import * as avmModule from './view_manager';
|
||||
|
@ -20,8 +19,6 @@ import {DirectiveMetadata} from 'angular2/src/render/api';
|
|||
|
||||
var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10;
|
||||
|
||||
var MAX_DEPTH = Math.pow(2, 30) - 1;
|
||||
|
||||
var _undefined = new Object();
|
||||
|
||||
var _staticKeys;
|
||||
|
@ -177,14 +174,14 @@ export class TreeNode {
|
|||
}
|
||||
|
||||
export class DirectiveDependency extends Dependency {
|
||||
depth:int;
|
||||
visibility:Visibility;
|
||||
attributeName:string;
|
||||
queryDirective;
|
||||
|
||||
constructor(key:Key, asPromise:boolean, lazy:boolean, optional:boolean, properties:List,
|
||||
depth:int, attributeName:string, queryDirective) {
|
||||
visibility:Visibility, attributeName:string, queryDirective) {
|
||||
super(key, asPromise, lazy, optional, properties);
|
||||
this.depth = depth;
|
||||
this.visibility = visibility;;
|
||||
this.attributeName = attributeName;
|
||||
this.queryDirective = queryDirective;
|
||||
this._verify();
|
||||
|
@ -199,18 +196,17 @@ export class DirectiveDependency extends Dependency {
|
|||
}
|
||||
|
||||
static createFrom(d:Dependency):Dependency {
|
||||
return new DirectiveDependency(d.key, d.asPromise, d.lazy, d.optional,
|
||||
d.properties, DirectiveDependency._depth(d.properties),
|
||||
return new DirectiveDependency(d.key, d.asPromise, d.lazy, d.optional, d.properties,
|
||||
DirectiveDependency._visibility(d.properties),
|
||||
DirectiveDependency._attributeName(d.properties),
|
||||
DirectiveDependency._query(d.properties)
|
||||
);
|
||||
}
|
||||
|
||||
static _depth(properties):int {
|
||||
if (properties.length == 0) return 0;
|
||||
if (ListWrapper.any(properties, p => p instanceof Parent)) return 1;
|
||||
if (ListWrapper.any(properties, p => p instanceof Ancestor)) return MAX_DEPTH;
|
||||
return 0;
|
||||
static _visibility(properties):Visibility {
|
||||
if (properties.length == 0) return new Self();
|
||||
var p = ListWrapper.find(properties, p => p instanceof Visibility);
|
||||
return isPresent(p) ? p : new Self();
|
||||
}
|
||||
|
||||
static _attributeName(properties):string {
|
||||
|
@ -225,13 +221,18 @@ export class DirectiveDependency extends Dependency {
|
|||
}
|
||||
|
||||
export class DirectiveBinding extends ResolvedBinding {
|
||||
resolvedInjectables:List<ResolvedBinding>;
|
||||
resolvedAppInjectables:List<ResolvedBinding>;
|
||||
resolvedHostInjectables:List<ResolvedBinding>;
|
||||
resolvedViewInjectables:List<ResolvedBinding>;
|
||||
metadata: DirectiveMetadata;
|
||||
|
||||
constructor(key:Key, factory:Function, dependencies:List, providedAsPromise:boolean,
|
||||
resolvedInjectables:List<ResolvedBinding>, metadata:DirectiveMetadata, annotation: Directive) {
|
||||
resolvedAppInjectables:List<ResolvedBinding>, resolvedHostInjectables:List<ResolvedBinding>,
|
||||
resolvedViewInjectables:List<ResolvedBinding>, metadata:DirectiveMetadata) {
|
||||
super(key, factory, dependencies, providedAsPromise);
|
||||
this.resolvedInjectables = resolvedInjectables;
|
||||
this.resolvedAppInjectables = resolvedAppInjectables;
|
||||
this.resolvedHostInjectables = resolvedHostInjectables;
|
||||
this.resolvedViewInjectables = resolvedViewInjectables;
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
|
@ -260,59 +261,52 @@ export class DirectiveBinding extends ResolvedBinding {
|
|||
}
|
||||
|
||||
get changeDetection() {
|
||||
if (isPresent(metadata)) {
|
||||
return metadata.changeDetection;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return this.metadata.changeDetection;
|
||||
}
|
||||
|
||||
static createFromBinding(b:Binding, ann:Directive):DirectiveBinding {
|
||||
static createFromBinding(binding:Binding, ann:Directive):DirectiveBinding {
|
||||
if (isBlank(ann)) {
|
||||
ann = new Directive();
|
||||
}
|
||||
var rb = b.resolve();
|
||||
|
||||
var rb = binding.resolve();
|
||||
var deps = ListWrapper.map(rb.dependencies, DirectiveDependency.createFrom);
|
||||
var renderType;
|
||||
var compileChildren = ann.compileChildren;
|
||||
var resolvedInjectables = null;
|
||||
var changeDetection = null;
|
||||
if (ann instanceof Component) {
|
||||
renderType = DirectiveMetadata.COMPONENT_TYPE;
|
||||
if (isPresent(ann.appInjector)) {
|
||||
resolvedInjectables = Injector.resolve(ann.appInjector);
|
||||
}
|
||||
changeDetection = ann.changeDetection;
|
||||
} else {
|
||||
renderType = DirectiveMetadata.DIRECTIVE_TYPE;
|
||||
}
|
||||
var readAttributes = [];
|
||||
ListWrapper.forEach(deps, (dep) => {
|
||||
if (isPresent(dep.attributeName)) {
|
||||
ListWrapper.push(readAttributes, dep.attributeName);
|
||||
}
|
||||
});
|
||||
var resolvedAppInjectables = ann instanceof Component && isPresent(ann.appInjector) ? Injector.resolve(ann.appInjector) : [];
|
||||
var resolvedHostInjectables = isPresent(ann.hostInjector) ? resolveBindings(ann.hostInjector) : [];
|
||||
var resolvedViewInjectables = ann instanceof Component && isPresent(ann.viewInjector) ? resolveBindings(ann.viewInjector) : [];
|
||||
|
||||
var metadata = new DirectiveMetadata({
|
||||
id: stringify(rb.key.token),
|
||||
type: renderType,
|
||||
type: ann instanceof Component ? DirectiveMetadata.COMPONENT_TYPE : DirectiveMetadata.DIRECTIVE_TYPE,
|
||||
selector: ann.selector,
|
||||
compileChildren: compileChildren,
|
||||
compileChildren: ann.compileChildren,
|
||||
events: ann.events,
|
||||
hostListeners: isPresent(ann.hostListeners) ? MapWrapper.createFromStringMap(ann.hostListeners) : null,
|
||||
hostProperties: isPresent(ann.hostProperties) ? MapWrapper.createFromStringMap(ann.hostProperties) : null,
|
||||
hostAttributes: isPresent(ann.hostAttributes) ? MapWrapper.createFromStringMap(ann.hostAttributes) : null,
|
||||
hostActions: isPresent(ann.hostActions) ? MapWrapper.createFromStringMap(ann.hostActions) : null,
|
||||
properties: isPresent(ann.properties) ? MapWrapper.createFromStringMap(ann.properties) : null,
|
||||
readAttributes: readAttributes,
|
||||
readAttributes: DirectiveBinding._readAttributes(deps),
|
||||
callOnDestroy: ann.hasLifecycleHook(onDestroy),
|
||||
callOnChange: ann.hasLifecycleHook(onChange),
|
||||
callOnAllChangesDone: ann.hasLifecycleHook(onAllChangesDone),
|
||||
changeDetection: changeDetection
|
||||
changeDetection: ann instanceof Component ? ann.changeDetection : null
|
||||
});
|
||||
return new DirectiveBinding(rb.key, rb.factory, deps, rb.providedAsPromise, resolvedInjectables, metadata, ann);
|
||||
return new DirectiveBinding(rb.key, rb.factory, deps, rb.providedAsPromise, resolvedAppInjectables,
|
||||
resolvedHostInjectables, resolvedViewInjectables, metadata);
|
||||
}
|
||||
|
||||
static createFromType(type:Type, annotation:Directive):DirectiveBinding {
|
||||
static _readAttributes(deps) {
|
||||
var readAttributes = [];
|
||||
ListWrapper.forEach(deps, (dep) => {
|
||||
if (isPresent(dep.attributeName)) {
|
||||
ListWrapper.push(readAttributes, dep.attributeName);
|
||||
}
|
||||
});
|
||||
return readAttributes;
|
||||
}
|
||||
|
||||
static createFromType(type:Type, annotation:Directive):DirectiveBinding {
|
||||
var binding = new Binding(type, {toClass: type});
|
||||
return DirectiveBinding.createFromBinding(binding, annotation);
|
||||
}
|
||||
|
@ -363,6 +357,42 @@ class HostActionAccessor {
|
|||
}
|
||||
}
|
||||
|
||||
const LIGHT_DOM = 1;
|
||||
const SHADOW_DOM = 2;
|
||||
const LIGHT_DOM_AND_SHADOW_DOM = 3;
|
||||
|
||||
class BindingData {
|
||||
binding:ResolvedBinding;
|
||||
visibility:number;
|
||||
|
||||
constructor(binding:ResolvedBinding, visibility:number) {
|
||||
this.binding = binding;
|
||||
this.visibility = visibility;
|
||||
}
|
||||
|
||||
getKeyId() {
|
||||
return this.binding.key.id;
|
||||
}
|
||||
|
||||
createEventEmitterAccessors() {
|
||||
if (!(this.binding instanceof DirectiveBinding)) return [];
|
||||
var db:DirectiveBinding = this.binding;
|
||||
return ListWrapper.map(db.eventEmitters, eventName =>
|
||||
new EventEmitterAccessor(eventName, reflector.getter(eventName))
|
||||
);
|
||||
}
|
||||
|
||||
createHostActionAccessors() {
|
||||
if (!(this.binding instanceof DirectiveBinding)) return [];
|
||||
var res = [];
|
||||
var db:DirectiveBinding = this.binding;
|
||||
MapWrapper.forEach(db.hostActions, (actionExpression, actionName) => {
|
||||
ListWrapper.push(res, new HostActionAccessor(actionExpression, reflector.getter(actionName)))
|
||||
});
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Difference between di.Injector and ElementInjector
|
||||
|
@ -382,20 +412,19 @@ ElementInjector:
|
|||
|
||||
PERF BENCHMARK: http://www.williambrownstreet.net/blog/2014/04/faster-angularjs-rendering-angularjs-and-reactjs/
|
||||
*/
|
||||
|
||||
|
||||
export class ProtoElementInjector {
|
||||
_binding0:DirectiveBinding;
|
||||
_binding1:DirectiveBinding;
|
||||
_binding2:DirectiveBinding;
|
||||
_binding3:DirectiveBinding;
|
||||
_binding4:DirectiveBinding;
|
||||
_binding5:DirectiveBinding;
|
||||
_binding6:DirectiveBinding;
|
||||
_binding7:DirectiveBinding;
|
||||
_binding8:DirectiveBinding;
|
||||
_binding9:DirectiveBinding;
|
||||
_binding0IsComponent:boolean;
|
||||
// only _binding0 can contain a component
|
||||
_binding0:ResolvedBinding;
|
||||
_binding1:ResolvedBinding;
|
||||
_binding2:ResolvedBinding;
|
||||
_binding3:ResolvedBinding;
|
||||
_binding4:ResolvedBinding;
|
||||
_binding5:ResolvedBinding;
|
||||
_binding6:ResolvedBinding;
|
||||
_binding7:ResolvedBinding;
|
||||
_binding8:ResolvedBinding;
|
||||
_binding9:ResolvedBinding;
|
||||
|
||||
_keyId0:int;
|
||||
_keyId1:int;
|
||||
_keyId2:int;
|
||||
|
@ -406,6 +435,18 @@ export class ProtoElementInjector {
|
|||
_keyId7:int;
|
||||
_keyId8:int;
|
||||
_keyId9:int;
|
||||
|
||||
_visibility0:number;
|
||||
_visibility1:number;
|
||||
_visibility2:number;
|
||||
_visibility3:number;
|
||||
_visibility4:number;
|
||||
_visibility5:number;
|
||||
_visibility6:number;
|
||||
_visibility7:number;
|
||||
_visibility8:number;
|
||||
_visibility9:number;
|
||||
|
||||
parent:ProtoElementInjector;
|
||||
index:int;
|
||||
view:viewModule.AppView;
|
||||
|
@ -414,8 +455,6 @@ export class ProtoElementInjector {
|
|||
eventEmitterAccessors:List<List<EventEmitterAccessor>>;
|
||||
hostActionAccessors:List<List<HostActionAccessor>>;
|
||||
|
||||
numberOfDirectives:number;
|
||||
|
||||
/** Whether the element is exported as $implicit. */
|
||||
exportElement:boolean;
|
||||
|
||||
|
@ -425,109 +464,144 @@ export class ProtoElementInjector {
|
|||
/** The variable name that will be set to $implicit for the element. */
|
||||
exportImplicitName:string;
|
||||
|
||||
constructor(parent:ProtoElementInjector, index:int, bindings:List, firstBindingIsComponent:boolean = false, distanceToParent:number = 0) {
|
||||
_firstBindingIsComponent:boolean;
|
||||
|
||||
static create(parent:ProtoElementInjector, index:int, bindings:List, firstBindingIsComponent:boolean, distanceToParent:number) {
|
||||
var bd = [];
|
||||
|
||||
ProtoElementInjector._createDirectiveBindingData(bindings, bd, firstBindingIsComponent);
|
||||
ProtoElementInjector._createHostInjectorBindingData(bindings, bd);
|
||||
if (firstBindingIsComponent) {
|
||||
ProtoElementInjector._createViewInjectorBindingData(bindings, bd);
|
||||
}
|
||||
|
||||
return new ProtoElementInjector(parent, index, bd, distanceToParent, firstBindingIsComponent);
|
||||
}
|
||||
|
||||
static _createDirectiveBindingData(bindings:List, bd:List, firstBindingIsComponent:boolean) {
|
||||
if (firstBindingIsComponent) {
|
||||
ListWrapper.push(bd, new BindingData(bindings[0], LIGHT_DOM_AND_SHADOW_DOM));
|
||||
for (var i = 1; i < bindings.length; ++i) {
|
||||
ListWrapper.push(bd, new BindingData(bindings[i], LIGHT_DOM));
|
||||
}
|
||||
} else {
|
||||
ListWrapper.forEach(bindings, b => {
|
||||
ListWrapper.push(bd, new BindingData(b, LIGHT_DOM))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static _createHostInjectorBindingData(bindings:List, bd:List) {
|
||||
ListWrapper.forEach(bindings, b => {
|
||||
ListWrapper.forEach(b.resolvedHostInjectables, b => {
|
||||
ListWrapper.push(bd, new BindingData(b, LIGHT_DOM));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static _createViewInjectorBindingData(bindings:List, bd:List) {
|
||||
ListWrapper.forEach(bindings[0].resolvedViewInjectables,
|
||||
b => ListWrapper.push(bd, new BindingData(b, SHADOW_DOM)));
|
||||
}
|
||||
|
||||
constructor(parent:ProtoElementInjector, index:int, bd:List<BindingData>, distanceToParent:number, firstBindingIsComponent:boolean) {
|
||||
this.parent = parent;
|
||||
this.index = index;
|
||||
this.distanceToParent = distanceToParent;
|
||||
this.exportComponent = false;
|
||||
this.exportElement = false;
|
||||
|
||||
this._binding0IsComponent = firstBindingIsComponent;
|
||||
this._binding0 = null; this._keyId0 = null;
|
||||
this._binding1 = null; this._keyId1 = null;
|
||||
this._binding2 = null; this._keyId2 = null;
|
||||
this._binding3 = null; this._keyId3 = null;
|
||||
this._binding4 = null; this._keyId4 = null;
|
||||
this._binding5 = null; this._keyId5 = null;
|
||||
this._binding6 = null; this._keyId6 = null;
|
||||
this._binding7 = null; this._keyId7 = null;
|
||||
this._binding8 = null; this._keyId8 = null;
|
||||
this._binding9 = null; this._keyId9 = null;
|
||||
|
||||
this.numberOfDirectives = bindings.length;
|
||||
var length = bindings.length;
|
||||
this._firstBindingIsComponent = firstBindingIsComponent;
|
||||
|
||||
this._binding0 = null; this._keyId0 = null; this._visibility0 = null;
|
||||
this._binding1 = null; this._keyId1 = null; this._visibility1 = null;
|
||||
this._binding2 = null; this._keyId2 = null; this._visibility2 = null;
|
||||
this._binding3 = null; this._keyId3 = null; this._visibility3 = null;
|
||||
this._binding4 = null; this._keyId4 = null; this._visibility4 = null;
|
||||
this._binding5 = null; this._keyId5 = null; this._visibility5 = null;
|
||||
this._binding6 = null; this._keyId6 = null; this._visibility6 = null;
|
||||
this._binding7 = null; this._keyId7 = null; this._visibility7 = null;
|
||||
this._binding8 = null; this._keyId8 = null; this._visibility8 = null;
|
||||
this._binding9 = null; this._keyId9 = null; this._visibility9 = null;
|
||||
|
||||
var length = bd.length;
|
||||
this.eventEmitterAccessors = ListWrapper.createFixedSize(length);
|
||||
this.hostActionAccessors = ListWrapper.createFixedSize(length);
|
||||
|
||||
if (length > 0) {
|
||||
this._binding0 = this._createBinding(bindings[0]);
|
||||
this._keyId0 = this._binding0.key.id;
|
||||
this.eventEmitterAccessors[0] = this._createEventEmitterAccessors(this._binding0);
|
||||
this.hostActionAccessors[0] = this._createHostActionAccessors(this._binding0);
|
||||
this._binding0 = bd[0].binding;
|
||||
this._keyId0 = bd[0].getKeyId();
|
||||
this._visibility0 = bd[0].visibility;
|
||||
this.eventEmitterAccessors[0] = bd[0].createEventEmitterAccessors();
|
||||
this.hostActionAccessors[0] = bd[0].createHostActionAccessors();
|
||||
}
|
||||
if (length > 1) {
|
||||
this._binding1 = this._createBinding(bindings[1]);
|
||||
this._keyId1 = this._binding1.key.id;
|
||||
this.eventEmitterAccessors[1] = this._createEventEmitterAccessors(this._binding1);
|
||||
this.hostActionAccessors[1] = this._createHostActionAccessors(this._binding1);
|
||||
this._binding1 = bd[1].binding;
|
||||
this._keyId1 = bd[1].getKeyId();
|
||||
this._visibility1 = bd[1].visibility;
|
||||
this.eventEmitterAccessors[1] = bd[1].createEventEmitterAccessors();
|
||||
this.hostActionAccessors[1] = bd[1].createHostActionAccessors();
|
||||
}
|
||||
if (length > 2) {
|
||||
this._binding2 = this._createBinding(bindings[2]);
|
||||
this._keyId2 = this._binding2.key.id;
|
||||
this.eventEmitterAccessors[2] = this._createEventEmitterAccessors(this._binding2);
|
||||
this.hostActionAccessors[2] = this._createHostActionAccessors(this._binding2);
|
||||
this._binding2 = bd[2].binding;
|
||||
this._keyId2 = bd[2].getKeyId();
|
||||
this._visibility2 = bd[2].visibility;
|
||||
this.eventEmitterAccessors[2] = bd[2].createEventEmitterAccessors();
|
||||
this.hostActionAccessors[2] = bd[2].createHostActionAccessors();
|
||||
}
|
||||
if (length > 3) {
|
||||
this._binding3 = this._createBinding(bindings[3]);
|
||||
this._keyId3 = this._binding3.key.id;
|
||||
this.eventEmitterAccessors[3] = this._createEventEmitterAccessors(this._binding3);
|
||||
this.hostActionAccessors[3] = this._createHostActionAccessors(this._binding3);
|
||||
this._binding3 = bd[3].binding;
|
||||
this._keyId3 = bd[3].getKeyId();
|
||||
this._visibility3 = bd[3].visibility;
|
||||
this.eventEmitterAccessors[3] = bd[3].createEventEmitterAccessors();
|
||||
this.hostActionAccessors[3] = bd[3].createHostActionAccessors();
|
||||
}
|
||||
if (length > 4) {
|
||||
this._binding4 = this._createBinding(bindings[4]);
|
||||
this._keyId4 = this._binding4.key.id;
|
||||
this.eventEmitterAccessors[4] = this._createEventEmitterAccessors(this._binding4);
|
||||
this.hostActionAccessors[4] = this._createHostActionAccessors(this._binding4);
|
||||
this._binding4 = bd[4].binding;
|
||||
this._keyId4 = bd[4].getKeyId();
|
||||
this._visibility4 = bd[4].visibility;
|
||||
this.eventEmitterAccessors[4] = bd[4].createEventEmitterAccessors();
|
||||
this.hostActionAccessors[4] = bd[4].createHostActionAccessors();
|
||||
}
|
||||
if (length > 5) {
|
||||
this._binding5 = this._createBinding(bindings[5]);
|
||||
this._keyId5 = this._binding5.key.id;
|
||||
this.eventEmitterAccessors[5] = this._createEventEmitterAccessors(this._binding5);
|
||||
this.hostActionAccessors[5] = this._createHostActionAccessors(this._binding5);
|
||||
this._binding5 = bd[5].binding;
|
||||
this._keyId5 = bd[5].getKeyId();
|
||||
this._visibility5 = bd[5].visibility;
|
||||
this.eventEmitterAccessors[5] = bd[5].createEventEmitterAccessors();
|
||||
this.hostActionAccessors[5] = bd[5].createHostActionAccessors();
|
||||
}
|
||||
if (length > 6) {
|
||||
this._binding6 = this._createBinding(bindings[6]);
|
||||
this._keyId6 = this._binding6.key.id;
|
||||
this.eventEmitterAccessors[6] = this._createEventEmitterAccessors(this._binding6);
|
||||
this.hostActionAccessors[6] = this._createHostActionAccessors(this._binding6);
|
||||
this._binding6 = bd[6].binding;
|
||||
this._keyId6 = bd[6].getKeyId();
|
||||
this._visibility6 = bd[6].visibility;
|
||||
this.eventEmitterAccessors[6] = bd[6].createEventEmitterAccessors();
|
||||
this.hostActionAccessors[6] = bd[6].createHostActionAccessors();
|
||||
}
|
||||
if (length > 7) {
|
||||
this._binding7 = this._createBinding(bindings[7]);
|
||||
this._keyId7 = this._binding7.key.id;
|
||||
this.eventEmitterAccessors[7] = this._createEventEmitterAccessors(this._binding7);
|
||||
this.hostActionAccessors[7] = this._createHostActionAccessors(this._binding7);
|
||||
this._binding7 = bd[7].binding;
|
||||
this._keyId7 = bd[7].getKeyId();
|
||||
this._visibility7 = bd[7].visibility;
|
||||
this.eventEmitterAccessors[7] = bd[7].createEventEmitterAccessors();
|
||||
this.hostActionAccessors[7] = bd[7].createHostActionAccessors();
|
||||
}
|
||||
if (length > 8) {
|
||||
this._binding8 = this._createBinding(bindings[8]);
|
||||
this._keyId8 = this._binding8.key.id;
|
||||
this.eventEmitterAccessors[8] = this._createEventEmitterAccessors(this._binding8);
|
||||
this.hostActionAccessors[8] = this._createHostActionAccessors(this._binding8);
|
||||
this._binding8 = bd[8].binding;
|
||||
this._keyId8 = bd[8].getKeyId();
|
||||
this._visibility8 = bd[8].visibility;
|
||||
this.eventEmitterAccessors[8] = bd[8].createEventEmitterAccessors();
|
||||
this.hostActionAccessors[8] = bd[8].createHostActionAccessors();
|
||||
}
|
||||
if (length > 9) {
|
||||
this._binding9 = this._createBinding(bindings[9]);
|
||||
this._keyId9 = this._binding9.key.id;
|
||||
this.eventEmitterAccessors[9] = this._createEventEmitterAccessors(this._binding9);
|
||||
this.hostActionAccessors[9] = this._createHostActionAccessors(this._binding9);
|
||||
this._binding9 = bd[9].binding;
|
||||
this._keyId9 = bd[9].getKeyId();
|
||||
this._visibility9 = bd[9].visibility;
|
||||
this.eventEmitterAccessors[9] = bd[9].createEventEmitterAccessors();
|
||||
this.hostActionAccessors[9] = bd[9].createHostActionAccessors();
|
||||
}
|
||||
if (length > 10) {
|
||||
throw 'Maximum number of directives per element has been reached.';
|
||||
}
|
||||
}
|
||||
|
||||
_createEventEmitterAccessors(b:DirectiveBinding) {
|
||||
return ListWrapper.map(b.eventEmitters, eventName =>
|
||||
new EventEmitterAccessor(eventName, reflector.getter(eventName))
|
||||
);
|
||||
}
|
||||
|
||||
_createHostActionAccessors(b:DirectiveBinding) {
|
||||
var res = [];
|
||||
MapWrapper.forEach(b.hostActions, (actionExpression, actionName) => {
|
||||
ListWrapper.push(res, new HostActionAccessor(actionExpression, reflector.getter(actionName)))
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
instantiate(parent:ElementInjector):ElementInjector {
|
||||
return new ElementInjector(this, parent);
|
||||
}
|
||||
|
@ -536,20 +610,11 @@ export class ProtoElementInjector {
|
|||
return this.distanceToParent < 2 ? this.parent : null;
|
||||
}
|
||||
|
||||
_createBinding(bindingOrType) {
|
||||
if (bindingOrType instanceof DirectiveBinding) {
|
||||
return bindingOrType;
|
||||
} else {
|
||||
var b = bind(bindingOrType).toClass(bindingOrType);
|
||||
return DirectiveBinding.createFromBinding(b, null);
|
||||
}
|
||||
}
|
||||
|
||||
get hasBindings():boolean {
|
||||
return isPresent(this._binding0);
|
||||
}
|
||||
|
||||
getDirectiveBindingAtIndex(index:int) {
|
||||
getBindingAtIndex(index:int) {
|
||||
if (index == 0) return this._binding0;
|
||||
if (index == 1) return this._binding1;
|
||||
if (index == 2) return this._binding2;
|
||||
|
@ -597,7 +662,7 @@ export class ElementInjector extends TreeNode {
|
|||
super(parent);
|
||||
this._proto = proto;
|
||||
|
||||
//we cannot call clearDirectives because fields won't be detected
|
||||
//we cannot call dehydrate because fields won't be detected
|
||||
this._preBuiltObjects = null;
|
||||
this._lightDomAppInjector = null;
|
||||
this._shadowDomAppInjector = null;
|
||||
|
@ -617,7 +682,7 @@ export class ElementInjector extends TreeNode {
|
|||
this._buildQueries();
|
||||
}
|
||||
|
||||
clearDirectives() {
|
||||
dehydrate() {
|
||||
this._host = null;
|
||||
this._preBuiltObjects = null;
|
||||
this._lightDomAppInjector = null;
|
||||
|
@ -625,16 +690,16 @@ export class ElementInjector extends TreeNode {
|
|||
|
||||
var p = this._proto;
|
||||
|
||||
if (isPresent(p._binding0) && p._binding0.callOnDestroy) {this._obj0.onDestroy();}
|
||||
if (isPresent(p._binding1) && p._binding1.callOnDestroy) {this._obj1.onDestroy();}
|
||||
if (isPresent(p._binding2) && p._binding2.callOnDestroy) {this._obj2.onDestroy();}
|
||||
if (isPresent(p._binding3) && p._binding3.callOnDestroy) {this._obj3.onDestroy();}
|
||||
if (isPresent(p._binding4) && p._binding4.callOnDestroy) {this._obj4.onDestroy();}
|
||||
if (isPresent(p._binding5) && p._binding5.callOnDestroy) {this._obj5.onDestroy();}
|
||||
if (isPresent(p._binding6) && p._binding6.callOnDestroy) {this._obj6.onDestroy();}
|
||||
if (isPresent(p._binding7) && p._binding7.callOnDestroy) {this._obj7.onDestroy();}
|
||||
if (isPresent(p._binding8) && p._binding8.callOnDestroy) {this._obj8.onDestroy();}
|
||||
if (isPresent(p._binding9) && p._binding9.callOnDestroy) {this._obj9.onDestroy();}
|
||||
if (p._binding0 instanceof DirectiveBinding && p._binding0.callOnDestroy) {this._obj0.onDestroy();}
|
||||
if (p._binding1 instanceof DirectiveBinding && p._binding1.callOnDestroy) {this._obj1.onDestroy();}
|
||||
if (p._binding2 instanceof DirectiveBinding && p._binding2.callOnDestroy) {this._obj2.onDestroy();}
|
||||
if (p._binding3 instanceof DirectiveBinding && p._binding3.callOnDestroy) {this._obj3.onDestroy();}
|
||||
if (p._binding4 instanceof DirectiveBinding && p._binding4.callOnDestroy) {this._obj4.onDestroy();}
|
||||
if (p._binding5 instanceof DirectiveBinding && p._binding5.callOnDestroy) {this._obj5.onDestroy();}
|
||||
if (p._binding6 instanceof DirectiveBinding && p._binding6.callOnDestroy) {this._obj6.onDestroy();}
|
||||
if (p._binding7 instanceof DirectiveBinding && p._binding7.callOnDestroy) {this._obj7.onDestroy();}
|
||||
if (p._binding8 instanceof DirectiveBinding && p._binding8.callOnDestroy) {this._obj8.onDestroy();}
|
||||
if (p._binding9 instanceof DirectiveBinding && p._binding9.callOnDestroy) {this._obj9.onDestroy();}
|
||||
if (isPresent(this._dynamicallyCreatedComponentBinding) && this._dynamicallyCreatedComponentBinding.callOnDestroy) {
|
||||
this._dynamicallyCreatedComponent.onDestroy();
|
||||
}
|
||||
|
@ -655,45 +720,38 @@ export class ElementInjector extends TreeNode {
|
|||
this._constructionCounter = 0;
|
||||
}
|
||||
|
||||
instantiateDirectives(
|
||||
lightDomAppInjector:Injector,
|
||||
host:ElementInjector,
|
||||
preBuiltObjects:PreBuiltObjects) {
|
||||
var shadowDomAppInjector = null;
|
||||
if (this._proto._binding0IsComponent) {
|
||||
shadowDomAppInjector = this._createShadowDomAppInjector(this._proto._binding0, lightDomAppInjector);
|
||||
}
|
||||
this._host = host;
|
||||
this._checkShadowDomAppInjector(shadowDomAppInjector);
|
||||
|
||||
this._preBuiltObjects = preBuiltObjects;
|
||||
this._lightDomAppInjector = lightDomAppInjector;
|
||||
this._shadowDomAppInjector = shadowDomAppInjector;
|
||||
|
||||
hydrate(injector:Injector, host:ElementInjector, preBuiltObjects:PreBuiltObjects) {
|
||||
var p = this._proto;
|
||||
if (isPresent(p._keyId0)) this._getDirectiveByKeyId(p._keyId0);
|
||||
if (isPresent(p._keyId1)) this._getDirectiveByKeyId(p._keyId1);
|
||||
if (isPresent(p._keyId2)) this._getDirectiveByKeyId(p._keyId2);
|
||||
if (isPresent(p._keyId3)) this._getDirectiveByKeyId(p._keyId3);
|
||||
if (isPresent(p._keyId4)) this._getDirectiveByKeyId(p._keyId4);
|
||||
if (isPresent(p._keyId5)) this._getDirectiveByKeyId(p._keyId5);
|
||||
if (isPresent(p._keyId6)) this._getDirectiveByKeyId(p._keyId6);
|
||||
if (isPresent(p._keyId7)) this._getDirectiveByKeyId(p._keyId7);
|
||||
if (isPresent(p._keyId8)) this._getDirectiveByKeyId(p._keyId8);
|
||||
if (isPresent(p._keyId9)) this._getDirectiveByKeyId(p._keyId9);
|
||||
|
||||
this._host = host;
|
||||
this._lightDomAppInjector = injector;
|
||||
this._preBuiltObjects = preBuiltObjects;
|
||||
|
||||
if (p._firstBindingIsComponent) {
|
||||
this._shadowDomAppInjector = this._createShadowDomAppInjector(p._binding0, injector);
|
||||
}
|
||||
|
||||
this._checkShadowDomAppInjector(this._shadowDomAppInjector);
|
||||
|
||||
if (isPresent(p._keyId0)) this._getObjByKeyId(p._keyId0, LIGHT_DOM_AND_SHADOW_DOM);
|
||||
if (isPresent(p._keyId1)) this._getObjByKeyId(p._keyId1, LIGHT_DOM_AND_SHADOW_DOM);
|
||||
if (isPresent(p._keyId2)) this._getObjByKeyId(p._keyId2, LIGHT_DOM_AND_SHADOW_DOM);
|
||||
if (isPresent(p._keyId3)) this._getObjByKeyId(p._keyId3, LIGHT_DOM_AND_SHADOW_DOM);
|
||||
if (isPresent(p._keyId4)) this._getObjByKeyId(p._keyId4, LIGHT_DOM_AND_SHADOW_DOM);
|
||||
if (isPresent(p._keyId5)) this._getObjByKeyId(p._keyId5, LIGHT_DOM_AND_SHADOW_DOM);
|
||||
if (isPresent(p._keyId6)) this._getObjByKeyId(p._keyId6, LIGHT_DOM_AND_SHADOW_DOM);
|
||||
if (isPresent(p._keyId7)) this._getObjByKeyId(p._keyId7, LIGHT_DOM_AND_SHADOW_DOM);
|
||||
if (isPresent(p._keyId8)) this._getObjByKeyId(p._keyId8, LIGHT_DOM_AND_SHADOW_DOM);
|
||||
if (isPresent(p._keyId9)) this._getObjByKeyId(p._keyId9, LIGHT_DOM_AND_SHADOW_DOM);
|
||||
}
|
||||
|
||||
_createShadowDomAppInjector(componentDirective:DirectiveBinding, appInjector:Injector) {
|
||||
var shadowDomAppInjector = null;
|
||||
|
||||
// shadowDomAppInjector
|
||||
var injectables = componentDirective.resolvedInjectables;
|
||||
if (isPresent(injectables)) {
|
||||
shadowDomAppInjector = appInjector.createChildFromResolved(injectables);
|
||||
if (! ListWrapper.isEmpty(componentDirective.resolvedAppInjectables)) {
|
||||
return appInjector.createChildFromResolved(componentDirective.resolvedAppInjectables);
|
||||
} else {
|
||||
shadowDomAppInjector = appInjector;
|
||||
return appInjector;
|
||||
}
|
||||
return shadowDomAppInjector;
|
||||
}
|
||||
|
||||
dynamicallyCreateComponent(componentDirective:DirectiveBinding, parentInjector:Injector) {
|
||||
|
@ -704,9 +762,9 @@ export class ElementInjector extends TreeNode {
|
|||
}
|
||||
|
||||
_checkShadowDomAppInjector(shadowDomAppInjector:Injector) {
|
||||
if (this._proto._binding0IsComponent && isBlank(shadowDomAppInjector)) {
|
||||
if (this._proto._firstBindingIsComponent && isBlank(shadowDomAppInjector)) {
|
||||
throw new BaseException('A shadowDomAppInjector is required as this ElementInjector contains a component');
|
||||
} else if (!this._proto._binding0IsComponent && isPresent(shadowDomAppInjector)) {
|
||||
} else if (!this._proto._firstBindingIsComponent && isPresent(shadowDomAppInjector)) {
|
||||
throw new BaseException('No shadowDomAppInjector allowed as there is not component stored in this ElementInjector');
|
||||
}
|
||||
}
|
||||
|
@ -716,7 +774,7 @@ export class ElementInjector extends TreeNode {
|
|||
return this._dynamicallyCreatedComponent;
|
||||
}
|
||||
|
||||
return this._getByKey(Key.get(token), 0, false, null);
|
||||
return this._getByKey(Key.get(token), new Self(), false, null);
|
||||
}
|
||||
|
||||
_isDynamicallyLoadedComponent(token) {
|
||||
|
@ -725,7 +783,7 @@ export class ElementInjector extends TreeNode {
|
|||
}
|
||||
|
||||
hasDirective(type:Type):boolean {
|
||||
return this._getDirectiveByKeyId(Key.get(type).id) !== _undefined;
|
||||
return this._getObjByKeyId(Key.get(type).id, LIGHT_DOM_AND_SHADOW_DOM) !== _undefined;
|
||||
}
|
||||
|
||||
getEventEmitterAccessors() {
|
||||
|
@ -737,11 +795,7 @@ export class ElementInjector extends TreeNode {
|
|||
}
|
||||
|
||||
getComponent() {
|
||||
if (this._proto._binding0IsComponent) {
|
||||
return this._obj0;
|
||||
} else {
|
||||
throw new BaseException('There is no component stored in this ElementInjector');
|
||||
}
|
||||
return this._obj0;
|
||||
}
|
||||
|
||||
getElementRef() {
|
||||
|
@ -761,7 +815,7 @@ export class ElementInjector extends TreeNode {
|
|||
}
|
||||
|
||||
_isComponentKey(key:Key) {
|
||||
return this._proto._binding0IsComponent && key.id === this._proto._keyId0;
|
||||
return this._proto._firstBindingIsComponent && key.id === this._proto._keyId0;
|
||||
}
|
||||
|
||||
_isDynamicallyLoadedComponentKey(key:Key) {
|
||||
|
@ -839,7 +893,7 @@ export class ElementInjector extends TreeNode {
|
|||
}
|
||||
return new ProtoViewRef(this._preBuiltObjects.protoView);
|
||||
}
|
||||
return this._getByKey(dep.key, dep.depth, dep.optional, requestor);
|
||||
return this._getByKey(dep.key, dep.visibility, dep.optional, requestor);
|
||||
}
|
||||
|
||||
_buildAttribute(dep): string {
|
||||
|
@ -965,25 +1019,46 @@ export class ElementInjector extends TreeNode {
|
|||
if (this._query2 == query) this._query2 = null;
|
||||
}
|
||||
|
||||
_getByKey(key:Key, depth:number, optional:boolean, requestor:Key) {
|
||||
_getByKey(key:Key, visibility:Visibility, optional:boolean, requestor:Key) {
|
||||
var ei = this;
|
||||
if (! this._shouldIncludeSelf(depth)) {
|
||||
depth -= ei._proto.distanceToParent;
|
||||
ei = ei._parent;
|
||||
}
|
||||
|
||||
var currentVisibility = LIGHT_DOM;
|
||||
var depth = visibility.depth;
|
||||
|
||||
if (! visibility.shouldIncludeSelf()) {
|
||||
depth -= ei._proto.distanceToParent;
|
||||
|
||||
if (isPresent(ei._parent)) {
|
||||
ei = ei._parent;
|
||||
} else {
|
||||
ei = ei._host;
|
||||
if (!visibility.crossComponentBoundaries) {
|
||||
currentVisibility = SHADOW_DOM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (ei != null && depth >= 0) {
|
||||
var preBuiltObj = ei._getPreBuiltObjectByKeyId(key.id);
|
||||
if (preBuiltObj !== _undefined) return preBuiltObj;
|
||||
|
||||
var dir = ei._getDirectiveByKeyId(key.id);
|
||||
var dir = ei._getObjByKeyId(key.id, currentVisibility);
|
||||
if (dir !== _undefined) return dir;
|
||||
|
||||
depth -= ei._proto.distanceToParent;
|
||||
ei = ei._parent;
|
||||
|
||||
if (currentVisibility === SHADOW_DOM) break;
|
||||
|
||||
if (isPresent(ei._parent)) {
|
||||
ei = ei._parent;
|
||||
} else {
|
||||
ei = ei._host;
|
||||
if (!visibility.crossComponentBoundaries) {
|
||||
currentVisibility = SHADOW_DOM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isPresent(this._host) && this._host._isComponentKey(key)) {
|
||||
return this._host.getComponent();
|
||||
} else if (isPresent(this._host) && this._host._isDynamicallyLoadedComponentKey(key)) {
|
||||
|
@ -994,7 +1069,7 @@ export class ElementInjector extends TreeNode {
|
|||
return this._appInjector(requestor).get(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_appInjector(requestor:Key) {
|
||||
if (isPresent(requestor) && (this._isComponentKey(requestor) || this._isDynamicallyLoadedComponentKey(requestor))) {
|
||||
return this._shadowDomAppInjector;
|
||||
|
@ -1003,10 +1078,6 @@ export class ElementInjector extends TreeNode {
|
|||
}
|
||||
}
|
||||
|
||||
_shouldIncludeSelf(depth:int) {
|
||||
return depth === 0;
|
||||
}
|
||||
|
||||
_getPreBuiltObjectByKeyId(keyId:int) {
|
||||
var staticKeys = StaticKeys.instance();
|
||||
if (keyId === staticKeys.viewManagerId) return this._preBuiltObjects.viewManager;
|
||||
|
@ -1015,19 +1086,20 @@ export class ElementInjector extends TreeNode {
|
|||
return _undefined;
|
||||
}
|
||||
|
||||
_getDirectiveByKeyId(keyId:int) {
|
||||
_getObjByKeyId(keyId:int, visibility:number) {
|
||||
var p = this._proto;
|
||||
|
||||
if (p._keyId0 === keyId) {if (isBlank(this._obj0)){this._obj0 = this._new(p._binding0);} return this._obj0;}
|
||||
if (p._keyId1 === keyId) {if (isBlank(this._obj1)){this._obj1 = this._new(p._binding1);} return this._obj1;}
|
||||
if (p._keyId2 === keyId) {if (isBlank(this._obj2)){this._obj2 = this._new(p._binding2);} return this._obj2;}
|
||||
if (p._keyId3 === keyId) {if (isBlank(this._obj3)){this._obj3 = this._new(p._binding3);} return this._obj3;}
|
||||
if (p._keyId4 === keyId) {if (isBlank(this._obj4)){this._obj4 = this._new(p._binding4);} return this._obj4;}
|
||||
if (p._keyId5 === keyId) {if (isBlank(this._obj5)){this._obj5 = this._new(p._binding5);} return this._obj5;}
|
||||
if (p._keyId6 === keyId) {if (isBlank(this._obj6)){this._obj6 = this._new(p._binding6);} return this._obj6;}
|
||||
if (p._keyId7 === keyId) {if (isBlank(this._obj7)){this._obj7 = this._new(p._binding7);} return this._obj7;}
|
||||
if (p._keyId8 === keyId) {if (isBlank(this._obj8)){this._obj8 = this._new(p._binding8);} return this._obj8;}
|
||||
if (p._keyId9 === keyId) {if (isBlank(this._obj9)){this._obj9 = this._new(p._binding9);} return this._obj9;}
|
||||
if (p._keyId0 === keyId && (p._visibility0 & visibility) > 0) {if (isBlank(this._obj0)){this._obj0 = this._new(p._binding0);} return this._obj0;}
|
||||
if (p._keyId1 === keyId && (p._visibility1 & visibility) > 0) {if (isBlank(this._obj1)){this._obj1 = this._new(p._binding1);} return this._obj1;}
|
||||
if (p._keyId2 === keyId && (p._visibility2 & visibility) > 0) {if (isBlank(this._obj2)){this._obj2 = this._new(p._binding2);} return this._obj2;}
|
||||
if (p._keyId3 === keyId && (p._visibility3 & visibility) > 0) {if (isBlank(this._obj3)){this._obj3 = this._new(p._binding3);} return this._obj3;}
|
||||
if (p._keyId4 === keyId && (p._visibility4 & visibility) > 0) {if (isBlank(this._obj4)){this._obj4 = this._new(p._binding4);} return this._obj4;}
|
||||
if (p._keyId5 === keyId && (p._visibility5 & visibility) > 0) {if (isBlank(this._obj5)){this._obj5 = this._new(p._binding5);} return this._obj5;}
|
||||
if (p._keyId6 === keyId && (p._visibility6 & visibility) > 0) {if (isBlank(this._obj6)){this._obj6 = this._new(p._binding6);} return this._obj6;}
|
||||
if (p._keyId7 === keyId && (p._visibility7 & visibility) > 0) {if (isBlank(this._obj7)){this._obj7 = this._new(p._binding7);} return this._obj7;}
|
||||
if (p._keyId8 === keyId && (p._visibility8 & visibility) > 0) {if (isBlank(this._obj8)){this._obj8 = this._new(p._binding8);} return this._obj8;}
|
||||
if (p._keyId9 === keyId && (p._visibility9 & visibility) > 0) {if (isBlank(this._obj9)){this._obj9 = this._new(p._binding9);} return this._obj9;}
|
||||
|
||||
return _undefined;
|
||||
}
|
||||
|
||||
|
|
|
@ -319,7 +319,7 @@ function _createProtoElementInjector(binderIndex, parentPeiWithDistance, renderE
|
|||
// so that, when hydrating, $implicit can be set to the element.
|
||||
var hasVariables = MapWrapper.size(renderElementBinder.variableBindings) > 0;
|
||||
if (directiveBindings.length > 0 || hasVariables) {
|
||||
protoElementInjector = new ProtoElementInjector(
|
||||
protoElementInjector = ProtoElementInjector.create(
|
||||
parentPeiWithDistance.protoElementInjector, binderIndex,
|
||||
directiveBindings,
|
||||
isPresent(componentDirectiveBinding), parentPeiWithDistance.distance
|
||||
|
|
|
@ -189,7 +189,7 @@ export class AppViewManagerUtils {
|
|||
for (var i = 0; i < binders.length; ++i) {
|
||||
var elementInjector = view.elementInjectors[i];
|
||||
if (isPresent(elementInjector)) {
|
||||
elementInjector.instantiateDirectives(appInjector, hostElementInjector, view.preBuiltObjects[i]);
|
||||
elementInjector.hydrate(appInjector, hostElementInjector, view.preBuiltObjects[i]);
|
||||
this._setUpEventEmitters(view, elementInjector, i);
|
||||
this._setUpHostActions(view, elementInjector, i);
|
||||
|
||||
|
@ -238,7 +238,7 @@ export class AppViewManagerUtils {
|
|||
for (var i = 0; i < binders.length; ++i) {
|
||||
var elementInjector = view.elementInjectors[i];
|
||||
if (isPresent(elementInjector)) {
|
||||
elementInjector.clearDirectives();
|
||||
elementInjector.dehydrate();
|
||||
}
|
||||
}
|
||||
if (isPresent(view.locals)) {
|
||||
|
|
|
@ -91,7 +91,7 @@ export class Injector {
|
|||
* `fromResolvedBindings` and `createChildFromResolved`.
|
||||
*/
|
||||
static resolve(bindings: List<any>): List<ResolvedBinding> {
|
||||
var resolvedBindings = _resolveBindings(bindings);
|
||||
var resolvedBindings = resolveBindings(bindings);
|
||||
var flatten = _flattenBindings(resolvedBindings, MapWrapper.create());
|
||||
return _createListOfBindings(flatten);
|
||||
}
|
||||
|
@ -368,7 +368,7 @@ class _AsyncInjectorStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
function _resolveBindings(bindings: List<any>): List<ResolvedBinding> {
|
||||
export function resolveBindings(bindings: List<any>): List<ResolvedBinding> {
|
||||
var resolvedList = ListWrapper.createFixedSize(bindings.length);
|
||||
for (var i = 0; i < bindings.length; i++) {
|
||||
var unresolved = resolveForwardRef(bindings[i]);
|
||||
|
@ -380,7 +380,7 @@ function _resolveBindings(bindings: List<any>): List<ResolvedBinding> {
|
|||
} else if (unresolved instanceof Binding) {
|
||||
resolved = unresolved.resolve();
|
||||
} else if (unresolved instanceof List) {
|
||||
resolved = _resolveBindings(unresolved);
|
||||
resolved = resolveBindings(unresolved);
|
||||
} else if (unresolved instanceof BindingBuilder) {
|
||||
throw new InvalidBindingError(unresolved.token);
|
||||
} else {
|
||||
|
@ -391,6 +391,13 @@ function _resolveBindings(bindings: List<any>): List<ResolvedBinding> {
|
|||
return resolvedList;
|
||||
}
|
||||
|
||||
function flattenBindings(bindings: List<ResolvedBinding>): List<ResolvedBinding> {
|
||||
var map = _flattenBindings(bindings, MapWrapper.create());
|
||||
var res = ListWrapper.create();
|
||||
MapWrapper.forEach(map, (binding, keyId) => ListWrapper.push(res, binding));
|
||||
return res;
|
||||
}
|
||||
|
||||
function _createListOfBindings(flattenedBindings): List<any> {
|
||||
var bindings = ListWrapper.createFixedSize(Key.numberOfKeys + 1);
|
||||
MapWrapper.forEach(flattenedBindings, (v, keyId) => bindings[keyId] = v);
|
||||
|
|
|
@ -2,11 +2,11 @@ import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, SpyObj
|
|||
import {isBlank, isPresent, IMPLEMENTS} from 'angular2/src/facade/lang';
|
||||
import {ListWrapper, MapWrapper, List, StringMapWrapper, iterateListLike} from 'angular2/src/facade/collection';
|
||||
import {ProtoElementInjector, ElementInjector, PreBuiltObjects, DirectiveBinding, TreeNode}
|
||||
from 'angular2/src/core/compiler/element_injector';
|
||||
import {Parent, Ancestor} from 'angular2/src/core/annotations_impl/visibility';
|
||||
from 'angular2/src/core/compiler/element_injector';
|
||||
import {Parent, Ancestor, Unbounded} from 'angular2/src/core/annotations_impl/visibility';
|
||||
import {Attribute, Query} from 'angular2/src/core/annotations_impl/di';
|
||||
import {Component, Directive, onDestroy} from 'angular2/src/core/annotations_impl/annotations';
|
||||
import {bind, Injector} from 'angular2/di';
|
||||
import {bind, Injector, Binding} from 'angular2/di';
|
||||
import {Optional, Inject} from 'angular2/src/di/annotations_impl';
|
||||
import {AppProtoView, AppView} from 'angular2/src/core/compiler/view';
|
||||
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
|
||||
|
@ -16,8 +16,10 @@ import {DynamicChangeDetector, ChangeDetectorRef, Parser, Lexer} from 'angular2/
|
|||
import {ViewRef, Renderer} from 'angular2/src/render/api';
|
||||
import {QueryList} from 'angular2/src/core/compiler/query_list';
|
||||
|
||||
class DummyDirective extends Directive {
|
||||
constructor({lifecycle, events, hostActions} = {}) { super({lifecycle: lifecycle, events: events, hostActions:hostActions}); }
|
||||
class DummyDirective extends Component {
|
||||
constructor({lifecycle, events, hostActions, hostInjector, viewInjector} = {}) {
|
||||
super({lifecycle: lifecycle, events: events, hostActions: hostActions, hostInjector: hostInjector, viewInjector: viewInjector});
|
||||
}
|
||||
}
|
||||
|
||||
@proxy
|
||||
|
@ -37,6 +39,9 @@ class DummyView extends SpyObject {
|
|||
class SimpleDirective {
|
||||
}
|
||||
|
||||
class SimpleService {
|
||||
}
|
||||
|
||||
class SomeOtherDirective {
|
||||
}
|
||||
|
||||
|
@ -69,20 +74,27 @@ class OptionallyNeedsDirective {
|
|||
}
|
||||
}
|
||||
|
||||
class NeedDirectiveFromParent {
|
||||
class NeedsDirectiveFromParent {
|
||||
dependency:SimpleDirective;
|
||||
constructor(@Parent() dependency:SimpleDirective){
|
||||
this.dependency = dependency;
|
||||
}
|
||||
}
|
||||
|
||||
class NeedDirectiveFromAncestor {
|
||||
class NeedsDirectiveFromAncestor {
|
||||
dependency:SimpleDirective;
|
||||
constructor(@Ancestor() dependency:SimpleDirective){
|
||||
this.dependency = dependency;
|
||||
}
|
||||
}
|
||||
|
||||
class NeedsDirectiveFromAnAncestorShadowDom {
|
||||
dependency:SimpleDirective;
|
||||
constructor(@Unbounded() dependency:SimpleDirective){
|
||||
this.dependency = dependency;
|
||||
}
|
||||
}
|
||||
|
||||
class NeedsService {
|
||||
service:any;
|
||||
constructor(@Inject("service") service) {
|
||||
|
@ -199,10 +211,19 @@ export function main() {
|
|||
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null);
|
||||
var appInjector = Injector.resolveAndCreate([]);
|
||||
|
||||
function createPei(parent, index, bindings, distance = 1, hasShadowRoot = false) {
|
||||
var directiveBinding = ListWrapper.map(bindings, b => {
|
||||
if (b instanceof DirectiveBinding) return b;
|
||||
if (b instanceof Binding) return DirectiveBinding.createFromBinding(b, null);
|
||||
return DirectiveBinding.createFromType(b, null);
|
||||
});
|
||||
return ProtoElementInjector.create(parent, index, directiveBinding, hasShadowRoot, distance);
|
||||
}
|
||||
|
||||
function humanize(tree, names:List) {
|
||||
var lookupName = (item) =>
|
||||
ListWrapper.last(
|
||||
ListWrapper.find(names, (pair) => pair[0] === item));
|
||||
ListWrapper.last(
|
||||
ListWrapper.find(names, (pair) => pair[0] === item));
|
||||
|
||||
if (tree.children.length == 0) return lookupName(tree);
|
||||
var children = tree.children.map(m => humanize(m, names));
|
||||
|
@ -210,56 +231,46 @@ export function main() {
|
|||
}
|
||||
|
||||
function injector(bindings, lightDomAppInjector = null,
|
||||
isComponent:bool = false, preBuiltObjects = null, attributes = null) {
|
||||
isComponent:bool = false, preBuiltObjects = null, attributes = null) {
|
||||
if (isBlank(lightDomAppInjector)) lightDomAppInjector = appInjector;
|
||||
|
||||
var proto = new ProtoElementInjector(null, 0, bindings, isComponent);
|
||||
var proto = createPei(null, 0, bindings, 0, isComponent);
|
||||
proto.attributes = attributes;
|
||||
var inj = proto.instantiate(null);
|
||||
var preBuilt = isPresent(preBuiltObjects)
|
||||
? preBuiltObjects
|
||||
: defaultPreBuiltObjects;
|
||||
|
||||
inj.instantiateDirectives(lightDomAppInjector, null, preBuilt);
|
||||
var inj = proto.instantiate(null);
|
||||
var preBuilt = isPresent(preBuiltObjects) ? preBuiltObjects : defaultPreBuiltObjects;
|
||||
inj.hydrate(lightDomAppInjector, null, preBuilt);
|
||||
return inj;
|
||||
}
|
||||
|
||||
function parentChildInjectors(
|
||||
parentBindings,
|
||||
childBindings,
|
||||
parentPreBuildObjects = null,
|
||||
isParentComponent:bool = false) {
|
||||
function parentChildInjectors(parentBindings, childBindings, parentPreBuildObjects = null) {
|
||||
if (isBlank(parentPreBuildObjects)) parentPreBuildObjects = defaultPreBuiltObjects;
|
||||
|
||||
var inj = Injector.resolveAndCreate([]);
|
||||
|
||||
var protoParent = new ProtoElementInjector(null, 0, parentBindings, isParentComponent);
|
||||
|
||||
var protoParent = createPei(null, 0, parentBindings);
|
||||
var parent = protoParent.instantiate(null);
|
||||
|
||||
parent.instantiateDirectives(inj, null, parentPreBuildObjects);
|
||||
parent.hydrate(inj, null, parentPreBuildObjects);
|
||||
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, childBindings, false, 1);
|
||||
var protoChild = createPei(protoParent, 1, childBindings, 1, false);
|
||||
var child = protoChild.instantiate(parent);
|
||||
child.instantiateDirectives(inj, null, defaultPreBuiltObjects);
|
||||
child.hydrate(inj, null, defaultPreBuiltObjects);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
function hostShadowInjectors(
|
||||
hostBindings:List,
|
||||
shadowBindings:List,
|
||||
isParentComponent:bool = true,
|
||||
isChildComponent:bool = false):ElementInjector {
|
||||
function hostShadowInjectors(hostBindings:List, shadowBindings:List):ElementInjector {
|
||||
var inj = Injector.resolveAndCreate([]);
|
||||
|
||||
var protoParent = new ProtoElementInjector(null, 0, hostBindings, isParentComponent);
|
||||
var host = protoParent.instantiate(null);
|
||||
host.instantiateDirectives(inj, null, defaultPreBuiltObjects);
|
||||
var protoHost = createPei(null, 0, hostBindings, 0, true);
|
||||
var host = protoHost.instantiate(null);
|
||||
host.hydrate(inj, null, defaultPreBuiltObjects);
|
||||
|
||||
var protoChild = new ProtoElementInjector(protoParent, 0, shadowBindings,
|
||||
isChildComponent, 1);
|
||||
var shadow = protoChild.instantiate(null);
|
||||
shadow.instantiateDirectives(host.getShadowDomAppInjector(), host, null);
|
||||
var protoShadow = createPei(null, 0, shadowBindings, 0, false);
|
||||
var shadow = protoShadow.instantiate(null);
|
||||
shadow.hydrate(host.getShadowDomAppInjector(), host, null);
|
||||
|
||||
return shadow;
|
||||
}
|
||||
|
@ -268,13 +279,13 @@ export function main() {
|
|||
var root, firstParent, lastParent, node;
|
||||
|
||||
/*
|
||||
Build a tree of the following shape:
|
||||
root
|
||||
- p1
|
||||
- c1
|
||||
- c2
|
||||
- p2
|
||||
- c3
|
||||
Build a tree of the following shape:
|
||||
root
|
||||
- p1
|
||||
- c1
|
||||
- c2
|
||||
- p2
|
||||
- c3
|
||||
*/
|
||||
beforeEach(() => {
|
||||
root = new TestNode(null, 'root');
|
||||
|
@ -339,43 +350,45 @@ export function main() {
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
describe("ProtoElementInjector", () => {
|
||||
describe("direct parent", () => {
|
||||
it("should return parent proto injector when distance is 1", () => {
|
||||
var distance = 1;
|
||||
var protoParent = new ProtoElementInjector(null, 0, []);
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, [], false, distance);
|
||||
var protoParent = createPei(null, 0, []);
|
||||
var protoChild = createPei(protoParent, 0, [], distance, false);
|
||||
|
||||
expect(protoChild.directParent()).toEqual(protoParent);
|
||||
});
|
||||
|
||||
it("should return null otherwise", () => {
|
||||
var distance = 2;
|
||||
var protoParent = new ProtoElementInjector(null, 0, []);
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, [], false, distance);
|
||||
var protoParent = createPei(null, 0, []);
|
||||
var protoChild = createPei(protoParent, 0, [], distance, false);
|
||||
|
||||
expect(protoChild.directParent()).toEqual(null);
|
||||
});
|
||||
|
||||
it("should allow for direct access using getDirectiveBindingAtIndex", function () {
|
||||
it("should allow for direct access using getBindingAtIndex", function () {
|
||||
var binding = DirectiveBinding.createFromBinding(
|
||||
bind(SimpleDirective).toClass(SimpleDirective), null);
|
||||
var proto = new ProtoElementInjector(null, 0, [binding]);
|
||||
bind(SimpleDirective).toClass(SimpleDirective), null);
|
||||
var proto = createPei(null, 0, [binding]);
|
||||
|
||||
expect(proto.getDirectiveBindingAtIndex(0)).toBeAnInstanceOf(DirectiveBinding);
|
||||
expect(() => proto.getDirectiveBindingAtIndex(-1)).toThrowError(
|
||||
'Index -1 is out-of-bounds.');
|
||||
expect(() => proto.getDirectiveBindingAtIndex(10)).toThrowError(
|
||||
'Index 10 is out-of-bounds.');
|
||||
expect(proto.getBindingAtIndex(0)).toBeAnInstanceOf(DirectiveBinding);
|
||||
expect(() => proto.getBindingAtIndex(-1)).toThrowError(
|
||||
'Index -1 is out-of-bounds.');
|
||||
expect(() => proto.getBindingAtIndex(10)).toThrowError(
|
||||
'Index 10 is out-of-bounds.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('event emitters', () => {
|
||||
it('should return a list of event accessors', () => {
|
||||
var binding = DirectiveBinding.createFromType(
|
||||
HasEventEmitter, new DummyDirective({events: ['emitter']}));
|
||||
HasEventEmitter, new DummyDirective({events: ['emitter']}));
|
||||
|
||||
var inj = new ProtoElementInjector(null, 0, [binding]);
|
||||
var inj = createPei(null, 0, [binding]);
|
||||
expect(inj.eventEmitterAccessors.length).toEqual(1);
|
||||
|
||||
var accessor = inj.eventEmitterAccessors[0][0];
|
||||
|
@ -385,9 +398,9 @@ export function main() {
|
|||
|
||||
it('should return a list of hostAction accessors', () => {
|
||||
var binding = DirectiveBinding.createFromType(
|
||||
HasEventEmitter, new DummyDirective({hostActions: {'hostActionName' : 'onAction'}}));
|
||||
HasEventEmitter, new DummyDirective({hostActions: {'hostActionName' : 'onAction'}}));
|
||||
|
||||
var inj = new ProtoElementInjector(null, 0, [binding]);
|
||||
var inj = createPei(null, 0, [binding]);
|
||||
expect(inj.hostActionAccessors.length).toEqual(1);
|
||||
|
||||
var accessor = inj.hostActionAccessors[0][0];
|
||||
|
@ -395,14 +408,41 @@ export function main() {
|
|||
expect(accessor.getter(new HasHostAction())).toEqual('hostAction');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe(".create", () => {
|
||||
it("should collect hostInjector injectables from all directives", () => {
|
||||
var pei = createPei(null, 0, [
|
||||
DirectiveBinding.createFromType(SimpleDirective,
|
||||
new DummyDirective({hostInjector: [bind('injectable1').toValue('injectable1')]})),
|
||||
DirectiveBinding.createFromType(SomeOtherDirective,
|
||||
new DummyDirective({hostInjector: [bind('injectable2').toValue('injectable2')]}))
|
||||
]);
|
||||
|
||||
expect(pei.getBindingAtIndex(0).key.token).toBe(SimpleDirective);
|
||||
expect(pei.getBindingAtIndex(1).key.token).toBe(SomeOtherDirective);
|
||||
expect(pei.getBindingAtIndex(2).key.token).toEqual("injectable1");
|
||||
expect(pei.getBindingAtIndex(3).key.token).toEqual("injectable2");
|
||||
});
|
||||
|
||||
it("should collect viewInjector injectables from the component", () => {
|
||||
var pei = createPei(null, 0, [
|
||||
DirectiveBinding.createFromType(SimpleDirective,
|
||||
new DummyDirective({viewInjector: [bind('injectable1').toValue('injectable1')]}))
|
||||
], 0, true);
|
||||
|
||||
expect(pei.getBindingAtIndex(0).key.token).toBe(SimpleDirective);
|
||||
expect(pei.getBindingAtIndex(1).key.token).toEqual("injectable1");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("ElementInjector", function () {
|
||||
describe("instantiate", function () {
|
||||
it("should create an element injector", function () {
|
||||
var protoParent = new ProtoElementInjector(null, 0, []);
|
||||
var protoChild1 = new ProtoElementInjector(protoParent, 1, []);
|
||||
var protoChild2 = new ProtoElementInjector(protoParent, 2, []);
|
||||
var protoParent = createPei(null, 0, []);
|
||||
var protoChild1 = createPei(protoParent, 1, []);
|
||||
var protoChild2 = createPei(protoParent, 2, []);
|
||||
|
||||
var p = protoParent.instantiate(null);
|
||||
var c1 = protoChild1.instantiate(p);
|
||||
|
@ -418,8 +458,8 @@ export function main() {
|
|||
describe("direct parent", () => {
|
||||
it("should return parent injector when distance is 1", () => {
|
||||
var distance = 1;
|
||||
var protoParent = new ProtoElementInjector(null, 0, []);
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, [], false, distance);
|
||||
var protoParent = createPei(null, 0, []);
|
||||
var protoChild = createPei(protoParent, 1, [], distance);
|
||||
|
||||
var p = protoParent.instantiate(null);
|
||||
var c = protoChild.instantiate(p);
|
||||
|
@ -429,8 +469,8 @@ export function main() {
|
|||
|
||||
it("should return null otherwise", () => {
|
||||
var distance = 2;
|
||||
var protoParent = new ProtoElementInjector(null, 0, []);
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, [], false, distance);
|
||||
var protoParent = createPei(null, 0, []);
|
||||
var protoChild = createPei(protoParent, 1, [], distance);
|
||||
|
||||
var p = protoParent.instantiate(null);
|
||||
var c = protoChild.instantiate(p);
|
||||
|
@ -442,12 +482,12 @@ export function main() {
|
|||
|
||||
describe("hasBindings", function () {
|
||||
it("should be true when there are bindings", function () {
|
||||
var p = new ProtoElementInjector(null, 0, [SimpleDirective]);
|
||||
var p = createPei(null, 0, [SimpleDirective]);
|
||||
expect(p.hasBindings).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should be false otherwise", function () {
|
||||
var p = new ProtoElementInjector(null, 0, []);
|
||||
var p = createPei(null, 0, []);
|
||||
expect(p.hasBindings).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
@ -462,7 +502,7 @@ export function main() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("instantiateDirectives", function () {
|
||||
describe("hydrate", function () {
|
||||
it("should instantiate directives that have no dependencies", function () {
|
||||
var inj = injector([SimpleDirective]);
|
||||
expect(inj.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective);
|
||||
|
@ -495,52 +535,6 @@ export function main() {
|
|||
expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView));
|
||||
});
|
||||
|
||||
it("should instantiate directives that depend on the containing component", function () {
|
||||
var directiveBinding = DirectiveBinding.createFromType(SimpleDirective, new Component());
|
||||
var shadow = hostShadowInjectors([directiveBinding], [NeedsDirective]);
|
||||
|
||||
var d = shadow.get(NeedsDirective);
|
||||
expect(d).toBeAnInstanceOf(NeedsDirective);
|
||||
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
||||
});
|
||||
|
||||
it("should not instantiate directives that depend on other directives in the containing component's ElementInjector", () => {
|
||||
var directiveBinding = DirectiveBinding
|
||||
.createFromType(SomeOtherDirective, new Component());
|
||||
expect(() => {
|
||||
hostShadowInjectors(
|
||||
[directiveBinding, SimpleDirective],
|
||||
[NeedsDirective]);
|
||||
}).toThrowError('No provider for SimpleDirective! (NeedsDirective -> SimpleDirective)');
|
||||
});
|
||||
|
||||
it("should instantiate component directives that depend on app services in the shadow app injector", () => {
|
||||
var directiveAnnotation = new Component({
|
||||
appInjector: [
|
||||
bind("service").toValue("service")
|
||||
]
|
||||
});
|
||||
var componentDirective = DirectiveBinding.createFromType(
|
||||
NeedsService, directiveAnnotation);
|
||||
var inj = injector([componentDirective], null, true);
|
||||
|
||||
var d = inj.get(NeedsService);
|
||||
expect(d).toBeAnInstanceOf(NeedsService);
|
||||
expect(d.service).toEqual("service");
|
||||
});
|
||||
|
||||
it("should not instantiate other directives that depend on app services in the shadow app injector", () => {
|
||||
var directiveAnnotation = new Component({
|
||||
appInjector: [
|
||||
bind("service").toValue("service")
|
||||
]
|
||||
});
|
||||
var componentDirective = DirectiveBinding.createFromType(SimpleDirective, directiveAnnotation);
|
||||
expect(() => {
|
||||
injector([componentDirective, NeedsService], null);
|
||||
}).toThrowError('No provider for service! (NeedsService -> service)');
|
||||
});
|
||||
|
||||
it("should return app services", function () {
|
||||
var appInjector = Injector.resolveAndCreate([
|
||||
bind("service").toValue("service")
|
||||
|
@ -551,41 +545,51 @@ export function main() {
|
|||
});
|
||||
|
||||
it("should get directives from parent", function () {
|
||||
var child = parentChildInjectors([SimpleDirective], [NeedDirectiveFromParent]);
|
||||
var child = parentChildInjectors([SimpleDirective], [NeedsDirectiveFromParent]);
|
||||
|
||||
var d = child.get(NeedDirectiveFromParent);
|
||||
var d = child.get(NeedsDirectiveFromParent);
|
||||
|
||||
expect(d).toBeAnInstanceOf(NeedDirectiveFromParent);
|
||||
expect(d).toBeAnInstanceOf(NeedsDirectiveFromParent);
|
||||
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
||||
});
|
||||
|
||||
it("should not return parent's directives on self", function () {
|
||||
expect(() => {
|
||||
injector([SimpleDirective, NeedDirectiveFromParent]);
|
||||
injector([SimpleDirective, NeedsDirectiveFromParent]);
|
||||
}).toThrowError(new RegExp("No provider for SimpleDirective"));
|
||||
});
|
||||
|
||||
it("should get directives from ancestor", function () {
|
||||
var child = parentChildInjectors([SimpleDirective], [NeedDirectiveFromAncestor]);
|
||||
var child = parentChildInjectors([SimpleDirective], [NeedsDirectiveFromAncestor]);
|
||||
|
||||
var d = child.get(NeedDirectiveFromAncestor);
|
||||
var d = child.get(NeedsDirectiveFromAncestor);
|
||||
|
||||
expect(d).toBeAnInstanceOf(NeedDirectiveFromAncestor);
|
||||
expect(d).toBeAnInstanceOf(NeedsDirectiveFromAncestor);
|
||||
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
||||
});
|
||||
|
||||
it("should throw when no SimpleDirective found", function () {
|
||||
expect(() => injector([NeedDirectiveFromParent])).
|
||||
toThrowError('No provider for SimpleDirective! (NeedDirectiveFromParent -> SimpleDirective)');
|
||||
it("should get directives crossing the boundaries", function () {
|
||||
var child = hostShadowInjectors([SomeOtherDirective, SimpleDirective],
|
||||
[NeedsDirectiveFromAnAncestorShadowDom]);
|
||||
|
||||
var d = child.get(NeedsDirectiveFromAnAncestorShadowDom);
|
||||
|
||||
expect(d).toBeAnInstanceOf(NeedsDirectiveFromAnAncestorShadowDom);
|
||||
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
||||
});
|
||||
|
||||
it("should inject null when no directive found", function () {
|
||||
it("should throw when a depenency cannot be resolved", function () {
|
||||
expect(() => injector([NeedsDirectiveFromParent])).
|
||||
toThrowError('No provider for SimpleDirective! (NeedsDirectiveFromParent -> SimpleDirective)');
|
||||
});
|
||||
|
||||
it("should inject null when an optional dependency cannot be resolved", function () {
|
||||
var inj = injector([OptionallyNeedsDirective]);
|
||||
var d = inj.get(OptionallyNeedsDirective);
|
||||
expect(d.dependency).toEqual(null);
|
||||
});
|
||||
|
||||
it("should accept SimpleDirective bindings instead of SimpleDirective types", function () {
|
||||
it("should accept bindings instead types", function () {
|
||||
var inj = injector([
|
||||
DirectiveBinding.createFromBinding(bind(SimpleDirective).toClass(SimpleDirective), null)
|
||||
]);
|
||||
|
@ -598,11 +602,12 @@ export function main() {
|
|||
]);
|
||||
expect(inj.getDirectiveAtIndex(0)).toBeAnInstanceOf(SimpleDirective);
|
||||
expect(() => inj.getDirectiveAtIndex(-1)).toThrowError(
|
||||
'Index -1 is out-of-bounds.');
|
||||
'Index -1 is out-of-bounds.');
|
||||
expect(() => inj.getDirectiveAtIndex(10)).toThrowError(
|
||||
'Index 10 is out-of-bounds.');
|
||||
'Index 10 is out-of-bounds.');
|
||||
});
|
||||
|
||||
|
||||
it("should handle cyclic dependencies", function () {
|
||||
expect(() => {
|
||||
var bAneedsB = bind(A_Needs_B).toFactory((a) => new A_Needs_B(a), [B_Needs_A]);
|
||||
|
@ -612,56 +617,107 @@ export function main() {
|
|||
DirectiveBinding.createFromBinding(bBneedsA, null)
|
||||
]);
|
||||
}).toThrowError('Cannot instantiate cyclic dependency! ' +
|
||||
'(A_Needs_B -> B_Needs_A -> A_Needs_B)');
|
||||
'(A_Needs_B -> B_Needs_A -> A_Needs_B)');
|
||||
});
|
||||
|
||||
describe("shadow DOM components", () => {
|
||||
it("should instantiate directives that depend on the containing component", function () {
|
||||
var directiveBinding = DirectiveBinding.createFromType(SimpleDirective, new Component());
|
||||
var shadow = hostShadowInjectors([directiveBinding], [NeedsDirective]);
|
||||
|
||||
var d = shadow.get(NeedsDirective);
|
||||
expect(d).toBeAnInstanceOf(NeedsDirective);
|
||||
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
||||
});
|
||||
|
||||
it("should not instantiate directives that depend on other directives in the containing component's ElementInjector", () => {
|
||||
var directiveBinding = DirectiveBinding.createFromType(SomeOtherDirective, new Component());
|
||||
expect(() => {
|
||||
hostShadowInjectors([directiveBinding, SimpleDirective],[NeedsDirective]);
|
||||
}).toThrowError('No provider for SimpleDirective! (NeedsDirective -> SimpleDirective)');
|
||||
});
|
||||
|
||||
it("should instantiate component directives that depend on app services in the shadow app injector", () => {
|
||||
var directiveAnnotation = new Component({
|
||||
appInjector: [
|
||||
bind("service").toValue("service")
|
||||
]
|
||||
});
|
||||
var componentDirective = DirectiveBinding.createFromType(
|
||||
NeedsService, directiveAnnotation);
|
||||
var inj = injector([componentDirective], null, true);
|
||||
|
||||
var d = inj.get(NeedsService);
|
||||
expect(d).toBeAnInstanceOf(NeedsService);
|
||||
expect(d.service).toEqual("service");
|
||||
});
|
||||
|
||||
it("should not instantiate other directives that depend on app services in the shadow app injector", () => {
|
||||
var directiveAnnotation = new Component({
|
||||
appInjector: [
|
||||
bind("service").toValue("service")
|
||||
]
|
||||
});
|
||||
var componentDirective = DirectiveBinding.createFromType(SimpleDirective, directiveAnnotation);
|
||||
expect(() => {
|
||||
injector([componentDirective, NeedsService], null);
|
||||
}).toThrowError('No provider for service! (NeedsService -> service)');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("lifecycle", () => {
|
||||
it("should call onDestroy on directives subscribed to this event", function() {
|
||||
var inj = injector([DirectiveBinding.createFromType(
|
||||
DirectiveWithDestroy,
|
||||
new DummyDirective({lifecycle: [onDestroy]}))]);
|
||||
var inj = injector([DirectiveBinding.createFromType(DirectiveWithDestroy, new DummyDirective({lifecycle: [onDestroy]}))]);
|
||||
var destroy = inj.get(DirectiveWithDestroy);
|
||||
inj.clearDirectives();
|
||||
inj.dehydrate();
|
||||
expect(destroy.onDestroyCounter).toBe(1);
|
||||
});
|
||||
|
||||
it("should work with services", function() {
|
||||
var inj = injector([DirectiveBinding.createFromType(SimpleDirective, new DummyDirective({hostInjector: [SimpleService]}))]);
|
||||
inj.dehydrate();
|
||||
});
|
||||
});
|
||||
|
||||
describe("dynamicallyCreateComponent", () => {
|
||||
it("should create a component dynamically", () => {
|
||||
var inj = injector([]);
|
||||
inj.dynamicallyCreateComponent(DirectiveBinding.createFromType(SimpleDirective, null), null);
|
||||
|
||||
inj.dynamicallyCreateComponent(DirectiveBinding.createFromType(SimpleDirective, null), appInjector);
|
||||
expect(inj.getDynamicallyLoadedComponent()).toBeAnInstanceOf(SimpleDirective);
|
||||
expect(inj.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective);
|
||||
});
|
||||
|
||||
it("should inject parent dependencies into the dynamically-loaded component", () => {
|
||||
var inj = parentChildInjectors([SimpleDirective], []);
|
||||
inj.dynamicallyCreateComponent(DirectiveBinding.createFromType(NeedDirectiveFromAncestor, null), null);
|
||||
expect(inj.getDynamicallyLoadedComponent()).toBeAnInstanceOf(NeedDirectiveFromAncestor);
|
||||
inj.dynamicallyCreateComponent(DirectiveBinding.createFromType(NeedsDirectiveFromAncestor, null), appInjector);
|
||||
expect(inj.getDynamicallyLoadedComponent()).toBeAnInstanceOf(NeedsDirectiveFromAncestor);
|
||||
expect(inj.getDynamicallyLoadedComponent().dependency).toBeAnInstanceOf(SimpleDirective);
|
||||
});
|
||||
|
||||
it("should not inject the proxy component into the children of the dynamically-loaded component", () => {
|
||||
var injWithDynamicallyLoadedComponent = injector([SimpleDirective]);
|
||||
injWithDynamicallyLoadedComponent.dynamicallyCreateComponent(DirectiveBinding.createFromType(SomeOtherDirective, null), null);
|
||||
injWithDynamicallyLoadedComponent.dynamicallyCreateComponent(DirectiveBinding.createFromType(SomeOtherDirective, null), appInjector);
|
||||
|
||||
var shadowDomProtoInjector = new ProtoElementInjector(null, 0, [NeedDirectiveFromAncestor], false);
|
||||
var shadowDomProtoInjector = createPei(null, 0, [NeedsDirectiveFromAncestor]);
|
||||
var shadowDomInj = shadowDomProtoInjector.instantiate(null);
|
||||
|
||||
expect(() =>
|
||||
shadowDomInj.instantiateDirectives(appInjector, injWithDynamicallyLoadedComponent, defaultPreBuiltObjects)).
|
||||
toThrowError(new RegExp("No provider for SimpleDirective"));
|
||||
shadowDomInj.hydrate(appInjector, injWithDynamicallyLoadedComponent, defaultPreBuiltObjects)).
|
||||
toThrowError(new RegExp("No provider for SimpleDirective"));
|
||||
});
|
||||
|
||||
it("should not inject the dynamically-loaded component into directives on the same element", () => {
|
||||
var dynamicComp = DirectiveBinding.createFromType(SomeOtherDirective, new Component());
|
||||
var proto = new ProtoElementInjector(null, 0, [dynamicComp, NeedsDirective], true);
|
||||
var proto = createPei(null, 0, [dynamicComp, NeedsDirective], 1, true);
|
||||
var inj = proto.instantiate(null);
|
||||
inj.dynamicallyCreateComponent(
|
||||
DirectiveBinding.createFromType(SimpleDirective, null), null);
|
||||
DirectiveBinding.createFromType(SimpleDirective, null), appInjector);
|
||||
|
||||
var error = null;
|
||||
try {
|
||||
inj.instantiateDirectives(Injector.resolveAndCreate([]), null, null);
|
||||
inj.hydrate(Injector.resolveAndCreate([]), null, null);
|
||||
} catch(e) {
|
||||
error = e;
|
||||
}
|
||||
|
@ -672,32 +728,32 @@ export function main() {
|
|||
it("should inject the dynamically-loaded component into the children of the dynamically-loaded component", () => {
|
||||
var componentDirective = DirectiveBinding.createFromType(SimpleDirective, null);
|
||||
var injWithDynamicallyLoadedComponent = injector([]);
|
||||
injWithDynamicallyLoadedComponent.dynamicallyCreateComponent(componentDirective, null);
|
||||
injWithDynamicallyLoadedComponent.dynamicallyCreateComponent(componentDirective, appInjector);
|
||||
|
||||
var shadowDomProtoInjector = new ProtoElementInjector(null, 0, [NeedDirectiveFromAncestor], false);
|
||||
var shadowDomProtoInjector = createPei(null, 0, [NeedsDirectiveFromAncestor]);
|
||||
var shadowDomInjector = shadowDomProtoInjector.instantiate(null);
|
||||
shadowDomInjector.instantiateDirectives(appInjector, injWithDynamicallyLoadedComponent, defaultPreBuiltObjects);
|
||||
shadowDomInjector.hydrate(appInjector, injWithDynamicallyLoadedComponent, defaultPreBuiltObjects);
|
||||
|
||||
expect(shadowDomInjector.get(NeedDirectiveFromAncestor)).toBeAnInstanceOf(NeedDirectiveFromAncestor);
|
||||
expect(shadowDomInjector.get(NeedDirectiveFromAncestor).dependency).toBeAnInstanceOf(SimpleDirective);
|
||||
expect(shadowDomInjector.get(NeedsDirectiveFromAncestor)).toBeAnInstanceOf(NeedsDirectiveFromAncestor);
|
||||
expect(shadowDomInjector.get(NeedsDirectiveFromAncestor).dependency).toBeAnInstanceOf(SimpleDirective);
|
||||
});
|
||||
|
||||
it("should remove the dynamically-loaded component when dehydrating", () => {
|
||||
var inj = injector([]);
|
||||
inj.dynamicallyCreateComponent(
|
||||
DirectiveBinding.createFromType(
|
||||
DirectiveWithDestroy,
|
||||
new DummyDirective({lifecycle: [onDestroy]})
|
||||
),
|
||||
null);
|
||||
DirectiveBinding.createFromType(
|
||||
DirectiveWithDestroy,
|
||||
new DummyDirective({lifecycle: [onDestroy]})
|
||||
),
|
||||
appInjector);
|
||||
var dir = inj.getDynamicallyLoadedComponent();
|
||||
|
||||
inj.clearDirectives();
|
||||
inj.dehydrate();
|
||||
|
||||
expect(inj.getDynamicallyLoadedComponent()).toBe(null);
|
||||
expect(dir.onDestroyCounter).toBe(1);
|
||||
|
||||
inj.instantiateDirectives(null, null, null);
|
||||
inj.hydrate(null, null, null);
|
||||
|
||||
expect(inj.getDynamicallyLoadedComponent()).toBe(null);
|
||||
});
|
||||
|
@ -766,7 +822,7 @@ export function main() {
|
|||
|
||||
it("should throw if there is no ProtoViewRef", function () {
|
||||
expect(
|
||||
() => injector([NeedsProtoViewRef])
|
||||
() => injector([NeedsProtoViewRef])
|
||||
).toThrowError('No provider for ProtoViewRef! (NeedsProtoViewRef -> ProtoViewRef)');
|
||||
});
|
||||
|
||||
|
@ -814,25 +870,25 @@ export function main() {
|
|||
//});
|
||||
|
||||
it('should contain directives on the same and a child injector in construction order', () => {
|
||||
var protoParent = new ProtoElementInjector(null, 0, [NeedsQuery, CountingDirective]);
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, [CountingDirective]);
|
||||
var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]);
|
||||
var protoChild = createPei(protoParent, 1, [CountingDirective]);
|
||||
|
||||
var parent = protoParent.instantiate(null);
|
||||
var child = protoChild.instantiate(parent);
|
||||
parent.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
parent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
|
||||
expectDirectives(parent.get(NeedsQuery).query, CountingDirective, [0,1]);
|
||||
});
|
||||
|
||||
it('should reflect unlinking an injector', () => {
|
||||
var protoParent = new ProtoElementInjector(null, 0, [NeedsQuery, CountingDirective]);
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, [CountingDirective]);
|
||||
var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]);
|
||||
var protoChild = createPei(protoParent, 1, [CountingDirective]);
|
||||
|
||||
var parent = protoParent.instantiate(null);
|
||||
var child = protoChild.instantiate(parent);
|
||||
parent.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
parent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
|
||||
child.unlink();
|
||||
|
||||
|
@ -840,17 +896,17 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should reflect moving an injector as a last child', () => {
|
||||
var protoParent = new ProtoElementInjector(null, 0, [NeedsQuery, CountingDirective]);
|
||||
var protoChild1 = new ProtoElementInjector(protoParent, 1, [CountingDirective]);
|
||||
var protoChild2 = new ProtoElementInjector(protoParent, 1, [CountingDirective]);
|
||||
var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]);
|
||||
var protoChild1 = createPei(protoParent, 1, [CountingDirective]);
|
||||
var protoChild2 = createPei(protoParent, 1, [CountingDirective]);
|
||||
|
||||
var parent = protoParent.instantiate(null);
|
||||
var child1 = protoChild1.instantiate(parent);
|
||||
var child2 = protoChild2.instantiate(parent);
|
||||
|
||||
parent.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child1.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child2.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
parent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child1.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child2.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
|
||||
child1.unlink();
|
||||
child1.link(parent);
|
||||
|
@ -860,17 +916,17 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should reflect moving an injector as a first child', () => {
|
||||
var protoParent = new ProtoElementInjector(null, 0, [NeedsQuery, CountingDirective]);
|
||||
var protoChild1 = new ProtoElementInjector(protoParent, 1, [CountingDirective]);
|
||||
var protoChild2 = new ProtoElementInjector(protoParent, 1, [CountingDirective]);
|
||||
var protoParent = createPei(null, 0, [NeedsQuery, CountingDirective]);
|
||||
var protoChild1 = createPei(protoParent, 1, [CountingDirective]);
|
||||
var protoChild2 = createPei(protoParent, 1, [CountingDirective]);
|
||||
|
||||
var parent = protoParent.instantiate(null);
|
||||
var child1 = protoChild1.instantiate(parent);
|
||||
var child2 = protoChild2.instantiate(parent);
|
||||
|
||||
parent.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child1.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child2.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
parent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child1.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child2.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
|
||||
child2.unlink();
|
||||
child2.linkAfter(parent, null);
|
||||
|
@ -880,17 +936,17 @@ export function main() {
|
|||
});
|
||||
|
||||
it('should support two concurrent queries for the same directive', () => {
|
||||
var protoGrandParent = new ProtoElementInjector(null, 0, [NeedsQuery]);
|
||||
var protoParent = new ProtoElementInjector(null, 0, [NeedsQuery]);
|
||||
var protoChild = new ProtoElementInjector(protoParent, 1, [CountingDirective]);
|
||||
var protoGrandParent = createPei(null, 0, [NeedsQuery]);
|
||||
var protoParent = createPei(null, 0, [NeedsQuery]);
|
||||
var protoChild = createPei(protoParent, 1, [CountingDirective]);
|
||||
|
||||
var grandParent = protoGrandParent.instantiate(null);
|
||||
var parent = protoParent.instantiate(grandParent);
|
||||
var child = protoChild.instantiate(parent);
|
||||
|
||||
grandParent.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
parent.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child.instantiateDirectives(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
grandParent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
parent.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
child.hydrate(Injector.resolveAndCreate([]), null, preBuildObjects);
|
||||
|
||||
var queryList1 = grandParent.get(NeedsQuery).query;
|
||||
var queryList2 = parent.get(NeedsQuery).query;
|
||||
|
|
|
@ -29,7 +29,7 @@ import {PipeRegistry, defaultPipeRegistry,
|
|||
import {Directive, Component} from 'angular2/src/core/annotations_impl/annotations';
|
||||
import {QueryList} from 'angular2/src/core/compiler/query_list';
|
||||
import {View} from 'angular2/src/core/annotations_impl/view';
|
||||
import {Parent, Ancestor} from 'angular2/src/core/annotations_impl/visibility';
|
||||
import {Parent, Ancestor, Unbounded} from 'angular2/src/core/annotations_impl/visibility';
|
||||
import {Attribute, Query} from 'angular2/src/core/annotations_impl/di';
|
||||
|
||||
import {NgIf} from 'angular2/src/directives/ng_if';
|
||||
|
@ -822,6 +822,68 @@ export function main() {
|
|||
}));
|
||||
});
|
||||
|
||||
describe("dependency injection", () => {
|
||||
it("should support hostInjector", inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideView(MyComp, new View({
|
||||
template: `
|
||||
<directive-providing-injectable>
|
||||
<directive-consuming-injectable #consuming>
|
||||
</directive-consuming-injectable>
|
||||
</directive-providing-injectable>
|
||||
`,
|
||||
directives: [DirectiveProvidingInjectable, DirectiveConsumingInjectable]
|
||||
}));
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
var comp = view.rawView.locals.get("consuming");
|
||||
expect(comp.injectable).toBeAnInstanceOf(Injectable);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should support viewInjector", inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideView(DirectiveProvidingInjectableInView, new View({
|
||||
template: `
|
||||
<directive-consuming-injectable #consuming>
|
||||
</directive-consuming-injectable>
|
||||
`,
|
||||
directives: [DirectiveConsumingInjectable]
|
||||
}));
|
||||
tb.createView(DirectiveProvidingInjectableInView, {context: new DirectiveProvidingInjectableInView()}).then((view) => {
|
||||
var comp = view.rawView.locals.get("consuming");
|
||||
expect(comp.injectable).toBeAnInstanceOf(Injectable);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it("should support unbounded lookup", inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideView(MyComp, new View({
|
||||
template: `
|
||||
<directive-providing-injectable>
|
||||
<directive-containing-directive-consuming-an-injectable #dir>
|
||||
</directive-containing-directive-consuming-an-injectable>
|
||||
</directive-providing-injectable>
|
||||
`,
|
||||
directives: [DirectiveProvidingInjectable, DirectiveContainingDirectiveConsumingAnInjectable]
|
||||
}));
|
||||
|
||||
tb.overrideView(DirectiveContainingDirectiveConsumingAnInjectable, new View({
|
||||
template: `
|
||||
<directive-consuming-injectable-unbounded></directive-consuming-injectable-unbounded>
|
||||
`,
|
||||
directives: [DirectiveConsumingInjectableUnbounded]
|
||||
}));
|
||||
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
var comp = view.rawView.locals.get("dir");
|
||||
expect(comp.directive.injectable).toBeAnInstanceOf(Injectable);
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe("error handling", () => {
|
||||
it('should report a meaningful error when a directive is missing annotation',
|
||||
inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
|
@ -1477,3 +1539,57 @@ class DirectiveWithTwoWayBinding {
|
|||
ObservableWrapper.callNext(this.control, value);
|
||||
}
|
||||
}
|
||||
|
||||
class Injectable {}
|
||||
|
||||
@Directive({
|
||||
selector: 'directive-providing-injectable',
|
||||
hostInjector: [Injectable]
|
||||
})
|
||||
class DirectiveProvidingInjectable {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'directive-providing-injectable',
|
||||
viewInjector: [Injectable]
|
||||
})
|
||||
@View({template:''})
|
||||
class DirectiveProvidingInjectableInView {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'directive-consuming-injectable'
|
||||
})
|
||||
@View({template:''})
|
||||
class DirectiveConsumingInjectable {
|
||||
injectable;
|
||||
|
||||
constructor(@Ancestor() injectable:Injectable) {
|
||||
this.injectable = injectable;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'directive-containing-directive-consuming-an-injectable'
|
||||
})
|
||||
class DirectiveContainingDirectiveConsumingAnInjectable {
|
||||
directive;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'directive-consuming-injectable-unbounded'
|
||||
})
|
||||
@View({template:''})
|
||||
class DirectiveConsumingInjectableUnbounded {
|
||||
injectable;
|
||||
|
||||
constructor(
|
||||
@Unbounded() injectable:Injectable,
|
||||
@Ancestor() parent:DirectiveContainingDirectiveConsumingAnInjectable) {
|
||||
|
||||
this.injectable = injectable;
|
||||
parent.directive = this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,14 +131,14 @@ export function main() {
|
|||
|
||||
// (() => () nonsense is required until our transpiler supports type casting
|
||||
var spyEi = (() => componentView.elementInjectors[0])();
|
||||
spyEi.spy('instantiateDirectives').andCallFake(log.fn('instantiateDirectives'));
|
||||
spyEi.spy('hydrate').andCallFake(log.fn('hydrate'));
|
||||
|
||||
var spyCd = (() => componentView.changeDetector)();
|
||||
spyCd.spy('hydrate').andCallFake(log.fn('hydrateCD'));
|
||||
|
||||
utils.hydrateComponentView(hostView, 0)
|
||||
|
||||
expect(log.result()).toEqual('instantiateDirectives; hydrateCD');
|
||||
expect(log.result()).toEqual('hydrate; hydrateCD');
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -261,7 +261,7 @@ export function main() {
|
|||
createViews();
|
||||
|
||||
utils.hydrateViewInContainer(parentView, 0, contextView, 0, 0, null);
|
||||
expect(childView.rootElementInjectors[0].spy('instantiateDirectives'))
|
||||
expect(childView.rootElementInjectors[0].spy('hydrate'))
|
||||
.toHaveBeenCalledWith(null, contextView.elementInjectors[0].getHost(), childView.preBuiltObjects[0]);
|
||||
});
|
||||
|
||||
|
@ -282,7 +282,7 @@ export function main() {
|
|||
createViews();
|
||||
|
||||
utils.hydrateRootHostView(hostView, injector);
|
||||
expect(hostView.rootElementInjectors[0].spy('instantiateDirectives'))
|
||||
expect(hostView.rootElementInjectors[0].spy('hydrate'))
|
||||
.toHaveBeenCalledWith(injector, null, hostView.preBuiltObjects[0]);
|
||||
});
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ export function main() {
|
|||
|
||||
@Component({
|
||||
selector: 'app',
|
||||
injectables: [
|
||||
appInjector: [
|
||||
forwardRef(() => Frame)
|
||||
]
|
||||
})
|
||||
|
|
|
@ -20,11 +20,11 @@ describe('ng2 element injector benchmark', function () {
|
|||
}).then(done, done.fail);
|
||||
});
|
||||
|
||||
it('should log the stats for instantiateDirectives', function(done) {
|
||||
it('should log the stats for hydrate', function(done) {
|
||||
perfUtil.runClickBenchmark({
|
||||
url: URL,
|
||||
buttons: ['#instantiateDirectives'],
|
||||
id: 'ng2.elementInjector.instantiateDirectives',
|
||||
buttons: ['#hydrate'],
|
||||
id: 'ng2.elementInjector.hydrate',
|
||||
params: [{
|
||||
name: 'iterations', value: 20000, scale: 'linear'
|
||||
}],
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<h2>Actions</h2>
|
||||
<p>
|
||||
<button id="instantiate">instantiate</button>
|
||||
<button id="instantiateDirectives">instantiateDirectives</button>
|
||||
<button id="hydrate">hydrate</button>
|
||||
</p>
|
||||
|
||||
$SCRIPTS$
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {reflector} from 'angular2/src/reflection/reflection';
|
||||
import {ReflectionCapabilities} from 'angular2/src/reflection/reflection_capabilities';
|
||||
import {Injectable, Injector} from 'angular2/di';
|
||||
import {ProtoElementInjector} from 'angular2/src/core/compiler/element_injector';
|
||||
import {ProtoElementInjector, DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
|
||||
import {getIntParameter, bindAction, microBenchmark} from 'angular2/src/test_lib/benchmark_util';
|
||||
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
|
||||
|
||||
|
@ -14,21 +14,25 @@ export function main() {
|
|||
reflector.reflectionCapabilities = new ReflectionCapabilities();
|
||||
var appInjector = Injector.resolveAndCreate([]);
|
||||
|
||||
var bindings = [A, B, C];
|
||||
var proto = new ProtoElementInjector(null, 0, bindings);
|
||||
var bindings = [
|
||||
DirectiveBinding.createFromType(A, null),
|
||||
DirectiveBinding.createFromType(B, null),
|
||||
DirectiveBinding.createFromType(C, null)
|
||||
];
|
||||
var proto = ProtoElementInjector.create(null, 0, bindings, false, 0);
|
||||
var elementInjector = proto.instantiate(null);
|
||||
|
||||
function instantiate () {
|
||||
for (var i = 0; i < iterations; ++i) {
|
||||
var ei = proto.instantiate(null);
|
||||
ei.instantiateDirectives(appInjector, null, null);
|
||||
ei.hydrate(appInjector, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
function instantiateDirectives () {
|
||||
function hydrate () {
|
||||
for (var i = 0; i < iterations; ++i) {
|
||||
elementInjector.clearDirectives();
|
||||
elementInjector.instantiateDirectives(appInjector, null, null);
|
||||
elementInjector.dehydrate();
|
||||
elementInjector.hydrate(appInjector, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,8 +41,8 @@ export function main() {
|
|||
() => microBenchmark('instantiateAvg', iterations, instantiate)
|
||||
);
|
||||
bindAction(
|
||||
'#instantiateDirectives',
|
||||
() => microBenchmark('instantiateAvg', iterations, instantiateDirectives)
|
||||
'#hydrate',
|
||||
() => microBenchmark('instantiateAvg', iterations, hydrate)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue