Skip to content

Commit fb1b1da

Browse files
committed
feat(directive): notify directive before they get destroyed
1 parent ec8e9f5 commit fb1b1da

File tree

6 files changed

+155
-59
lines changed

6 files changed

+155
-59
lines changed

modules/core/src/annotations/annotations.js

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,27 @@ export class Directive {
1010
bind:any;
1111
lightDomServices:any; //List;
1212
implementsTypes:any; //List;
13+
lifecycle:any; //List
1314
@CONST()
1415
constructor({
1516
selector,
1617
bind,
1718
lightDomServices,
18-
implementsTypes
19+
implementsTypes,
20+
lifecycle
1921
}:{
2022
selector:string,
2123
bind:any,
2224
lightDomServices:List,
23-
implementsTypes:List
25+
implementsTypes:List,
26+
lifecycle:List
2427
}={})
2528
{
2629
this.selector = selector;
2730
this.lightDomServices = lightDomServices;
2831
this.implementsTypes = implementsTypes;
2932
this.bind = bind;
33+
this.lifecycle = lifecycle;
3034
}
3135
}
3236

@@ -37,8 +41,9 @@ export class Component extends Directive {
3741
shadowDomServices:any; //List;
3842
componentServices:any; //List;
3943
shadowDom:any; //ShadowDomStrategy;
44+
lifecycle:any; //List
4045

41-
@CONST()
46+
@CONST()
4247
constructor({
4348
selector,
4449
bind,
@@ -47,29 +52,34 @@ export class Component extends Directive {
4752
shadowDomServices,
4853
componentServices,
4954
implementsTypes,
50-
shadowDom
55+
shadowDom,
56+
lifecycle
5157
}:{
52-
selector:String,
58+
selector:String,
5359
bind:Object,
5460
template:TemplateConfig,
5561
lightDomServices:List,
5662
shadowDomServices:List,
5763
componentServices:List,
5864
implementsTypes:List,
59-
shadowDom:ShadowDomStrategy
60-
}={})
65+
shadowDom:ShadowDomStrategy,
66+
lifecycle:List
67+
}={})
6168
{
6269
super({
6370
selector: selector,
6471
bind: bind,
6572
lightDomServices: lightDomServices,
66-
implementsTypes: implementsTypes});
73+
implementsTypes: implementsTypes,
74+
lifecycle: lifecycle
75+
});
6776

6877
this.template = template;
6978
this.lightDomServices = lightDomServices;
7079
this.shadowDomServices = shadowDomServices;
7180
this.componentServices = componentServices;
7281
this.shadowDom = shadowDom;
82+
this.lifecycle = lifecycle;
7383
}
7484
}
7585

@@ -81,12 +91,14 @@ export class Decorator extends Directive {
8191
bind,
8292
lightDomServices,
8393
implementsTypes,
84-
compileChildren = true
94+
lifecycle,
95+
compileChildren = true,
8596
}:{
8697
selector:string,
8798
bind:any,
8899
lightDomServices:List,
89100
implementsTypes:List,
101+
lifecycle:List,
90102
compileChildren:boolean
91103
}={})
92104
{
@@ -95,7 +107,8 @@ export class Decorator extends Directive {
95107
selector: selector,
96108
bind: bind,
97109
lightDomServices: lightDomServices,
98-
implementsTypes: implementsTypes
110+
implementsTypes: implementsTypes,
111+
lifecycle: lifecycle
99112
});
100113
}
101114
}
@@ -106,19 +119,24 @@ export class Template extends Directive {
106119
selector,
107120
bind,
108121
lightDomServices,
109-
implementsTypes
122+
implementsTypes,
123+
lifecycle
110124
}:{
111125
selector:string,
112126
bind:any,
113127
lightDomServices:List,
114-
implementsTypes:List
128+
implementsTypes:List,
129+
lifecycle:List
115130
}={})
116131
{
117132
super({
118133
selector: selector,
119134
bind: bind,
120135
lightDomServices: lightDomServices,
121-
implementsTypes: implementsTypes
136+
implementsTypes: implementsTypes,
137+
lifecycle: lifecycle
122138
});
123139
}
124140
}
141+
142+
export var onDestroy = "onDestroy";

