feat(directive): notify directive before they get destroyed
This commit is contained in:
parent
ec8e9f5634
commit
fb1b1da7b9
|
@ -10,23 +10,27 @@ export class Directive {
|
||||||
bind:any;
|
bind:any;
|
||||||
lightDomServices:any; //List;
|
lightDomServices:any; //List;
|
||||||
implementsTypes:any; //List;
|
implementsTypes:any; //List;
|
||||||
|
lifecycle:any; //List
|
||||||
@CONST()
|
@CONST()
|
||||||
constructor({
|
constructor({
|
||||||
selector,
|
selector,
|
||||||
bind,
|
bind,
|
||||||
lightDomServices,
|
lightDomServices,
|
||||||
implementsTypes
|
implementsTypes,
|
||||||
|
lifecycle
|
||||||
}:{
|
}:{
|
||||||
selector:string,
|
selector:string,
|
||||||
bind:any,
|
bind:any,
|
||||||
lightDomServices:List,
|
lightDomServices:List,
|
||||||
implementsTypes:List
|
implementsTypes:List,
|
||||||
|
lifecycle:List
|
||||||
}={})
|
}={})
|
||||||
{
|
{
|
||||||
this.selector = selector;
|
this.selector = selector;
|
||||||
this.lightDomServices = lightDomServices;
|
this.lightDomServices = lightDomServices;
|
||||||
this.implementsTypes = implementsTypes;
|
this.implementsTypes = implementsTypes;
|
||||||
this.bind = bind;
|
this.bind = bind;
|
||||||
|
this.lifecycle = lifecycle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +41,9 @@ export class Component extends Directive {
|
||||||
shadowDomServices:any; //List;
|
shadowDomServices:any; //List;
|
||||||
componentServices:any; //List;
|
componentServices:any; //List;
|
||||||
shadowDom:any; //ShadowDomStrategy;
|
shadowDom:any; //ShadowDomStrategy;
|
||||||
|
lifecycle:any; //List
|
||||||
|
|
||||||
@CONST()
|
@CONST()
|
||||||
constructor({
|
constructor({
|
||||||
selector,
|
selector,
|
||||||
bind,
|
bind,
|
||||||
|
@ -47,29 +52,34 @@ export class Component extends Directive {
|
||||||
shadowDomServices,
|
shadowDomServices,
|
||||||
componentServices,
|
componentServices,
|
||||||
implementsTypes,
|
implementsTypes,
|
||||||
shadowDom
|
shadowDom,
|
||||||
|
lifecycle
|
||||||
}:{
|
}:{
|
||||||
selector:String,
|
selector:String,
|
||||||
bind:Object,
|
bind:Object,
|
||||||
template:TemplateConfig,
|
template:TemplateConfig,
|
||||||
lightDomServices:List,
|
lightDomServices:List,
|
||||||
shadowDomServices:List,
|
shadowDomServices:List,
|
||||||
componentServices:List,
|
componentServices:List,
|
||||||
implementsTypes:List,
|
implementsTypes:List,
|
||||||
shadowDom:ShadowDomStrategy
|
shadowDom:ShadowDomStrategy,
|
||||||
}={})
|
lifecycle:List
|
||||||
|
}={})
|
||||||
{
|
{
|
||||||
super({
|
super({
|
||||||
selector: selector,
|
selector: selector,
|
||||||
bind: bind,
|
bind: bind,
|
||||||
lightDomServices: lightDomServices,
|
lightDomServices: lightDomServices,
|
||||||
implementsTypes: implementsTypes});
|
implementsTypes: implementsTypes,
|
||||||
|
lifecycle: lifecycle
|
||||||
|
});
|
||||||
|
|
||||||
this.template = template;
|
this.template = template;
|
||||||
this.lightDomServices = lightDomServices;
|
this.lightDomServices = lightDomServices;
|
||||||
this.shadowDomServices = shadowDomServices;
|
this.shadowDomServices = shadowDomServices;
|
||||||
this.componentServices = componentServices;
|
this.componentServices = componentServices;
|
||||||
this.shadowDom = shadowDom;
|
this.shadowDom = shadowDom;
|
||||||
|
this.lifecycle = lifecycle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,12 +91,14 @@ export class Decorator extends Directive {
|
||||||
bind,
|
bind,
|
||||||
lightDomServices,
|
lightDomServices,
|
||||||
implementsTypes,
|
implementsTypes,
|
||||||
compileChildren = true
|
lifecycle,
|
||||||
|
compileChildren = true,
|
||||||
}:{
|
}:{
|
||||||
selector:string,
|
selector:string,
|
||||||
bind:any,
|
bind:any,
|
||||||
lightDomServices:List,
|
lightDomServices:List,
|
||||||
implementsTypes:List,
|
implementsTypes:List,
|
||||||
|
lifecycle:List,
|
||||||
compileChildren:boolean
|
compileChildren:boolean
|
||||||
}={})
|
}={})
|
||||||
{
|
{
|
||||||
|
@ -95,7 +107,8 @@ export class Decorator extends Directive {
|
||||||
selector: selector,
|
selector: selector,
|
||||||
bind: bind,
|
bind: bind,
|
||||||
lightDomServices: lightDomServices,
|
lightDomServices: lightDomServices,
|
||||||
implementsTypes: implementsTypes
|
implementsTypes: implementsTypes,
|
||||||
|
lifecycle: lifecycle
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,19 +119,24 @@ export class Template extends Directive {
|
||||||
selector,
|
selector,
|
||||||
bind,
|
bind,
|
||||||
lightDomServices,
|
lightDomServices,
|
||||||
implementsTypes
|
implementsTypes,
|
||||||
|
lifecycle
|
||||||
}:{
|
}:{
|
||||||
selector:string,
|
selector:string,
|
||||||
bind:any,
|
bind:any,
|
||||||
lightDomServices:List,
|
lightDomServices:List,
|
||||||
implementsTypes:List
|
implementsTypes:List,
|
||||||
|
lifecycle:List
|
||||||
}={})
|
}={})
|
||||||
{
|
{
|
||||||
super({
|
super({
|
||||||
selector: selector,
|
selector: selector,
|
||||||
bind: bind,
|
bind: bind,
|
||||||
lightDomServices: lightDomServices,
|
lightDomServices: lightDomServices,
|
||||||
implementsTypes: implementsTypes
|
implementsTypes: implementsTypes,
|
||||||
|
lifecycle: lifecycle
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export var onDestroy = "onDestroy";
|
||||||
|
|
|
@ -3,10 +3,12 @@ import {Math} from 'facade/math';
|
||||||
import {List, ListWrapper} from 'facade/collection';
|
import {List, ListWrapper} from 'facade/collection';
|
||||||
import {Injector, Key, Dependency, bind, Binding, NoProviderError, ProviderError, CyclicDependencyError} from 'di/di';
|
import {Injector, Key, Dependency, bind, Binding, NoProviderError, ProviderError, CyclicDependencyError} from 'di/di';
|
||||||
import {Parent, Ancestor} from 'core/annotations/visibility';
|
import {Parent, Ancestor} from 'core/annotations/visibility';
|
||||||
|
import {onDestroy} from 'core/annotations/annotations';
|
||||||
import {View} from 'core/compiler/view';
|
import {View} from 'core/compiler/view';
|
||||||
import {LightDom, SourceLightDom, DestinationLightDom} from 'core/compiler/shadow_dom_emulation/light_dom';
|
import {LightDom, SourceLightDom, DestinationLightDom} from 'core/compiler/shadow_dom_emulation/light_dom';
|
||||||
import {ViewPort} from 'core/compiler/viewport';
|
import {ViewPort} from 'core/compiler/viewport';
|
||||||
import {NgElement} from 'core/dom/element';
|
import {NgElement} from 'core/dom/element';
|
||||||
|
import {Directive} from 'core/annotations/annotations'
|
||||||
|
|
||||||
var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10;
|
var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10;
|
||||||
|
|
||||||
|
@ -85,8 +87,9 @@ class TreeNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DirectiveDependency extends Dependency {
|
export class DirectiveDependency extends Dependency {
|
||||||
depth:int;
|
depth:int;
|
||||||
|
|
||||||
constructor(key:Key, asPromise:boolean, lazy:boolean, properties:List, depth:int) {
|
constructor(key:Key, asPromise:boolean, lazy:boolean, properties:List, depth:int) {
|
||||||
super(key, asPromise, lazy, properties);
|
super(key, asPromise, lazy, properties);
|
||||||
this.depth = depth;
|
this.depth = depth;
|
||||||
|
@ -105,6 +108,28 @@ class DirectiveDependency extends Dependency {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class DirectiveBinding extends Binding {
|
||||||
|
callOnDestroy:boolean;
|
||||||
|
|
||||||
|
constructor(key:Key, factory:Function, dependencies:List, providedAsPromise:boolean, callOnDestroy:boolean) {
|
||||||
|
super(key, factory, dependencies, providedAsPromise);
|
||||||
|
this.callOnDestroy = callOnDestroy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static createFromBinding(b:Binding, annotation:Directive):Binding {
|
||||||
|
var deps = ListWrapper.map(b.dependencies, DirectiveDependency.createFrom);
|
||||||
|
var callOnDestroy = isPresent(annotation) && isPresent(annotation.lifecycle) ?
|
||||||
|
ListWrapper.contains(annotation.lifecycle, onDestroy) :
|
||||||
|
false;
|
||||||
|
return new DirectiveBinding(b.key, b.factory, deps, b.providedAsPromise, callOnDestroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static createFromType(type:Type, annotation:Directive):Binding {
|
||||||
|
var binding = bind(type).toClass(type);
|
||||||
|
return DirectiveBinding.createFromBinding(binding, annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO(rado): benchmark and consider rolling in as ElementInjector fields.
|
// TODO(rado): benchmark and consider rolling in as ElementInjector fields.
|
||||||
export class PreBuiltObjects {
|
export class PreBuiltObjects {
|
||||||
|
@ -205,11 +230,12 @@ export class ProtoElementInjector {
|
||||||
}
|
}
|
||||||
|
|
||||||
_createBinding(bindingOrType) {
|
_createBinding(bindingOrType) {
|
||||||
var b = (bindingOrType instanceof Type) ?
|
if (bindingOrType instanceof DirectiveBinding) {
|
||||||
bind(bindingOrType).toClass(bindingOrType) :
|
return bindingOrType;
|
||||||
bindingOrType;
|
} else {
|
||||||
var deps = ListWrapper.map(b.dependencies, DirectiveDependency.createFrom);
|
var b = bind(bindingOrType).toClass(bindingOrType);
|
||||||
return new Binding(b.key, b.factory, deps, b.providedAsPromise);
|
return DirectiveBinding.createFromBinding(b, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasBindings():boolean {
|
get hasBindings():boolean {
|
||||||
|
@ -271,6 +297,19 @@ export class ElementInjector extends TreeNode {
|
||||||
this._lightDomAppInjector = null;
|
this._lightDomAppInjector = null;
|
||||||
this._shadowDomAppInjector = null;
|
this._shadowDomAppInjector = null;
|
||||||
|
|
||||||
|
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();}
|
||||||
|
|
||||||
this._obj0 = null;
|
this._obj0 = null;
|
||||||
this._obj1 = null;
|
this._obj1 = null;
|
||||||
this._obj2 = null;
|
this._obj2 = null;
|
||||||
|
@ -281,6 +320,7 @@ export class ElementInjector extends TreeNode {
|
||||||
this._obj7 = null;
|
this._obj7 = null;
|
||||||
this._obj8 = null;
|
this._obj8 = null;
|
||||||
this._obj9 = null;
|
this._obj9 = null;
|
||||||
|
|
||||||
this._constructionCounter = 0;
|
this._constructionCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,12 @@ import {isPresent, isBlank} from 'facade/lang';
|
||||||
import {ListWrapper} from 'facade/collection';
|
import {ListWrapper} from 'facade/collection';
|
||||||
|
|
||||||
import {Key} from 'di/di';
|
import {Key} from 'di/di';
|
||||||
import {ProtoElementInjector, ComponentKeyMetaData} from '../element_injector';
|
import {ProtoElementInjector, ComponentKeyMetaData, DirectiveBinding} from '../element_injector';
|
||||||
|
|
||||||
import {CompileStep} from './compile_step';
|
import {CompileStep} from './compile_step';
|
||||||
import {CompileElement} from './compile_element';
|
import {CompileElement} from './compile_element';
|
||||||
import {CompileControl} from './compile_control';
|
import {CompileControl} from './compile_control';
|
||||||
|
import {DirectiveMetadata} from '../directive_metadata';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the ProtoElementInjectors.
|
* Creates the ProtoElementInjectors.
|
||||||
|
@ -67,16 +68,20 @@ export class ProtoElementInjectorBuilder extends CompileStep {
|
||||||
_collectDirectiveBindings(pipelineElement) {
|
_collectDirectiveBindings(pipelineElement) {
|
||||||
var directiveTypes = [];
|
var directiveTypes = [];
|
||||||
if (isPresent(pipelineElement.componentDirective)) {
|
if (isPresent(pipelineElement.componentDirective)) {
|
||||||
ListWrapper.push(directiveTypes, pipelineElement.componentDirective.type);
|
ListWrapper.push(directiveTypes, this._createBinding(pipelineElement.componentDirective));
|
||||||
}
|
}
|
||||||
if (isPresent(pipelineElement.templateDirective)) {
|
if (isPresent(pipelineElement.templateDirective)) {
|
||||||
ListWrapper.push(directiveTypes, pipelineElement.templateDirective.type);
|
ListWrapper.push(directiveTypes, this._createBinding(pipelineElement.templateDirective));
|
||||||
}
|
}
|
||||||
if (isPresent(pipelineElement.decoratorDirectives)) {
|
if (isPresent(pipelineElement.decoratorDirectives)) {
|
||||||
for (var i=0; i<pipelineElement.decoratorDirectives.length; i++) {
|
for (var i=0; i<pipelineElement.decoratorDirectives.length; i++) {
|
||||||
ListWrapper.push(directiveTypes, pipelineElement.decoratorDirectives[i].type);
|
ListWrapper.push(directiveTypes, this._createBinding(pipelineElement.decoratorDirectives[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return directiveTypes;
|
return directiveTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_createBinding(d:DirectiveMetadata): DirectiveBinding {
|
||||||
|
return DirectiveBinding.createFromType(d.type, d.annotation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,7 +180,9 @@ export class View {
|
||||||
|
|
||||||
// elementInjectors
|
// elementInjectors
|
||||||
for (var i = 0; i < this.elementInjectors.length; i++) {
|
for (var i = 0; i < this.elementInjectors.length; i++) {
|
||||||
this.elementInjectors[i].clearDirectives();
|
if (isPresent(this.elementInjectors[i])) {
|
||||||
|
this.elementInjectors[i].clearDirectives();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// viewPorts
|
// viewPorts
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, SpyObject} from 'test_lib/test_lib';
|
import {describe, ddescribe, it, iit, xit, xdescribe, expect, beforeEach, SpyObject} from 'test_lib/test_lib';
|
||||||
import {isBlank, isPresent, FIELD, IMPLEMENTS, proxy} from 'facade/lang';
|
import {isBlank, isPresent, FIELD, IMPLEMENTS, proxy} from 'facade/lang';
|
||||||
import {ListWrapper, MapWrapper, List} from 'facade/collection';
|
import {ListWrapper, MapWrapper, List} from 'facade/collection';
|
||||||
import {ProtoElementInjector, PreBuiltObjects} from 'core/compiler/element_injector';
|
import {ProtoElementInjector, PreBuiltObjects, DirectiveBinding} from 'core/compiler/element_injector';
|
||||||
import {Parent, Ancestor} from 'core/annotations/visibility';
|
import {Parent, Ancestor} from 'core/annotations/visibility';
|
||||||
|
import {onDestroy} from 'core/annotations/annotations';
|
||||||
import {Injector, Inject, bind} from 'di/di';
|
import {Injector, Inject, bind} from 'di/di';
|
||||||
import {View} from 'core/compiler/view';
|
import {View} from 'core/compiler/view';
|
||||||
import {ProtoRecordRange} from 'change_detection/change_detection';
|
import {ProtoRecordRange} from 'change_detection/change_detection';
|
||||||
import {ViewPort} from 'core/compiler/viewport';
|
import {ViewPort} from 'core/compiler/viewport';
|
||||||
import {NgElement} from 'core/dom/element';
|
import {NgElement} from 'core/dom/element';
|
||||||
import {LightDom, SourceLightDom, DestinationLightDom} from 'core/compiler/shadow_dom_emulation/light_dom';
|
import {LightDom, SourceLightDom, DestinationLightDom} from 'core/compiler/shadow_dom_emulation/light_dom';
|
||||||
|
import {Directive} from 'core/annotations/annotations';
|
||||||
|
|
||||||
@proxy
|
@proxy
|
||||||
@IMPLEMENTS(View)
|
@IMPLEMENTS(View)
|
||||||
|
@ -19,7 +21,7 @@ class DummyView extends SpyObject {noSuchMethod(m){super.noSuchMethod(m)}}
|
||||||
class DummyLightDom extends SpyObject {noSuchMethod(m){super.noSuchMethod(m)}}
|
class DummyLightDom extends SpyObject {noSuchMethod(m){super.noSuchMethod(m)}}
|
||||||
|
|
||||||
|
|
||||||
class Directive {
|
class SimpleDirective {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,22 +29,22 @@ class SomeOtherDirective {
|
||||||
}
|
}
|
||||||
|
|
||||||
class NeedsDirective {
|
class NeedsDirective {
|
||||||
dependency:Directive;
|
dependency:SimpleDirective;
|
||||||
constructor(dependency:Directive){
|
constructor(dependency:SimpleDirective){
|
||||||
this.dependency = dependency;
|
this.dependency = dependency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NeedDirectiveFromParent {
|
class NeedDirectiveFromParent {
|
||||||
dependency:Directive;
|
dependency:SimpleDirective;
|
||||||
constructor(@Parent() dependency:Directive){
|
constructor(@Parent() dependency:SimpleDirective){
|
||||||
this.dependency = dependency;
|
this.dependency = dependency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NeedDirectiveFromAncestor {
|
class NeedDirectiveFromAncestor {
|
||||||
dependency:Directive;
|
dependency:SimpleDirective;
|
||||||
constructor(@Ancestor() dependency:Directive){
|
constructor(@Ancestor() dependency:SimpleDirective){
|
||||||
this.dependency = dependency;
|
this.dependency = dependency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +71,18 @@ class NeedsView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DirectiveWithDestroy {
|
||||||
|
onDestroyCounter:number;
|
||||||
|
|
||||||
|
constructor(){
|
||||||
|
this.onDestroyCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
onDestroy() {
|
||||||
|
this.onDestroyCounter ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null, null);
|
var defaultPreBuiltObjects = new PreBuiltObjects(null, null, null, null);
|
||||||
|
|
||||||
|
@ -172,7 +186,7 @@ export function main() {
|
||||||
|
|
||||||
describe("hasBindings", function () {
|
describe("hasBindings", function () {
|
||||||
it("should be true when there are bindings", function () {
|
it("should be true when there are bindings", function () {
|
||||||
var p = new ProtoElementInjector(null, 0, [Directive]);
|
var p = new ProtoElementInjector(null, 0, [SimpleDirective]);
|
||||||
expect(p.hasBindings).toBeTruthy();
|
expect(p.hasBindings).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -188,23 +202,23 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be true when directives are instantiated", function () {
|
it("should be true when directives are instantiated", function () {
|
||||||
expect(injector([Directive]).hasInstances()).toBe(true);
|
expect(injector([SimpleDirective]).hasInstances()).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("instantiateDirectives", function () {
|
describe("instantiateDirectives", function () {
|
||||||
it("should instantiate directives that have no dependencies", function () {
|
it("should instantiate directives that have no dependencies", function () {
|
||||||
var inj = injector([Directive]);
|
var inj = injector([SimpleDirective]);
|
||||||
expect(inj.get(Directive)).toBeAnInstanceOf(Directive);
|
expect(inj.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should instantiate directives that depend on other directives", function () {
|
it("should instantiate directives that depend on other directives", function () {
|
||||||
var inj = injector([Directive, NeedsDirective]);
|
var inj = injector([SimpleDirective, NeedsDirective]);
|
||||||
|
|
||||||
var d = inj.get(NeedsDirective);
|
var d = inj.get(NeedsDirective);
|
||||||
|
|
||||||
expect(d).toBeAnInstanceOf(NeedsDirective);
|
expect(d).toBeAnInstanceOf(NeedsDirective);
|
||||||
expect(d.dependency).toBeAnInstanceOf(Directive);
|
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should instantiate directives that depend on app services", function () {
|
it("should instantiate directives that depend on app services", function () {
|
||||||
|
@ -226,17 +240,17 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should instantiate directives that depend on the containing component", function () {
|
it("should instantiate directives that depend on the containing component", function () {
|
||||||
var shadow = hostShadowInjectors([Directive], [NeedsDirective]);
|
var shadow = hostShadowInjectors([SimpleDirective], [NeedsDirective]);
|
||||||
|
|
||||||
var d = shadow.get(NeedsDirective);
|
var d = shadow.get(NeedsDirective);
|
||||||
expect(d).toBeAnInstanceOf(NeedsDirective);
|
expect(d).toBeAnInstanceOf(NeedsDirective);
|
||||||
expect(d.dependency).toBeAnInstanceOf(Directive);
|
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not instantiate directives that depend on other directives in the containing component's ElementInjector", () => {
|
it("should not instantiate directives that depend on other directives in the containing component's ElementInjector", () => {
|
||||||
expect( () => {
|
expect( () => {
|
||||||
hostShadowInjectors([SomeOtherDirective, Directive], [NeedsDirective]);
|
hostShadowInjectors([SomeOtherDirective, SimpleDirective], [NeedsDirective]);
|
||||||
}).toThrowError('No provider for Directive! (NeedsDirective -> Directive)')
|
}).toThrowError('No provider for SimpleDirective! (NeedsDirective -> SimpleDirective)')
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should instantiate component directives that depend on app services in the shadow app injector", () => {
|
it("should instantiate component directives that depend on app services in the shadow app injector", () => {
|
||||||
|
@ -269,42 +283,46 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should get directives from parent", function () {
|
it("should get directives from parent", function () {
|
||||||
var child = parentChildInjectors([Directive], [NeedDirectiveFromParent]);
|
var child = parentChildInjectors([SimpleDirective], [NeedDirectiveFromParent]);
|
||||||
|
|
||||||
var d = child.get(NeedDirectiveFromParent);
|
var d = child.get(NeedDirectiveFromParent);
|
||||||
|
|
||||||
expect(d).toBeAnInstanceOf(NeedDirectiveFromParent);
|
expect(d).toBeAnInstanceOf(NeedDirectiveFromParent);
|
||||||
expect(d.dependency).toBeAnInstanceOf(Directive);
|
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not return parent's directives on self", function () {
|
it("should not return parent's directives on self", function () {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
injector([Directive, NeedDirectiveFromParent]);
|
injector([SimpleDirective, NeedDirectiveFromParent]);
|
||||||
}).toThrowError();
|
}).toThrowError();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should get directives from ancestor", function () {
|
it("should get directives from ancestor", function () {
|
||||||
var child = parentChildInjectors([Directive], [NeedDirectiveFromAncestor]);
|
var child = parentChildInjectors([SimpleDirective], [NeedDirectiveFromAncestor]);
|
||||||
|
|
||||||
var d = child.get(NeedDirectiveFromAncestor);
|
var d = child.get(NeedDirectiveFromAncestor);
|
||||||
|
|
||||||
expect(d).toBeAnInstanceOf(NeedDirectiveFromAncestor);
|
expect(d).toBeAnInstanceOf(NeedDirectiveFromAncestor);
|
||||||
expect(d.dependency).toBeAnInstanceOf(Directive);
|
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should throw when no directive found", function () {
|
it("should throw when no SimpleDirective found", function () {
|
||||||
expect(() => injector([NeedDirectiveFromParent])).
|
expect(() => injector([NeedDirectiveFromParent])).
|
||||||
toThrowError('No provider for Directive! (NeedDirectiveFromParent -> Directive)');
|
toThrowError('No provider for SimpleDirective! (NeedDirectiveFromParent -> SimpleDirective)');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should accept bindings instead of directive types", function () {
|
it("should accept SimpleDirective bindings instead of SimpleDirective types", function () {
|
||||||
var inj = injector([bind(Directive).toClass(Directive)]);
|
var inj = injector([
|
||||||
expect(inj.get(Directive)).toBeAnInstanceOf(Directive);
|
DirectiveBinding.createFromBinding(bind(SimpleDirective).toClass(SimpleDirective), null)
|
||||||
|
]);
|
||||||
|
expect(inj.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should allow for direct access using getAtIndex", function () {
|
it("should allow for direct access using getAtIndex", function () {
|
||||||
var inj = injector([bind(Directive).toClass(Directive)]);
|
var inj = injector([
|
||||||
expect(inj.getAtIndex(0)).toBeAnInstanceOf(Directive);
|
DirectiveBinding.createFromBinding(bind(SimpleDirective).toClass(SimpleDirective), null)
|
||||||
|
]);
|
||||||
|
expect(inj.getAtIndex(0)).toBeAnInstanceOf(SimpleDirective);
|
||||||
expect(() => inj.getAtIndex(-1)).toThrowError(
|
expect(() => inj.getAtIndex(-1)).toThrowError(
|
||||||
'Index -1 is out-of-bounds.');
|
'Index -1 is out-of-bounds.');
|
||||||
expect(() => inj.getAtIndex(10)).toThrowError(
|
expect(() => inj.getAtIndex(10)).toThrowError(
|
||||||
|
@ -313,13 +331,24 @@ export function main() {
|
||||||
|
|
||||||
it("should handle cyclic dependencies", function () {
|
it("should handle cyclic dependencies", function () {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
|
var bAneedsB = bind(A_Needs_B).toFactory((a) => new A_Needs_B(a), [B_Needs_A]);
|
||||||
|
var bBneedsA = bind(B_Needs_A).toFactory((a) => new B_Needs_A(a), [A_Needs_B]);
|
||||||
injector([
|
injector([
|
||||||
bind(A_Needs_B).toFactory((a) => new A_Needs_B(a), [B_Needs_A]),
|
DirectiveBinding.createFromBinding(bAneedsB, null),
|
||||||
bind(B_Needs_A).toFactory((a) => new B_Needs_A(a), [A_Needs_B])
|
DirectiveBinding.createFromBinding(bBneedsA, null)
|
||||||
]);
|
]);
|
||||||
}).toThrowError('Cannot instantiate cyclic dependency! ' +
|
}).toThrowError('Cannot instantiate cyclic dependency! ' +
|
||||||
'(A_Needs_B -> B_Needs_A -> A_Needs_B)');
|
'(A_Needs_B -> B_Needs_A -> A_Needs_B)');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should call onDestroy on directives subscribed to this event", function () {
|
||||||
|
var inj = injector([
|
||||||
|
DirectiveBinding.createFromType(DirectiveWithDestroy, new Directive({lifecycle: [onDestroy]}))
|
||||||
|
]);
|
||||||
|
var destroy = inj.get(DirectiveWithDestroy);
|
||||||
|
inj.clearDirectives();
|
||||||
|
expect(destroy.onDestroyCounter).toBe(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("pre built objects", function () {
|
describe("pre built objects", function () {
|
||||||
|
|
|
@ -52,7 +52,8 @@ export function main() {
|
||||||
var directives = [SomeComponentDirective, SomeTemplateDirective, SomeDecoratorDirective];
|
var directives = [SomeComponentDirective, SomeTemplateDirective, SomeDecoratorDirective];
|
||||||
var results = createPipeline(directives).process(el('<div directives></div>'));
|
var results = createPipeline(directives).process(el('<div directives></div>'));
|
||||||
var creationArgs = getCreationArgs(results[0].inheritedProtoElementInjector);
|
var creationArgs = getCreationArgs(results[0].inheritedProtoElementInjector);
|
||||||
expect(creationArgs['bindings']).toEqual(directives);
|
var boundDirectives = creationArgs['bindings'].map((b) => b.key.token);
|
||||||
|
expect(boundDirectives).toEqual(directives);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should mark ProtoElementInjector for elements with component directives and use the ComponentDirective as first binding', () => {
|
it('should mark ProtoElementInjector for elements with component directives and use the ComponentDirective as first binding', () => {
|
||||||
|
@ -60,7 +61,8 @@ export function main() {
|
||||||
var results = createPipeline(directives).process(el('<div directives></div>'));
|
var results = createPipeline(directives).process(el('<div directives></div>'));
|
||||||
var creationArgs = getCreationArgs(results[0].inheritedProtoElementInjector);
|
var creationArgs = getCreationArgs(results[0].inheritedProtoElementInjector);
|
||||||
expect(creationArgs['firstBindingIsComponent']).toBe(true);
|
expect(creationArgs['firstBindingIsComponent']).toBe(true);
|
||||||
expect(creationArgs['bindings']).toEqual([SomeComponentDirective, SomeDecoratorDirective]);
|
var boundDirectives = creationArgs['bindings'].map((b) => b.key.token);
|
||||||
|
expect(boundDirectives).toEqual([SomeComponentDirective, SomeDecoratorDirective]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use the next ElementBinder index as index of the ProtoElementInjector', () => {
|
it('should use the next ElementBinder index as index of the ProtoElementInjector', () => {
|
||||||
|
@ -171,4 +173,4 @@ class SomeTemplateDirective {}
|
||||||
class SomeComponentDirective {}
|
class SomeComponentDirective {}
|
||||||
|
|
||||||
@Decorator()
|
@Decorator()
|
||||||
class SomeDecoratorDirective {}
|
class SomeDecoratorDirective {}
|
||||||
|
|
Loading…
Reference in New Issue