X Tutup
Skip to content

Commit 5bfcca2

Browse files
committed
feat(query): notify on changes
1 parent 73d1525 commit 5bfcca2

File tree

11 files changed

+129
-7
lines changed

11 files changed

+129
-7
lines changed

modules/angular2/src/change_detection/change_detection_jit_generator.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,12 @@ export class ChangeDetectorJITGenerator {
203203
}
204204
}
205205

206-
return notifications.join("\n");
206+
var directiveNotifications = notifications.join("\n");
207+
208+
return `
209+
this.dispatcher.notifyOnAllChangesDone();
210+
${directiveNotifications}
211+
`;
207212
}
208213

209214
_genLocalDefinitions(): string { return this._localNames.map((n) => `var ${n};`).join("\n"); }

modules/angular2/src/change_detection/dynamic_change_detector.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
110110
}
111111

112112
callOnAllChangesDone() {
113+
this.dispatcher.notifyOnAllChangesDone();
113114
var dirs = this.directiveRecords;
114115
for (var i = dirs.length - 1; i >= 0; --i) {
115116
var dir = dirs[i];

modules/angular2/src/core/compiler/base_query_list.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ export class BaseQueryList<T> {
2626
this._dirty = true;
2727
}
2828

29-
// TODO(rado): hook up with change detection after #995.
3029
fireCallbacks() {
3130
if (this._dirty) {
3231
ListWrapper.forEach(this._callbacks, (c) => c());

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,15 @@ export class ElementInjector extends TreeNode<ElementInjector> {
707707
}
708708
}
709709

710+
onAllChangesDone(): void {
711+
if (isPresent(this._query0) && this._query0.originator === this)
712+
this._query0.list.fireCallbacks();
713+
if (isPresent(this._query1) && this._query1.originator === this)
714+
this._query1.list.fireCallbacks();
715+
if (isPresent(this._query2) && this._query2.originator === this)
716+
this._query2.list.fireCallbacks();
717+
}
718+
710719
hydrate(injector: Injector, host: ElementInjector, preBuiltObjects: PreBuiltObjects): void {
711720
var p = this._proto;
712721

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ export class AppView implements ChangeDispatcher, EventDispatcher {
111111
}
112112
}
113113

114+
notifyOnAllChangesDone(): void {
115+
var ei = this.elementInjectors;
116+
for (var i = ei.length - 1; i >= 0; i--) {
117+
if (isPresent(ei[i])) ei[i].onAllChangesDone();
118+
}
119+
}
120+
114121
getDirectiveFor(directive: DirectiveIndex) {
115122
var elementInjector = this.elementInjectors[directive.elementIndex];
116123
return elementInjector.getDirectiveAtIndex(directive.directiveIndex);

modules/angular2/src/transform/template_compiler/change_detector_codegen.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,11 +262,15 @@ class _CodegenState {
262262
/// them.
263263
String _getCallOnAllChangesDoneBody() {
264264
// NOTE(kegluneq): Order is important!
265-
return _directiveRecords.reversed
265+
var directiveNotifications = _directiveRecords.reversed
266266
.where((rec) => rec.callOnAllChangesDone)
267267
.map((rec) =>
268268
'${_genGetDirective(rec.directiveIndex)}.onAllChangesDone();')
269269
.join('');
270+
return '''
271+
_dispatcher.notifyOnAllChangesDone();
272+
${directiveNotifications}
273+
''';
270274
}
271275

272276
String _genLocalDefinitions() =>

modules/angular2/test/change_detection/change_detector_spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,12 @@ export function main() {
324324
});
325325
});
326326

327+
it('should notify the dispatcher on all changes done', () => {
328+
var val = _createChangeDetector('name', new Person('bob'));
329+
val.changeDetector.detectChanges();
330+
expect(val.dispatcher.onAllChangesDoneCalled).toEqual(true);
331+
});
332+
327333
describe('updating directives', () => {
328334
var directive1;
329335
var directive2;
@@ -975,6 +981,7 @@ class FakeDirectives {
975981
class TestDispatcher extends ChangeDispatcher {
976982
log: List<string>;
977983
loggedValues: List<any>;
984+
onAllChangesDoneCalled: boolean = false;
978985

979986
constructor() {
980987
super();
@@ -984,13 +991,16 @@ class TestDispatcher extends ChangeDispatcher {
984991
clear() {
985992
this.log = ListWrapper.create();
986993
this.loggedValues = ListWrapper.create();
994+
this.onAllChangesDoneCalled = true;
987995
}
988996

989997
notifyOnBinding(binding, value) {
990998
ListWrapper.push(this.log, `${binding.propertyName}=${this._asString(value)}`);
991999
ListWrapper.push(this.loggedValues, value);
9921000
}
9931001

1002+
notifyOnAllChangesDone() { this.onAllChangesDoneCalled = true; }
1003+
9941004
_asString(value) { return (isBlank(value) ? 'null' : value.toString()); }
9951005
}
9961006

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

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
beforeEach,
1313
SpyObject,
1414
proxy,
15+
inject,
16+
AsyncTestCompleter,
1517
el,
1618
containsRegexp
1719
} from 'angular2/test_lib';
@@ -730,7 +732,7 @@ export function main() {
730732
expect(d.dependency).toBeAnInstanceOf(SimpleDirective);
731733
});
732734

733-
it("should throw when a depenency cannot be resolved", () => {
735+
it("should throw when a dependency cannot be resolved", () => {
734736
expect(() => injector(ListWrapper.concat([NeedsDirectiveFromParent], extraBindings)))
735737
.toThrowError(containsRegexp(
736738
`No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirectiveFromParent) } -> ${stringify(SimpleDirective) })`));
@@ -818,7 +820,7 @@ export function main() {
818820
});
819821

820822
describe("lifecycle", () => {
821-
it("should call onDestroy on directives subscribed to this event", function() {
823+
it("should call onDestroy on directives subscribed to this event", () => {
822824
var inj = injector(ListWrapper.concat(
823825
[DirectiveBinding.createFromType(DirectiveWithDestroy,
824826
new dirAnn.Directive({lifecycle: [onDestroy]}))],
@@ -828,13 +830,45 @@ export function main() {
828830
expect(destroy.onDestroyCounter).toBe(1);
829831
});
830832

831-
it("should work with services", function() {
833+
it("should work with services", () => {
832834
var inj = injector(ListWrapper.concat(
833835
[DirectiveBinding.createFromType(
834836
SimpleDirective, new dirAnn.Directive({hostInjector: [SimpleService]}))],
835837
extraBindings));
836838
inj.dehydrate();
837839
});
840+
841+
it("should notify queries", inject([AsyncTestCompleter], (async) => {
842+
var inj = injector(ListWrapper.concat([NeedsQuery], extraBindings));
843+
var query = inj.get(NeedsQuery).query;
844+
query.add(new CountingDirective()); // this marks the query as dirty
845+
846+
query.onChange(() => async.done());
847+
848+
inj.onAllChangesDone();
849+
}));
850+
851+
it("should not notify inherited queries", inject([AsyncTestCompleter], (async) => {
852+
var child = parentChildInjectors(ListWrapper.concat([NeedsQuery], extraBindings), []);
853+
854+
var query = child.parent.get(NeedsQuery).query;
855+
856+
var calledOnChange = false;
857+
query.onChange(() => {
858+
// make sure the callback is called only once
859+
expect(calledOnChange).toEqual(false);
860+
expect(query.length).toEqual(2);
861+
862+
calledOnChange = true;
863+
async.done()
864+
});
865+
866+
query.add(new CountingDirective());
867+
child.onAllChangesDone(); // this does not notify the query
868+
869+
query.add(new CountingDirective());
870+
child.parent.onAllChangesDone();
871+
}));
838872
});
839873

840874
describe("dynamicallyCreateComponent", () => {

modules/angular2/test/core/compiler/query_integration_spec.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {QueryList} from 'angular2/core';
1818
import {Query, Component, Directive, View} from 'angular2/annotations';
1919

2020
import {NgIf, NgFor} from 'angular2/angular2';
21+
import {ListWrapper} from 'angular2/src/facade/collection';
2122

2223
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
2324

@@ -120,6 +121,55 @@ export function main() {
120121
async.done();
121122
});
122123
}));
124+
125+
126+
it('should notify query on change',
127+
inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => {
128+
var template = '<needs-query-desc #q>' +
129+
'<div text="1"></div>' +
130+
'<div *ng-if="shouldShow" text="2"></div>' +
131+
'</needs-query-desc>';
132+
133+
tb.createView(MyComp, {html: template})
134+
.then((view) => {
135+
var q = view.rawView.locals.get("q");
136+
view.detectChanges();
137+
138+
q.query.onChange(() => {
139+
expect(q.query.first.text).toEqual("1");
140+
expect(q.query.last.text).toEqual("2");
141+
async.done();
142+
});
143+
144+
view.context.shouldShow = true;
145+
view.detectChanges();
146+
});
147+
}));
148+
149+
it("should notify child's query before notifying parent's query",
150+
inject([TestBed, AsyncTestCompleter], (tb: TestBed, async) => {
151+
var template = '<needs-query-desc #q1>' +
152+
'<needs-query-desc #q2>' +
153+
'<div text="1"></div>' +
154+
'</needs-query-desc>' +
155+
'</needs-query-desc>';
156+
157+
tb.createView(MyComp, {html: template})
158+
.then((view) => {
159+
var q1 = view.rawView.locals.get("q1");
160+
var q2 = view.rawView.locals.get("q2");
161+
162+
var firedQ2 = false;
163+
164+
q2.query.onChange(() => { firedQ2 = true; });
165+
q1.query.onChange(() => {
166+
expect(firedQ2).toBe(true);
167+
async.done();
168+
});
169+
170+
view.detectChanges();
171+
});
172+
}));
123173
});
124174
}
125175

modules/angular2/test/transform/integration/two_annotations_files/expected/bar.ng_deps.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ class _MyComponent_ChangeDetector0 extends _gen.AbstractChangeDetector {
5151
_alreadyChecked = true;
5252
}
5353

54-
void callOnAllChangesDone() {}
54+
void callOnAllChangesDone() {
55+
_dispatcher.notifyOnAllChangesDone();
56+
}
5557

5658
void hydrate(MyComponent context, locals, directives) {
5759
mode = 'ALWAYS_CHECK';

0 commit comments

Comments
 (0)
X Tutup