Skip to content

Commit 9240b09

Browse files
committed
refactor(directives): directives use declare that they listen to onChange in the annotations
1 parent ee3f709 commit 9240b09

File tree

7 files changed

+91
-27
lines changed

7 files changed

+91
-27
lines changed

modules/angular2/src/core/annotations/annotations.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {ABSTRACT, CONST, normalizeBlank} from 'angular2/src/facade/lang';
2-
import {List} from 'angular2/src/facade/collection';
1+
import {ABSTRACT, CONST, normalizeBlank, isPresent} from 'angular2/src/facade/lang';
2+
import {ListWrapper, List} from 'angular2/src/facade/collection';
33
import {TemplateConfig} from './template_config';
44

55
@ABSTRACT()
@@ -30,6 +30,10 @@ export class Directive {
3030
this.bind = bind;
3131
this.lifecycle = lifecycle;
3232
}
33+
34+
hasLifecycleHook(hook:string):boolean {
35+
return isPresent(this.lifecycle) ? ListWrapper.contains(this.lifecycle, hook) : false;
36+
}
3337
}
3438

3539
export class Component extends Directive {
@@ -133,4 +137,5 @@ export class Template extends Directive {
133137
}
134138
}
135139

136-
export var onDestroy = "onDestroy";
140+
export const onDestroy = "onDestroy";
141+
export const onChange = "onChange";

modules/angular2/src/core/compiler/element_injector.js

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ import {List, ListWrapper, MapWrapper} from 'angular2/src/facade/collection';
44
import {Injector, Key, Dependency, bind, Binding, NoProviderError, ProviderError, CyclicDependencyError} from 'angular2/di';
55
import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility';
66
import {EventEmitter} from 'angular2/src/core/annotations/events';
7-
import {onDestroy} from 'angular2/src/core/annotations/annotations';
87
import {View, ProtoView} from 'angular2/src/core/compiler/view';
98
import {LightDom, SourceLightDom, DestinationLightDom} from 'angular2/src/core/compiler/shadow_dom_emulation/light_dom';
109
import {ViewPort} from 'angular2/src/core/compiler/viewport';
1110
import {NgElement} from 'angular2/src/core/dom/element';
12-
import {Directive} from 'angular2/src/core/annotations/annotations'
11+
import {Directive, onChange, onDestroy} from 'angular2/src/core/annotations/annotations'
1312
import {BindingPropagationConfig} from 'angular2/src/core/compiler/binding_propagation_config'
1413