modules/core/src/compiler/element_injector.js

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import {Math} from 'facade/math';
33
import {List, ListWrapper} from 'facade/collection';
44
import {Injector, Key, Dependency, bind, Binding, NoProviderError, ProviderError, CyclicDependencyError} from 'di/di';
55
import {Parent, Ancestor} from 'core/annotations/visibility';
6+
import {onDestroy} from 'core/annotations/annotations';
67
import {View} from 'core/compiler/view';
78
import {LightDom, SourceLightDom, DestinationLightDom} from 'core/compiler/shadow_dom_emulation/light_dom';
89
import {ViewPort} from 'core/compiler/viewport';
910
import {NgElement} from 'core/dom/element';
11+
import {Directive} from 'core/annotations/annotations'
1012

1113
var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10;
1214

@@ -85,8 +87,9 @@ class TreeNode {
8587
}
8688
}
8789

88-
class DirectiveDependency extends Dependency {
90+
export class DirectiveDependency extends Dependency {
8991
depth:int;
92+
9093
constructor(key:Key, asPromise:boolean, lazy:boolean, properties:List, depth:int) {
9194
super(key, asPromise, lazy, properties);
9295
this.depth = depth;
@@ -105,6 +108,28 @@ class DirectiveDependency extends Dependency {
105108
}
106109
}
107110

111+
export class DirectiveBinding extends Binding {
112+
callOnDestroy:boolean;
113+
114+
constructor(key:Key, factory:Function, dependencies:List, providedAsPromise:boolean, callOnDestroy:boolean) {
115+
super(key, factory, dependencies, providedAsPromise);
116+
this.callOnDestroy = callOnDestroy;
117+
}
118+
119+
static createFromBinding(b:Binding, annotation:Directive):Binding {
120+
var deps = ListWrapper.map(b.dependencies, DirectiveDependency.createFrom);
121+
var callOnDestroy = isPresent(annotation) && isPresent(annotation.lifecycle) ?
122+
ListWrapper.contains(annotation.lifecycle, onDestroy) :
123+
false;
124+
return new DirectiveBinding(b.key, b.factory, deps, b.providedAsPromise, callOnDestroy);
125+
}
126+
127+
static createFromType(type:Type, annotation:Directive):Binding {
128+
var binding = bind(type).toClass(type);
129+
return DirectiveBinding.createFromBinding(binding, annotation);
130+
}
131+
}
132+
108133

109134
// TODO(rado): benchmark and consider rolling in as ElementInjector fields.
110135
export class PreBuiltObjects {
@@ -205,11 +230,12 @@ export class ProtoElementInjector {
205230
}
206231

207232
_createBinding(bindingOrType) {
208-
var b = (bindingOrType instanceof Type) ?
209-
bind(bindingOrType).toClass(bindingOrType) :
210-
bindingOrType;
211-
var deps = ListWrapper.map(b.dependencies, DirectiveDependency.createFrom);
212-
return new Binding(b.key, b.factory, deps, b.providedAsPromise);
233+
if (bindingOrType instanceof DirectiveBinding) {
234+
return bindingOrType;
235+
} else {
236+
var b = bind(bindingOrType).toClass(bindingOrType);
237+
return DirectiveBinding.createFromBinding(b, null);
238+
}
213239
}
214240

215241
get hasBindings():boolean {
@@ -271,6 +297,19 @@ export class ElementInjector extends TreeNode {
271297
this._lightDomAppInjector = null;
272298
this._shadowDomAppInjector = null;
273299

300+
var p = this._proto;
301+
302+
if (isPresent(p._binding0) && p._binding0.callOnDestroy) {this._obj0.onDestroy();}
303+
if (isPresent(p._binding1) && p._binding1.callOnDestroy) {this._obj1.onDestroy();}
304+
if (isPresent(p._binding2) && p._binding2.callOnDestroy) {this._obj2.onDestroy();}
305+
if (isPresent(p._binding3) && p._binding3.callOnDestroy) {this._obj3.onDestroy();}
306+
if (isPresent(p._binding4) && p._binding4.callOnDestroy) {this._obj4.onDestroy();}
307+
if (isPresent(p._binding5) && p._binding5.callOnDestroy) {this._obj5.onDestroy();}
308+
if (isPresent(p._binding6) && p._binding6.callOnDestroy) {this._obj6.onDestroy();}
309+
if (isPresent(p._binding7) && p._binding7.callOnDestroy) {this._obj7.onDestroy();}
310+
if (isPresent(p._binding8) && p._binding8.callOnDestroy) {this._obj8.onDestroy();}
311+
if (isPresent(p._binding9) && p._binding9.callOnDestroy) {this._obj9.onDestroy();}
312+
274313
this._obj0 = null;
275314
this._obj1 = null;
276315
this._obj2 = null;
@@ -281,6 +320,7 @@ export class ElementInjector extends TreeNode {
281320
this._obj7 = null;
282321
this._obj8 = null;
283322
this._obj9 = null;
323+
284324
this._constructionCounter = 0;
285325
}
286326

modules/core/src/compiler/pipeline/proto_element_injector_builder.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import {isPresent, isBlank} from 'facade/lang';
22
import {ListWrapper} from 'facade/collection';
33

44
import {Key} from 'di/di';
5-
import {ProtoElementInjector, ComponentKeyMetaData} from '../element_injector';
5+
import {ProtoElementInjector, ComponentKeyMetaData, DirectiveBinding} from '../element_injector';
66

77
import {CompileStep} from './compile_step';
88
import {CompileElement} from './compile_element';
99
import {CompileControl} from './compile_control';
10+
import {DirectiveMetadata} from '../directive_metadata';
1011

1112
/**
1213
* Creates the ProtoElementInjectors.
@@ -67,16 +68,20 @@ export class ProtoElementInjectorBuilder extends CompileStep {
6768
_collectDirectiveBindings(pipelineElement) {
6869
var directiveTypes = [];
6970
if (isPresent(pipelineElement.componentDirective)) {
70-
ListWrapper.push(directiveTypes, pipelineElement.componentDirective.type);
71+
ListWrapper.push(directiveTypes, this._createBinding(pipelineElement.componentDirective));
7172
}
7273
if (isPresent(pipelineElement.templateDirective)) {
73-
ListWrapper.push(directiveTypes, pipelineElement.templateDirective.type);
74+
ListWrapper.push(directiveTypes, this._createBinding(pipelineElement.templateDirective));
7475
}
7576
if (isPresent(pipelineElement.decoratorDirectives)) {
7677
for (var i=0; i<pipelineElement.decoratorDirectives.length; i++) {
77-
ListWrapper.push(directiveTypes, pipelineElement.decoratorDirectives[i].type);
78+
ListWrapper.push(directiveTypes, this._createBinding(pipelineElement.decoratorDirectives[i]));
7879
}
7980
}
8081
return directiveTypes;
8182
}
83+
84+
_createBinding(d:DirectiveMetadata): DirectiveBinding {
85+
return DirectiveBinding.createFromType(d.type, d.annotation);
86+
}
8287
}

modules/core/src/compiler/view.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,9 @@ export class View {
180180

181181
// elementInjectors
182182
for (var i = 0; i < this.elementInjectors.length; i++) {
183-
this.elementInjectors[i].clearDirectives();
183+
if (isPresent(this.elementInjectors[i])) {
184+
this.elementInjectors[i].clearDirectives();
185+
}
184186
}
185187

186188
// viewPorts

0 commit comments

Comments
 (0)