1514
var _MAX_DIRECTIVE_CONSTRUCTION_COUNTER = 10;
@@ -123,18 +122,19 @@ export class DirectiveDependency extends Dependency {
123122

124123
export class DirectiveBinding extends Binding {
125124
callOnDestroy:boolean;
125+
callOnChange:boolean;
126+
onCheck:boolean;
126127

127-
constructor(key:Key, factory:Function, dependencies:List, providedAsPromise:boolean, callOnDestroy:boolean) {
128+
constructor(key:Key, factory:Function, dependencies:List, providedAsPromise:boolean, annotation:Directive) {
128129
super(key, factory, dependencies, providedAsPromise);
129-
this.callOnDestroy = callOnDestroy;
130+
this.callOnDestroy = isPresent(annotation) && annotation.hasLifecycleHook(onDestroy);
131+
this.callOnChange = isPresent(annotation) && annotation.hasLifecycleHook(onChange);
132+
//this.onCheck = isPresent(annotation) && annotation.hasLifecycleHook(onCheck);
130133
}
131134

132135
static createFromBinding(b:Binding, annotation:Directive):Binding {
133136
var deps = ListWrapper.map(b.dependencies, DirectiveDependency.createFrom);
134-
var callOnDestroy = isPresent(annotation) && isPresent(annotation.lifecycle) ?
135-
ListWrapper.contains(annotation.lifecycle, onDestroy) :
136-
false;
137-
return new DirectiveBinding(b.key, b.factory, deps, b.providedAsPromise, callOnDestroy);
137+
return new DirectiveBinding(b.key, b.factory, deps, b.providedAsPromise, annotation);
138138
}
139139

140140
static createFromType(type:Type, annotation:Directive):Binding {
@@ -567,7 +567,7 @@ export class ElementInjector extends TreeNode {
567567
return _undefined;
568568
}
569569

570-
getAtIndex(index:int) {
570+
getDirectiveAtIndex(index:int) {
571571
if (index == 0) return this._obj0;
572572
if (index == 1) return this._obj1;
573573
if (index == 2) return this._obj2;
@@ -581,6 +581,21 @@ export class ElementInjector extends TreeNode {
581581
throw new OutOfBoundsAccess(index);
582582
}
583583

584+
getDirectiveBindingAtIndex(index:int) {
585+
var p = this._proto;
586+
if (index == 0) return p._binding0;
587+
if (index == 1) return p._binding1;
588+
if (index == 2) return p._binding2;
589+
if (index == 3) return p._binding3;
590+
if (index == 4) return p._binding4;
591+
if (index == 5) return p._binding5;
592+
if (index == 6) return p._binding6;
593+
if (index == 7) return p._binding7;
594+
if (index == 8) return p._binding8;
595+
if (index == 9) return p._binding9;
596+
throw new OutOfBoundsAccess(index);
597+
}
598+
584599
hasInstances() {
585600
return this._constructionCounter > 0;
586601
}

modules/angular2/src/core/compiler/view.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {FIELD, IMPLEMENTS, int, isPresent, isBlank, BaseException} from 'angular
1212
import {Injector} from 'angular2/di';
1313
import {NgElement} from 'angular2/src/core/dom/element';
1414
import {ViewPort} from './viewport';
15-
import {OnChange} from './interfaces';
1615
import {Content} from './shadow_dom_emulation/content_tag';
1716
import {LightDom, DestinationLightDom} from './shadow_dom_emulation/light_dom';
1817
import {ShadowDomStrategy} from './shadow_dom_strategy';
@@ -211,7 +210,9 @@ export class View {
211210

212211
_notifyDirectiveAboutChanges(groupMemento, records:List) {
213212
var dir = groupMemento.directive(this.elementInjectors);
214-
if (dir instanceof OnChange) {
213+
var binding = groupMemento.directiveBinding(this.elementInjectors);
214+
215+
if (binding.callOnChange) {
215216
dir.onChange(this._collectChanges(records));
216217
}
217218
}
@@ -552,7 +553,7 @@ export class DirectivePropertyMemento {
552553

553554
invoke(record:ChangeRecord, elementInjectors:List<ElementInjector>) {
554555
var elementInjector:ElementInjector = elementInjectors[this._elementInjectorIndex];
555-
var directive = elementInjector.getAtIndex(this._directiveIndex);
556+
var directive = elementInjector.getDirectiveAtIndex(this._directiveIndex);
556557
this._setter(directive, record.currentValue);
557558
}
558559
}
@@ -581,7 +582,12 @@ class DirectivePropertyGroupMemento {
581582

582583
directive(elementInjectors:List<ElementInjector>) {
583584
var elementInjector:ElementInjector = elementInjectors[this._elementInjectorIndex];
584-
return elementInjector.getAtIndex(this._directiveIndex);
585+
return elementInjector.getDirectiveAtIndex(this._directiveIndex);
586+
}
587+
588+
directiveBinding(elementInjectors:List<ElementInjector>) {
589+
var elementInjector:ElementInjector = elementInjectors[this._elementInjectorIndex];
590+
return elementInjector.getDirectiveBindingAtIndex(this._directiveIndex);
585591
}
586592
}
587593

modules/angular2/src/directives/foreach.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Template} from 'angular2/src/core/annotations/annotations';
1+
import {Template, onChange} from 'angular2/src/core/annotations/annotations';
22
import {OnChange} from 'angular2/src/core/compiler/interfaces';
33
import {ViewPort} from 'angular2/src/core/compiler/viewport';
44
import {View} from 'angular2/src/core/compiler/view';
@@ -7,6 +7,7 @@ import {ListWrapper} from 'angular2/src/facade/collection';
77

88
@Template({
99
selector: '[foreach][in]',
10+
lifecycle: [onChange],
1011
bind: {
1112
'in': 'iterable[]'
1213
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {ddescribe, describe, it, iit, expect, beforeEach} from 'angular2/test_lib';
2+
import {Directive, onChange} from 'angular2/src/core/annotations/annotations';
3+
4+
export function main() {
5+
describe("Directive", () => {
6+
describe("lifecycle", () => {
7+
it("should be false when no lifecycle specified", () => {
8+
var d = new Directive();
9+
expect(d.hasLifecycleHook(onChange)).toBe(false);
10+
});
11+
12+
it("should be false when the lifecycle does not contain the hook", () => {
13+
var d = new Directive({lifecycle:[]});
14+
expect(d.hasLifecycleHook(onChange)).toBe(false);
15+
});
16+
17+
it("should be true otherwise", () => {
18+
var d = new Directive({lifecycle:[onChange]});
19+
expect(d.hasLifecycleHook(onChange)).toBe(true);
20+
});
21+
});
22+
});
23+
}

modules/angular2/test/core/compiler/element_injector_spec.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,14 +330,25 @@ export function main() {
330330
expect(inj.get(SimpleDirective)).toBeAnInstanceOf(SimpleDirective);
331331
});
332332

333-
it("should allow for direct access using getAtIndex", function () {
333+
it("should allow for direct access using getDirectiveAtIndex", function () {
334334
var inj = injector([
335335
DirectiveBinding.createFromBinding(bind(SimpleDirective).toClass(SimpleDirective), null)
336336
]);
337-
expect(inj.getAtIndex(0)).toBeAnInstanceOf(SimpleDirective);
338-
expect(() => inj.getAtIndex(-1)).toThrowError(
337+
expect(inj.getDirectiveAtIndex(0)).toBeAnInstanceOf(SimpleDirective);
338+
expect(() => inj.getDirectiveAtIndex(-1)).toThrowError(
339339
'Index -1 is out-of-bounds.');
340-
expect(() => inj.getAtIndex(10)).toThrowError(
340+
expect(() => inj.getDirectiveAtIndex(10)).toThrowError(
341+
'Index 10 is out-of-bounds.');
342+
});
343+
344+
it("should allow for direct access using getBindingAtIndex", function () {
345+
var inj = injector([
346+
DirectiveBinding.createFromBinding(bind(SimpleDirective).toClass(SimpleDirective), null)
347+
]);
348+
expect(inj.getDirectiveBindingAtIndex(0)).toBeAnInstanceOf(DirectiveBinding);
349+
expect(() => inj.getDirectiveBindingAtIndex(-1)).toThrowError(
350+
'Index -1 is out-of-bounds.');
351+
expect(() => inj.getDirectiveBindingAtIndex(10)).toThrowError(
341352
'Index 10 is out-of-bounds.');
342353
});
343354

modules/angular2/test/core/compiler/view_spec.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import {describe, xit, it, expect, beforeEach, ddescribe, iit, el} from 'angular2/test_lib';
22
import {ProtoView, ElementPropertyMemento, DirectivePropertyMemento} from 'angular2/src/core/compiler/view';
3-
import {ProtoElementInjector, ElementInjector} from 'angular2/src/core/compiler/element_injector';
3+
import {ProtoElementInjector, ElementInjector, DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
44
import {EmulatedShadowDomStrategy, NativeShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy';
55
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
6-
import {Component, Decorator, Template} from 'angular2/src/core/annotations/annotations';
7-
import {OnChange} from 'angular2/core';
6+
import {Component, Decorator, Template, Directive, onChange} from 'angular2/src/core/annotations/annotations';
87
import {Lexer, Parser, DynamicProtoChangeDetector,
98
ChangeDetector} from 'angular2/change_detection';
109
import {TemplateConfig} from 'angular2/src/core/annotations/template_config';
@@ -546,7 +545,9 @@ export function main() {
546545
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
547546
new DynamicProtoChangeDetector(), null);
548547

549-
pv.bindElement(new ProtoElementInjector(null, 0, [DirectiveImplementingOnChange]));
548+
pv.bindElement(new ProtoElementInjector(null, 0, [
549+
DirectiveBinding.createFromType(DirectiveImplementingOnChange, new Directive({lifecycle: [onChange]}))
550+
]));
550551
pv.bindDirectiveProperty( 0, parser.parseBinding('a', null), 'a', reflector.setter('a'), false);
551552
pv.bindDirectiveProperty( 0, parser.parseBinding('b', null), 'b', reflector.setter('b'), false);
552553
createViewAndChangeDetector(pv);
@@ -563,7 +564,9 @@ export function main() {
563564
var pv = new ProtoView(el('<div class="ng-binding"></div>'),
564565
new DynamicProtoChangeDetector(), null);
565566

566-
pv.bindElement(new ProtoElementInjector(null, 0, [DirectiveImplementingOnChange]));
567+
pv.bindElement(new ProtoElementInjector(null, 0, [
568+
DirectiveBinding.createFromType(DirectiveImplementingOnChange, new Directive({lifecycle: [onChange]}))
569+
]));
567570
pv.bindDirectiveProperty( 0, parser.parseBinding('a', null), 'a', reflector.setter('a'), false);
568571
pv.bindDirectiveProperty( 0, parser.parseBinding('b', null), 'b', reflector.setter('b'), false);
569572
createViewAndChangeDetector(pv);
@@ -616,7 +619,7 @@ class SomeDirective {
616619
}
617620
}
618621

619-
class DirectiveImplementingOnChange extends OnChange {
622+
class DirectiveImplementingOnChange {
620623
a;
621624
b;
622625
c;

0 commit comments

Comments
 (0)