@angular-wave/angular.ts 0.4.2 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular-ts.esm.js +2 -2
- package/dist/angular-ts.umd.js +12 -2
- package/index.html +74 -3
- package/package.json +7 -7
- package/src/angular.spec.js +1 -269
- package/src/animations/animate-css-driver.js +2 -2
- package/src/animations/animate-css.js +12 -21
- package/src/animations/animate-js-driver.js +1 -3
- package/src/animations/animate-js.js +4 -4
- package/src/animations/animate-queue.js +23 -23
- package/src/animations/animate-runner.js +4 -8
- package/src/animations/animate.md +1 -1
- package/src/animations/animate.spec.js +0 -21
- package/src/animations/animation.js +4 -4
- package/src/animations/shared.js +14 -12
- package/src/binding.spec.js +0 -1
- package/src/core/cache/cache.js +2 -29
- package/src/core/compile/attributes.js +2 -3
- package/src/core/compile/compile.js +260 -245
- package/src/core/compile/compile.spec.js +63 -317
- package/src/core/compile/compile.test.js +1 -1
- package/src/core/controller/controller.js +2 -0
- package/src/core/di/injector.md +1 -1
- package/src/core/di/injector.spec.js +0 -2
- package/src/core/di/internal-injector.js +2 -1
- package/src/core/interpolate/interpolate.js +16 -3
- package/src/core/interpolate/interpolate.spec.js +70 -16
- package/src/core/location/location.js +0 -2
- package/src/core/location/location.spec.js +27 -27
- package/src/core/{scope/scope.html → model/model.html} +1 -1
- package/src/core/model/model.js +944 -0
- package/src/core/model/model.spec.js +3012 -0
- package/src/core/on.spec.js +0 -7
- package/src/core/parse/interpreter.js +10 -7
- package/src/core/parse/parse.js +28 -7
- package/src/core/parse/parse.spec.js +95 -91
- package/src/core/prop.spec.js +4 -60
- package/src/core/sce/sce.js +1 -2
- package/src/core/sce/sce.spec.js +0 -8
- package/src/core/scope/scope.js +62 -32
- package/src/core/scope/scope.spec.js +25 -1960
- package/src/directive/aria/aria.js +3 -6
- package/src/directive/aria/aria.spec.js +0 -87
- package/src/directive/attrs/attrs.spec.js +0 -5
- package/src/directive/{list/list.test.js → attrs/attrs.test.js} +1 -1
- package/src/{core/q/q.html → directive/attrs/boolean.html} +1 -1
- package/src/directive/attrs/boolean.spec.js +0 -15
- package/src/{core/q/q.test.js → directive/attrs/boolean.test.js} +1 -2
- package/src/{core/timeout/timeout.html → directive/attrs/element-style.html} +4 -1
- package/src/directive/attrs/element-style.spec.js +0 -8
- package/src/{core/scope/scope.test.js → directive/attrs/element-style.test.js} +1 -2
- package/src/directive/attrs/src.spec.js +0 -7
- package/src/directive/bind/bind.spec.js +0 -33
- package/src/directive/bind/bing-html.spec.js +1 -4
- package/src/{core/interval/interval.html → directive/channel/channel.html} +1 -1
- package/src/directive/channel/channel.js +29 -0
- package/src/directive/channel/channel.spec.js +52 -0
- package/src/directive/channel/channel.test.js +9 -0
- package/src/directive/class/class.js +3 -3
- package/src/directive/class/class.spec.js +9 -75
- package/src/directive/controller/controller.spec.js +0 -13
- package/src/directive/events/click.spec.js +0 -3
- package/src/directive/events/event.spec.js +0 -6
- package/src/directive/form/form.js +14 -22
- package/src/directive/form/form.spec.js +0 -65
- package/src/directive/if/if.spec.js +2 -7
- package/src/directive/if/if.test.js +1 -2
- package/src/directive/include/include.js +2 -2
- package/src/directive/include/include.spec.js +8 -59
- package/src/directive/init/init.js +6 -2
- package/src/directive/init/init.spec.js +0 -2
- package/src/directive/input/input.js +1 -2
- package/src/directive/input/input.spec.js +191 -331
- package/src/directive/messages/messages.spec.js +4 -35
- package/src/directive/model/model.js +30 -42
- package/src/directive/model/model.spec.js +2 -49
- package/src/directive/model-options/model-options.js +22 -26
- package/src/directive/model-options/model-options.spec.js +0 -6
- package/src/directive/non-bindable/non-bindable.spec.js +0 -1
- package/src/directive/observe/observe.js +0 -1
- package/src/directive/observe/observe.spec.js +0 -1
- package/src/directive/options/options.js +1 -3
- package/src/directive/options/options.spec.js +3 -38
- package/src/directive/ref/href.spec.js +0 -15
- package/src/directive/repeat/repeat.js +2 -2
- package/src/directive/repeat/repeat.spec.js +56 -192
- package/src/directive/script/script.spec.js +0 -2
- package/src/directive/select/select.js +3 -3
- package/src/directive/select/select.spec.js +9 -106
- package/src/directive/show-hide/show-hide.js +2 -2
- package/src/directive/show-hide/show-hide.spec.js +8 -19
- package/src/directive/style/style.spec.js +0 -7
- package/src/directive/switch/switch.js +1 -2
- package/src/directive/switch/switch.spec.js +5 -5
- package/src/directive/validators/validators.spec.js +0 -1
- package/src/loader.js +0 -1
- package/src/public.js +75 -80
- package/src/router/common/coreservices.js +0 -2
- package/src/router/directives/state-directives.js +24 -30
- package/src/router/directives/state-directives.spec.js +0 -83
- package/src/router/directives/view-directive.js +6 -15
- package/src/router/directives/view-directive.spec.js +25 -71
- package/src/router/hooks/lazy-load.js +2 -2
- package/src/router/hooks/views.js +3 -5
- package/src/router/resolve/resolvable.js +3 -6
- package/src/router/resolve/resolve-context.js +2 -2
- package/src/router/state/state-service.js +4 -4
- package/src/router/state/state.spec.js +2 -5
- package/src/router/state/views.js +9 -12
- package/src/router/template-factory.js +3 -6
- package/src/router/template-factory.spec.js +0 -4
- package/src/router/transition/transition-hook.js +1 -1
- package/src/router/transition/transition.js +1 -1
- package/src/router/url/url-service.js +2 -8
- package/src/router/url/url-service.spec.js +3 -4
- package/src/router/view-hook.spec.js +2 -2
- package/src/router/view-scroll.js +4 -6
- package/src/services/http/http.js +11 -15
- package/src/services/http/http.spec.js +30 -31
- package/src/services/http/template-request.spec.js +0 -10
- package/src/services/http-backend/http-backend.js +19 -17
- package/src/services/http-backend/http-backend.spec.js +3 -3
- package/src/services/template-request.js +2 -4
- package/src/shared/common.js +6 -10
- package/src/shared/jqlite/jqlite.js +14 -15
- package/src/shared/jqlite/jqlite.spec.js +2 -2
- package/src/shared/utils.js +15 -92
- package/types/core/cache/cache.d.ts +1 -1
- package/types/core/model/model.d.ts +204 -0
- package/types/core/parse/parse.d.ts +26 -0
- package/types/core/scope/scope.d.ts +22 -21
- package/types/directive/channel/channel.d.ts +11 -0
- package/types/directive/form/form.d.ts +1 -0
- package/types/shared/common.d.ts +0 -1
- package/types/shared/utils.d.ts +0 -35
- package/src/core/interval/interval-factory.js +0 -50
- package/src/core/interval/interval.js +0 -77
- package/src/core/interval/interval.md +0 -123
- package/src/core/interval/interval.spec.js +0 -280
- package/src/core/q/q.js +0 -472
- package/src/core/q/q.md +0 -211
- package/src/core/q/q.spec.js +0 -2748
- package/src/core/timeout/timeout.js +0 -109
- package/src/core/timeout/timeout.spec.js +0 -354
- package/src/core/timeout/timout.test.js +0 -12
- package/src/directive/list/list.html +0 -18
- package/src/directive/list/list.js +0 -46
- package/src/directive/list/list.md +0 -22
- package/src/directive/list/list.spec.js +0 -172
- package/types/directive/list/list.d.ts +0 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $$asyncQueue, Scope } from "./scope";
|
|
1
|
+
import { $$asyncQueue, Scope, ScopePhase } from "./scope";
|
|
2
2
|
import { extend, sliceArgs } from "../../shared/utils";
|
|
3
3
|
import { Angular } from "../../loader";
|
|
4
4
|
import { createInjector } from "../di/injector";
|
|
@@ -9,6 +9,7 @@ describe("Scope", function () {
|
|
|
9
9
|
let $browser;
|
|
10
10
|
let logs;
|
|
11
11
|
let scope;
|
|
12
|
+
let injector;
|
|
12
13
|
|
|
13
14
|
beforeEach(() => {
|
|
14
15
|
logs = [];
|
|
@@ -23,7 +24,7 @@ describe("Scope", function () {
|
|
|
23
24
|
};
|
|
24
25
|
});
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
injector = createInjector(["myModule"]);
|
|
27
28
|
$parse = injector.get("$parse");
|
|
28
29
|
$browser = injector.get("$browser");
|
|
29
30
|
|
|
@@ -135,7 +136,7 @@ describe("Scope", function () {
|
|
|
135
136
|
|
|
136
137
|
it("should attach the child scope to a specified parent", () => {
|
|
137
138
|
const isolated = $rootScope.$new(true);
|
|
138
|
-
const trans = $rootScope.$
|
|
139
|
+
const trans = $rootScope.$transcluded(isolated);
|
|
139
140
|
$rootScope.a = 123;
|
|
140
141
|
expect(isolated.a).toBeUndefined();
|
|
141
142
|
expect(trans.a).toEqual(123);
|
|
@@ -196,822 +197,6 @@ describe("Scope", function () {
|
|
|
196
197
|
});
|
|
197
198
|
|
|
198
199
|
describe("$watch/$digest", () => {
|
|
199
|
-
it("calls the listener function of a watch on first $digest", function () {
|
|
200
|
-
var watchFn = function () {
|
|
201
|
-
return "wat";
|
|
202
|
-
};
|
|
203
|
-
var listenerFn = jasmine.createSpy();
|
|
204
|
-
$rootScope.$watch(watchFn, listenerFn);
|
|
205
|
-
$rootScope.$digest();
|
|
206
|
-
expect(listenerFn).toHaveBeenCalled();
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it("calls the watch function with the scope as the argument", function () {
|
|
210
|
-
var watchFn = jasmine.createSpy();
|
|
211
|
-
var listenerFn = function () {};
|
|
212
|
-
$rootScope.$watch(watchFn, listenerFn);
|
|
213
|
-
$rootScope.$digest();
|
|
214
|
-
expect(watchFn).toHaveBeenCalledWith($rootScope);
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it("calls the listener function when the watched value changes", function () {
|
|
218
|
-
scope.someValue = "a";
|
|
219
|
-
scope.counter = 0;
|
|
220
|
-
scope.$watch(
|
|
221
|
-
function (scope) {
|
|
222
|
-
return scope.someValue;
|
|
223
|
-
},
|
|
224
|
-
function (newValue, oldValue, scope) {
|
|
225
|
-
scope.counter++;
|
|
226
|
-
},
|
|
227
|
-
);
|
|
228
|
-
expect(scope.counter).toBe(0);
|
|
229
|
-
scope.$digest();
|
|
230
|
-
expect(scope.counter).toBe(1);
|
|
231
|
-
scope.$digest();
|
|
232
|
-
expect(scope.counter).toBe(1);
|
|
233
|
-
scope.someValue = "b";
|
|
234
|
-
expect(scope.counter).toBe(1);
|
|
235
|
-
scope.$digest();
|
|
236
|
-
expect(scope.counter).toBe(2);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it("should watch and fire on simple property change", () => {
|
|
240
|
-
const spy = jasmine.createSpy();
|
|
241
|
-
$rootScope.$watch("name", spy);
|
|
242
|
-
$rootScope.$digest();
|
|
243
|
-
spy.calls.reset();
|
|
244
|
-
|
|
245
|
-
expect(spy).not.toHaveBeenCalled();
|
|
246
|
-
$rootScope.$digest();
|
|
247
|
-
expect(spy).not.toHaveBeenCalled();
|
|
248
|
-
$rootScope.name = "misko";
|
|
249
|
-
$rootScope.$digest();
|
|
250
|
-
expect(spy).toHaveBeenCalledWith("misko", undefined, $rootScope);
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it("should not expose the `inner working of watch", () => {
|
|
254
|
-
function Getter() {
|
|
255
|
-
expect(this).toBeUndefined();
|
|
256
|
-
return "foo";
|
|
257
|
-
}
|
|
258
|
-
function Listener() {
|
|
259
|
-
expect(this).toBeUndefined();
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
$rootScope.$watch(Getter, Listener);
|
|
263
|
-
$rootScope.$digest();
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
it("should watch and fire on expression change", () => {
|
|
267
|
-
const spy = jasmine.createSpy();
|
|
268
|
-
$rootScope.$watch("name.first", spy);
|
|
269
|
-
$rootScope.$digest();
|
|
270
|
-
spy.calls.reset();
|
|
271
|
-
|
|
272
|
-
$rootScope.name = {};
|
|
273
|
-
expect(spy).not.toHaveBeenCalled();
|
|
274
|
-
$rootScope.$digest();
|
|
275
|
-
expect(spy).not.toHaveBeenCalled();
|
|
276
|
-
$rootScope.name.first = "misko";
|
|
277
|
-
$rootScope.$digest();
|
|
278
|
-
expect(spy).toHaveBeenCalled();
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
it("should decrement the watcherCount when destroying a child scope", () => {
|
|
282
|
-
const child1 = $rootScope.$new();
|
|
283
|
-
const child2 = $rootScope.$new();
|
|
284
|
-
const grandChild1 = child1.$new();
|
|
285
|
-
const grandChild2 = child2.$new();
|
|
286
|
-
child1.$watch("a", () => {});
|
|
287
|
-
child2.$watch("a", () => {});
|
|
288
|
-
grandChild1.$watch("a", () => {});
|
|
289
|
-
grandChild2.$watch("a", () => {});
|
|
290
|
-
|
|
291
|
-
expect($rootScope.$$watchersCount).toBe(4);
|
|
292
|
-
expect(child1.$$watchersCount).toBe(2);
|
|
293
|
-
expect(child2.$$watchersCount).toBe(2);
|
|
294
|
-
expect(grandChild1.$$watchersCount).toBe(1);
|
|
295
|
-
expect(grandChild2.$$watchersCount).toBe(1);
|
|
296
|
-
|
|
297
|
-
grandChild2.$destroy();
|
|
298
|
-
expect(child2.$$watchersCount).toBe(1);
|
|
299
|
-
expect($rootScope.$$watchersCount).toBe(3);
|
|
300
|
-
child1.$destroy();
|
|
301
|
-
expect($rootScope.$$watchersCount).toBe(1);
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
it("should decrement the watcherCount when calling the remove function", () => {
|
|
305
|
-
const child1 = $rootScope.$new();
|
|
306
|
-
const child2 = $rootScope.$new();
|
|
307
|
-
const grandChild1 = child1.$new();
|
|
308
|
-
const grandChild2 = child2.$new();
|
|
309
|
-
let remove1;
|
|
310
|
-
let remove2;
|
|
311
|
-
|
|
312
|
-
remove1 = child1.$watch("a", () => {});
|
|
313
|
-
child2.$watch("a", () => {});
|
|
314
|
-
grandChild1.$watch("a", () => {});
|
|
315
|
-
remove2 = grandChild2.$watch("a", () => {});
|
|
316
|
-
|
|
317
|
-
remove2();
|
|
318
|
-
expect(grandChild2.$$watchersCount).toBe(0);
|
|
319
|
-
expect(child2.$$watchersCount).toBe(1);
|
|
320
|
-
expect($rootScope.$$watchersCount).toBe(3);
|
|
321
|
-
remove1();
|
|
322
|
-
expect(grandChild1.$$watchersCount).toBe(1);
|
|
323
|
-
expect(child1.$$watchersCount).toBe(1);
|
|
324
|
-
expect($rootScope.$$watchersCount).toBe(2);
|
|
325
|
-
|
|
326
|
-
// Execute everything a second time to be sure that calling the remove function
|
|
327
|
-
// several times, it only decrements the counter once
|
|
328
|
-
remove2();
|
|
329
|
-
expect(child2.$$watchersCount).toBe(1);
|
|
330
|
-
expect($rootScope.$$watchersCount).toBe(2);
|
|
331
|
-
remove1();
|
|
332
|
-
expect(child1.$$watchersCount).toBe(1);
|
|
333
|
-
expect($rootScope.$$watchersCount).toBe(2);
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
describe("constants cleanup", () => {
|
|
337
|
-
beforeEach(() => (logs = []));
|
|
338
|
-
it("should remove $watch of constant literals after initial digest", () => {
|
|
339
|
-
$rootScope.$watch("[]", () => {});
|
|
340
|
-
$rootScope.$watch("{}", () => {});
|
|
341
|
-
$rootScope.$watch("1", () => {});
|
|
342
|
-
$rootScope.$watch('"foo"', () => {});
|
|
343
|
-
expect($rootScope.$$watchers.length).not.toEqual(0);
|
|
344
|
-
$rootScope.$digest();
|
|
345
|
-
|
|
346
|
-
expect($rootScope.$$watchers.length).toEqual(0);
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
it("should remove $watchCollection of constant literals after initial digest", () => {
|
|
350
|
-
$rootScope.$watchCollection("[]", () => {});
|
|
351
|
-
$rootScope.$watchCollection("{}", () => {});
|
|
352
|
-
$rootScope.$watchCollection("1", () => {});
|
|
353
|
-
$rootScope.$watchCollection('"foo"', () => {});
|
|
354
|
-
expect($rootScope.$$watchers.length).not.toEqual(0);
|
|
355
|
-
$rootScope.$digest();
|
|
356
|
-
|
|
357
|
-
expect($rootScope.$$watchers.length).toEqual(0);
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
it("should remove $watchGroup of constant literals after initial digest", () => {
|
|
361
|
-
$rootScope.$watchGroup(["[]", "{}", "1", '"foo"'], () => {});
|
|
362
|
-
expect($rootScope.$$watchers.length).not.toEqual(0);
|
|
363
|
-
$rootScope.$digest();
|
|
364
|
-
|
|
365
|
-
expect($rootScope.$$watchers.length).toEqual(0);
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
it("should remove $watch of filtered constant literals after initial digest", () => {
|
|
369
|
-
$rootScope.$watch('[1] | filter:"x"', () => {});
|
|
370
|
-
$rootScope.$watch("1 | limitTo:2", () => {});
|
|
371
|
-
expect($rootScope.$$watchers.length).not.toEqual(0);
|
|
372
|
-
$rootScope.$digest();
|
|
373
|
-
|
|
374
|
-
expect($rootScope.$$watchers.length).toEqual(0);
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
it("should remove $watchCollection of filtered constant literals after initial digest", () => {
|
|
378
|
-
$rootScope.$watchCollection('[1] | filter:"x"', () => {});
|
|
379
|
-
expect($rootScope.$$watchers.length).not.toEqual(0);
|
|
380
|
-
$rootScope.$digest();
|
|
381
|
-
|
|
382
|
-
expect($rootScope.$$watchers.length).toEqual(0);
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
it("should remove $watchGroup of filtered constant literals after initial digest", () => {
|
|
386
|
-
$rootScope.$watchGroup(['[1] | filter:"x"', "1 | limitTo:2"], () => {});
|
|
387
|
-
expect($rootScope.$$watchers.length).not.toEqual(0);
|
|
388
|
-
$rootScope.$digest();
|
|
389
|
-
|
|
390
|
-
expect($rootScope.$$watchers.length).toEqual(0);
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
it("should remove $watch of constant expressions after initial digest", () => {
|
|
394
|
-
$rootScope.$watch("1 + 1", () => {});
|
|
395
|
-
$rootScope.$watch('"a" + "b"', () => {});
|
|
396
|
-
$rootScope.$watch('"ab".length', () => {});
|
|
397
|
-
$rootScope.$watch("[].length", () => {});
|
|
398
|
-
$rootScope.$watch("(1 + 1) | limitTo:2", () => {});
|
|
399
|
-
expect($rootScope.$$watchers.length).not.toEqual(0);
|
|
400
|
-
$rootScope.$digest();
|
|
401
|
-
|
|
402
|
-
expect($rootScope.$$watchers.length).toEqual(0);
|
|
403
|
-
});
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
describe("onetime cleanup", () => {
|
|
407
|
-
it("should clean up stable watches on the watch queue", () => {
|
|
408
|
-
$rootScope.$watch("::foo", () => {});
|
|
409
|
-
expect($rootScope.$$watchers.length).toEqual(1);
|
|
410
|
-
$rootScope.$digest();
|
|
411
|
-
expect($rootScope.$$watchers.length).toEqual(1);
|
|
412
|
-
|
|
413
|
-
$rootScope.foo = "foo";
|
|
414
|
-
$rootScope.$digest();
|
|
415
|
-
expect($rootScope.$$watchers.length).toEqual(0);
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
it("should clean up stable watches from $watchCollection", () => {
|
|
419
|
-
$rootScope.$watchCollection("::foo", () => {});
|
|
420
|
-
expect($rootScope.$$watchers.length).toEqual(1);
|
|
421
|
-
|
|
422
|
-
$rootScope.$digest();
|
|
423
|
-
expect($rootScope.$$watchers.length).toEqual(1);
|
|
424
|
-
|
|
425
|
-
$rootScope.foo = [];
|
|
426
|
-
$rootScope.$digest();
|
|
427
|
-
expect($rootScope.$$watchers.length).toEqual(0);
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
it("should clean up stable watches from $watchCollection literals", () => {
|
|
431
|
-
$rootScope.$watchCollection("::[foo, bar]", () => {});
|
|
432
|
-
expect($rootScope.$$watchers.length).toEqual(1);
|
|
433
|
-
|
|
434
|
-
$rootScope.$digest();
|
|
435
|
-
expect($rootScope.$$watchers.length).toEqual(1);
|
|
436
|
-
|
|
437
|
-
$rootScope.foo = 1;
|
|
438
|
-
$rootScope.$digest();
|
|
439
|
-
expect($rootScope.$$watchers.length).toEqual(1);
|
|
440
|
-
|
|
441
|
-
$rootScope.foo = 2;
|
|
442
|
-
$rootScope.$digest();
|
|
443
|
-
expect($rootScope.$$watchers.length).toEqual(1);
|
|
444
|
-
|
|
445
|
-
$rootScope.bar = 3;
|
|
446
|
-
$rootScope.$digest();
|
|
447
|
-
expect($rootScope.$$watchers.length).toEqual(0);
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
it("should clean up stable watches from $watchGroup", () => {
|
|
451
|
-
$rootScope.$watchGroup(["::foo", "::bar"], () => {});
|
|
452
|
-
expect($rootScope.$$watchers.length).toEqual(2);
|
|
453
|
-
|
|
454
|
-
$rootScope.$digest();
|
|
455
|
-
expect($rootScope.$$watchers.length).toEqual(2);
|
|
456
|
-
|
|
457
|
-
$rootScope.foo = "foo";
|
|
458
|
-
$rootScope.$digest();
|
|
459
|
-
expect($rootScope.$$watchers.length).toEqual(1);
|
|
460
|
-
|
|
461
|
-
$rootScope.bar = "bar";
|
|
462
|
-
$rootScope.$digest();
|
|
463
|
-
expect($rootScope.$$watchers.length).toEqual(0);
|
|
464
|
-
});
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
it("should delegate exceptions", () => {
|
|
468
|
-
$rootScope.$watch("a", () => {
|
|
469
|
-
throw new Error("abc");
|
|
470
|
-
});
|
|
471
|
-
$rootScope.a = 1;
|
|
472
|
-
$rootScope.$digest();
|
|
473
|
-
expect(logs[0]).toMatch(/abc/);
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
it("should fire watches in order of addition", () => {
|
|
477
|
-
// this is not an external guarantee, just our own sanity
|
|
478
|
-
logs = "";
|
|
479
|
-
$rootScope.$watch("a", () => {
|
|
480
|
-
logs += "a";
|
|
481
|
-
});
|
|
482
|
-
$rootScope.$watch("b", () => {
|
|
483
|
-
logs += "b";
|
|
484
|
-
});
|
|
485
|
-
// constant expressions have slightly different handling,
|
|
486
|
-
// let's ensure they are kept in the same list as others
|
|
487
|
-
$rootScope.$watch("1", () => {
|
|
488
|
-
logs += "1";
|
|
489
|
-
});
|
|
490
|
-
$rootScope.$watch("c", () => {
|
|
491
|
-
logs += "c";
|
|
492
|
-
});
|
|
493
|
-
$rootScope.$watch("2", () => {
|
|
494
|
-
logs += "2";
|
|
495
|
-
});
|
|
496
|
-
$rootScope.a = $rootScope.b = $rootScope.c = 1;
|
|
497
|
-
$rootScope.$digest();
|
|
498
|
-
expect(logs).toEqual("ab1c2");
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
it("should call child $watchers in addition order", () => {
|
|
502
|
-
// this is not an external guarantee, just our own sanity
|
|
503
|
-
logs = "";
|
|
504
|
-
const childA = $rootScope.$new();
|
|
505
|
-
const childB = $rootScope.$new();
|
|
506
|
-
const childC = $rootScope.$new();
|
|
507
|
-
childA.$watch("a", () => {
|
|
508
|
-
logs += "a";
|
|
509
|
-
});
|
|
510
|
-
childB.$watch("b", () => {
|
|
511
|
-
logs += "b";
|
|
512
|
-
});
|
|
513
|
-
childC.$watch("c", () => {
|
|
514
|
-
logs += "c";
|
|
515
|
-
});
|
|
516
|
-
childA.a = childB.b = childC.c = 1;
|
|
517
|
-
$rootScope.$digest();
|
|
518
|
-
expect(logs).toEqual("abc");
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
it("should allow $digest on a child scope with and without a right sibling", () => {
|
|
522
|
-
// tests a traversal edge case which we originally missed
|
|
523
|
-
logs = "";
|
|
524
|
-
const childA = $rootScope.$new();
|
|
525
|
-
const childB = $rootScope.$new();
|
|
526
|
-
|
|
527
|
-
$rootScope.$watch(() => {
|
|
528
|
-
logs += "r";
|
|
529
|
-
});
|
|
530
|
-
childA.$watch(() => {
|
|
531
|
-
logs += "a";
|
|
532
|
-
});
|
|
533
|
-
childB.$watch(() => {
|
|
534
|
-
logs += "b";
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
// init
|
|
538
|
-
$rootScope.$digest();
|
|
539
|
-
expect(logs).toBe("rabrab");
|
|
540
|
-
|
|
541
|
-
logs = "";
|
|
542
|
-
childA.$digest();
|
|
543
|
-
expect(logs).toBe("a");
|
|
544
|
-
|
|
545
|
-
logs = "";
|
|
546
|
-
childB.$digest();
|
|
547
|
-
expect(logs).toBe("b");
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
it("should repeat watch cycle while model changes are identified", () => {
|
|
551
|
-
logs = "";
|
|
552
|
-
$rootScope.$watch("c", (v) => {
|
|
553
|
-
$rootScope.d = v;
|
|
554
|
-
logs += "c";
|
|
555
|
-
});
|
|
556
|
-
$rootScope.$watch("b", (v) => {
|
|
557
|
-
$rootScope.c = v;
|
|
558
|
-
logs += "b";
|
|
559
|
-
});
|
|
560
|
-
$rootScope.$watch("a", (v) => {
|
|
561
|
-
$rootScope.b = v;
|
|
562
|
-
logs += "a";
|
|
563
|
-
});
|
|
564
|
-
$rootScope.$digest();
|
|
565
|
-
logs = "";
|
|
566
|
-
$rootScope.a = 1;
|
|
567
|
-
$rootScope.$digest();
|
|
568
|
-
expect($rootScope.b).toEqual(1);
|
|
569
|
-
expect($rootScope.c).toEqual(1);
|
|
570
|
-
expect($rootScope.d).toEqual(1);
|
|
571
|
-
expect(logs).toEqual("abc");
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
it("should repeat watch cycle from the root element", () => {
|
|
575
|
-
logs = "";
|
|
576
|
-
const child = $rootScope.$new();
|
|
577
|
-
$rootScope.$watch(() => {
|
|
578
|
-
logs += "a";
|
|
579
|
-
});
|
|
580
|
-
child.$watch(() => {
|
|
581
|
-
logs += "b";
|
|
582
|
-
});
|
|
583
|
-
$rootScope.$digest();
|
|
584
|
-
expect(logs).toEqual("abab");
|
|
585
|
-
});
|
|
586
|
-
|
|
587
|
-
it("should prevent infinite recursion and print watcher expression", () => {
|
|
588
|
-
$rootScope.$watch("a", function () {
|
|
589
|
-
$rootScope.b++;
|
|
590
|
-
});
|
|
591
|
-
$rootScope.$watch("b", function () {
|
|
592
|
-
$rootScope.a++;
|
|
593
|
-
});
|
|
594
|
-
$rootScope.a = $rootScope.b = 0;
|
|
595
|
-
expect(function () {
|
|
596
|
-
$rootScope.$digest();
|
|
597
|
-
}).toThrow();
|
|
598
|
-
|
|
599
|
-
expect($rootScope.$$phase).toBe(0);
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
it("should prevent infinite recursion and print watcher function name or body", () => {
|
|
603
|
-
$rootScope.$watch(
|
|
604
|
-
() => $rootScope.a,
|
|
605
|
-
() => {
|
|
606
|
-
$rootScope.b++;
|
|
607
|
-
},
|
|
608
|
-
);
|
|
609
|
-
$rootScope.$watch(
|
|
610
|
-
() => $rootScope.b,
|
|
611
|
-
() => {
|
|
612
|
-
$rootScope.a++;
|
|
613
|
-
},
|
|
614
|
-
);
|
|
615
|
-
$rootScope.a = $rootScope.b = 0;
|
|
616
|
-
|
|
617
|
-
try {
|
|
618
|
-
$rootScope.$digest();
|
|
619
|
-
throw new Error("Should have thrown exception");
|
|
620
|
-
} catch (e) {
|
|
621
|
-
console.error(e);
|
|
622
|
-
expect(e.message.match(/rootScope.a/g).length).toBeTruthy();
|
|
623
|
-
expect(e.message.match(/rootScope.b/g).length).toBeTruthy();
|
|
624
|
-
}
|
|
625
|
-
});
|
|
626
|
-
|
|
627
|
-
// it("should prevent infinite loop when creating and resolving a promise in a watched expression", () => {
|
|
628
|
-
// module(($rootScopeProvider) => {
|
|
629
|
-
// $rootScopeProvider.digestTtl(10);
|
|
630
|
-
// });
|
|
631
|
-
// () => {
|
|
632
|
-
// const d = $q.defer();
|
|
633
|
-
|
|
634
|
-
// d.resolve("Hello, world.");
|
|
635
|
-
// $rootScope.$watch(
|
|
636
|
-
// () => {
|
|
637
|
-
// const $d2 = $q.defer();
|
|
638
|
-
// $d2.resolve("Goodbye.");
|
|
639
|
-
// $d2.promise.then(() => {});
|
|
640
|
-
// return d.promise;
|
|
641
|
-
// },
|
|
642
|
-
// () => 0,
|
|
643
|
-
// );
|
|
644
|
-
|
|
645
|
-
// expect(() => {
|
|
646
|
-
// $rootScope.$digest();
|
|
647
|
-
// }).toThrow(
|
|
648
|
-
// "$rootScope",
|
|
649
|
-
// "infdig",
|
|
650
|
-
// "10 $digest() iterations reached. Aborting!\n" +
|
|
651
|
-
// "Watchers fired in the last 5 iterations: []",
|
|
652
|
-
// );
|
|
653
|
-
|
|
654
|
-
// expect($rootScope.$$phase).toBeNull();
|
|
655
|
-
// });
|
|
656
|
-
// });
|
|
657
|
-
|
|
658
|
-
it("should not fire upon $watch registration on initial $digest", () => {
|
|
659
|
-
logs = "";
|
|
660
|
-
$rootScope.a = 1;
|
|
661
|
-
$rootScope.$watch("a", () => {
|
|
662
|
-
logs += "a";
|
|
663
|
-
});
|
|
664
|
-
$rootScope.$watch("b", () => {
|
|
665
|
-
logs += "b";
|
|
666
|
-
});
|
|
667
|
-
$rootScope.$digest();
|
|
668
|
-
logs = "";
|
|
669
|
-
$rootScope.$digest();
|
|
670
|
-
expect(logs).toEqual("");
|
|
671
|
-
});
|
|
672
|
-
|
|
673
|
-
it("should watch objects", () => {
|
|
674
|
-
logs = "";
|
|
675
|
-
$rootScope.a = [];
|
|
676
|
-
$rootScope.b = {};
|
|
677
|
-
$rootScope.$watch(
|
|
678
|
-
"a",
|
|
679
|
-
(value) => {
|
|
680
|
-
logs += ".";
|
|
681
|
-
expect(value).toBe($rootScope.a);
|
|
682
|
-
},
|
|
683
|
-
true,
|
|
684
|
-
);
|
|
685
|
-
$rootScope.$watch(
|
|
686
|
-
"b",
|
|
687
|
-
(value) => {
|
|
688
|
-
logs += "!";
|
|
689
|
-
expect(value).toBe($rootScope.b);
|
|
690
|
-
},
|
|
691
|
-
true,
|
|
692
|
-
);
|
|
693
|
-
$rootScope.$digest();
|
|
694
|
-
logs = "";
|
|
695
|
-
|
|
696
|
-
$rootScope.a.push({});
|
|
697
|
-
$rootScope.b.name = "";
|
|
698
|
-
|
|
699
|
-
$rootScope.$digest();
|
|
700
|
-
expect(logs).toEqual(".!");
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
it("should watch functions", () => {
|
|
704
|
-
$rootScope.fn = function () {
|
|
705
|
-
return "a";
|
|
706
|
-
};
|
|
707
|
-
$rootScope.$watch("fn", (fn) => {
|
|
708
|
-
logs.push(fn());
|
|
709
|
-
});
|
|
710
|
-
$rootScope.$digest();
|
|
711
|
-
expect(logs).toEqual(["a"]);
|
|
712
|
-
$rootScope.fn = function () {
|
|
713
|
-
return "b";
|
|
714
|
-
};
|
|
715
|
-
$rootScope.$digest();
|
|
716
|
-
expect(logs).toEqual(["a", "b"]);
|
|
717
|
-
});
|
|
718
|
-
|
|
719
|
-
it("should prevent $digest recursion", () => {
|
|
720
|
-
let callCount = 0;
|
|
721
|
-
$rootScope.$watch("name", () => {
|
|
722
|
-
expect(() => {
|
|
723
|
-
$rootScope.$digest();
|
|
724
|
-
}).toThrowError(/digest already in progress/);
|
|
725
|
-
callCount++;
|
|
726
|
-
});
|
|
727
|
-
$rootScope.name = "a";
|
|
728
|
-
$rootScope.$digest();
|
|
729
|
-
expect(callCount).toEqual(1);
|
|
730
|
-
});
|
|
731
|
-
|
|
732
|
-
it("should allow a watch to be added while in a digest", () => {
|
|
733
|
-
const watch1 = jasmine.createSpy("watch1");
|
|
734
|
-
const watch2 = jasmine.createSpy("watch2");
|
|
735
|
-
$rootScope.$watch("foo", () => {
|
|
736
|
-
$rootScope.$watch("foo", watch1);
|
|
737
|
-
$rootScope.$watch("foo", watch2);
|
|
738
|
-
});
|
|
739
|
-
$rootScope.$apply("foo = true");
|
|
740
|
-
expect(watch1).toHaveBeenCalled();
|
|
741
|
-
expect(watch2).toHaveBeenCalled();
|
|
742
|
-
});
|
|
743
|
-
|
|
744
|
-
it("should not skip watchers when adding new watchers during digest", () => {
|
|
745
|
-
const watchFn1 = function () {
|
|
746
|
-
logs.push(1);
|
|
747
|
-
};
|
|
748
|
-
const watchFn2 = function () {
|
|
749
|
-
logs.push(2);
|
|
750
|
-
};
|
|
751
|
-
const watchFn3 = function () {
|
|
752
|
-
logs.push(3);
|
|
753
|
-
};
|
|
754
|
-
const addWatcherOnce = function (newValue, oldValue) {
|
|
755
|
-
if (newValue === oldValue) {
|
|
756
|
-
$rootScope.$watch(watchFn3);
|
|
757
|
-
}
|
|
758
|
-
};
|
|
759
|
-
|
|
760
|
-
$rootScope.$watch(watchFn1, addWatcherOnce);
|
|
761
|
-
$rootScope.$watch(watchFn2);
|
|
762
|
-
|
|
763
|
-
$rootScope.$digest();
|
|
764
|
-
|
|
765
|
-
expect(logs).toEqual([1, 2, 3, 1, 2, 3]);
|
|
766
|
-
});
|
|
767
|
-
|
|
768
|
-
it("should not run the current watcher twice when removing a watcher during digest", () => {
|
|
769
|
-
let removeWatcher3;
|
|
770
|
-
|
|
771
|
-
const watchFn3 = function () {
|
|
772
|
-
logs.push(3);
|
|
773
|
-
};
|
|
774
|
-
const watchFn2 = function () {
|
|
775
|
-
logs.push(2);
|
|
776
|
-
};
|
|
777
|
-
const watchFn1 = function () {
|
|
778
|
-
logs.push(1);
|
|
779
|
-
};
|
|
780
|
-
const removeWatcherOnce = function (newValue, oldValue) {
|
|
781
|
-
if (newValue === oldValue) {
|
|
782
|
-
removeWatcher3();
|
|
783
|
-
}
|
|
784
|
-
};
|
|
785
|
-
|
|
786
|
-
$rootScope.$watch(watchFn1, removeWatcherOnce);
|
|
787
|
-
$rootScope.$watch(watchFn2);
|
|
788
|
-
removeWatcher3 = $rootScope.$watch(watchFn3);
|
|
789
|
-
|
|
790
|
-
$rootScope.$digest();
|
|
791
|
-
|
|
792
|
-
expect(logs).toEqual([1, 2, 1, 2]);
|
|
793
|
-
});
|
|
794
|
-
|
|
795
|
-
it("should not skip watchers when removing itself during digest", () => {
|
|
796
|
-
let removeWatcher1;
|
|
797
|
-
|
|
798
|
-
const watchFn3 = function () {
|
|
799
|
-
logs.push(3);
|
|
800
|
-
};
|
|
801
|
-
const watchFn2 = function () {
|
|
802
|
-
logs.push(2);
|
|
803
|
-
};
|
|
804
|
-
const watchFn1 = function () {
|
|
805
|
-
logs.push(1);
|
|
806
|
-
};
|
|
807
|
-
const removeItself = function () {
|
|
808
|
-
removeWatcher1();
|
|
809
|
-
};
|
|
810
|
-
|
|
811
|
-
removeWatcher1 = $rootScope.$watch(watchFn1, removeItself);
|
|
812
|
-
$rootScope.$watch(watchFn2);
|
|
813
|
-
$rootScope.$watch(watchFn3);
|
|
814
|
-
|
|
815
|
-
$rootScope.$digest();
|
|
816
|
-
|
|
817
|
-
expect(logs).toEqual([1, 2, 3, 2, 3]);
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
it("should not infinitely digest when current value is NaN", () => {
|
|
821
|
-
$rootScope.$watch(() => NaN);
|
|
822
|
-
|
|
823
|
-
expect(() => {
|
|
824
|
-
$rootScope.$digest();
|
|
825
|
-
}).not.toThrow();
|
|
826
|
-
});
|
|
827
|
-
|
|
828
|
-
it("should always call the watcher with newVal and oldVal equal on the first run", () => {
|
|
829
|
-
function logger(scope, newVal, oldVal) {
|
|
830
|
-
const val =
|
|
831
|
-
newVal === oldVal || (newVal !== oldVal && oldVal !== newVal)
|
|
832
|
-
? newVal
|
|
833
|
-
: "xxx";
|
|
834
|
-
logs.push(val);
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
$rootScope.$watch(() => NaN, logger);
|
|
838
|
-
$rootScope.$watch(() => undefined, logger);
|
|
839
|
-
$rootScope.$watch(() => "", logger);
|
|
840
|
-
$rootScope.$watch(() => false, logger);
|
|
841
|
-
$rootScope.$watch(() => ({}), logger, true);
|
|
842
|
-
$rootScope.$watch(() => 23, logger);
|
|
843
|
-
|
|
844
|
-
$rootScope.$digest();
|
|
845
|
-
expect(isNaN(logs.shift())).toBe(true); // jasmine's toBe and toEqual don't work well with NaNs
|
|
846
|
-
expect(logs).toEqual([undefined, "", false, {}, 23]);
|
|
847
|
-
logs = [];
|
|
848
|
-
$rootScope.$digest();
|
|
849
|
-
expect(logs).toEqual([]);
|
|
850
|
-
});
|
|
851
|
-
|
|
852
|
-
describe("$watch deregistration", () => {
|
|
853
|
-
beforeEach(() => (logs = []));
|
|
854
|
-
it("should return a function that allows listeners to be deregistered", () => {
|
|
855
|
-
const listener = jasmine.createSpy("watch listener");
|
|
856
|
-
let listenerRemove;
|
|
857
|
-
|
|
858
|
-
listenerRemove = $rootScope.$watch("foo", listener);
|
|
859
|
-
$rootScope.$digest(); // init
|
|
860
|
-
expect(listener).toHaveBeenCalled();
|
|
861
|
-
expect(listenerRemove).toBeDefined();
|
|
862
|
-
|
|
863
|
-
listener.calls.reset();
|
|
864
|
-
$rootScope.foo = "bar";
|
|
865
|
-
$rootScope.$digest(); // trigger
|
|
866
|
-
expect(listener).toHaveBeenCalled();
|
|
867
|
-
|
|
868
|
-
listener.calls.reset();
|
|
869
|
-
$rootScope.foo = "baz";
|
|
870
|
-
listenerRemove();
|
|
871
|
-
$rootScope.$digest(); // trigger
|
|
872
|
-
expect(listener).not.toHaveBeenCalled();
|
|
873
|
-
});
|
|
874
|
-
|
|
875
|
-
it("should allow a watch to be deregistered while in a digest", () => {
|
|
876
|
-
let remove1;
|
|
877
|
-
let remove2;
|
|
878
|
-
$rootScope.$watch("remove", () => {
|
|
879
|
-
remove1();
|
|
880
|
-
remove2();
|
|
881
|
-
});
|
|
882
|
-
remove1 = $rootScope.$watch("thing", () => {});
|
|
883
|
-
remove2 = $rootScope.$watch("thing", () => {});
|
|
884
|
-
expect(() => {
|
|
885
|
-
$rootScope.$apply("remove = true");
|
|
886
|
-
}).not.toThrow();
|
|
887
|
-
});
|
|
888
|
-
|
|
889
|
-
it("should not mess up the digest loop if deregistration happens during digest", () => {
|
|
890
|
-
// we are testing this due to regression #5525 which is related to how the digest loops lastDirtyWatch short-circuiting optimization works
|
|
891
|
-
// scenario: watch1 deregistering watch1
|
|
892
|
-
let scope = $rootScope.$new();
|
|
893
|
-
let deregWatch1 = scope.$watch(
|
|
894
|
-
() => {
|
|
895
|
-
logs.push("watch1");
|
|
896
|
-
return "watch1";
|
|
897
|
-
},
|
|
898
|
-
() => {
|
|
899
|
-
deregWatch1();
|
|
900
|
-
logs.push("watchAction1");
|
|
901
|
-
},
|
|
902
|
-
);
|
|
903
|
-
scope.$watch(
|
|
904
|
-
() => {
|
|
905
|
-
logs.push("watch2");
|
|
906
|
-
return "watch2";
|
|
907
|
-
},
|
|
908
|
-
() => logs.push("watchAction2"),
|
|
909
|
-
);
|
|
910
|
-
scope.$watch(
|
|
911
|
-
() => {
|
|
912
|
-
logs.push("watch3");
|
|
913
|
-
return "watch3";
|
|
914
|
-
},
|
|
915
|
-
() => logs.push("watchAction3"),
|
|
916
|
-
);
|
|
917
|
-
|
|
918
|
-
$rootScope.$digest();
|
|
919
|
-
|
|
920
|
-
expect(logs).toEqual([
|
|
921
|
-
"watch1",
|
|
922
|
-
"watchAction1",
|
|
923
|
-
"watch2",
|
|
924
|
-
"watchAction2",
|
|
925
|
-
"watch3",
|
|
926
|
-
"watchAction3",
|
|
927
|
-
"watch2",
|
|
928
|
-
"watch3",
|
|
929
|
-
]);
|
|
930
|
-
scope.$destroy();
|
|
931
|
-
logs = [];
|
|
932
|
-
|
|
933
|
-
// scenario: watch1 deregistering watch2
|
|
934
|
-
scope = $rootScope.$new();
|
|
935
|
-
scope.$watch(
|
|
936
|
-
() => {
|
|
937
|
-
logs.push("watch1");
|
|
938
|
-
return "watch1";
|
|
939
|
-
},
|
|
940
|
-
() => {
|
|
941
|
-
deregWatch2();
|
|
942
|
-
logs.push("watchAction1");
|
|
943
|
-
},
|
|
944
|
-
);
|
|
945
|
-
let deregWatch2 = scope.$watch(
|
|
946
|
-
() => {
|
|
947
|
-
logs.push("watch2");
|
|
948
|
-
return "watch2";
|
|
949
|
-
},
|
|
950
|
-
() => logs.push("watchAction2"),
|
|
951
|
-
);
|
|
952
|
-
scope.$watch(
|
|
953
|
-
() => {
|
|
954
|
-
logs.push("watch3");
|
|
955
|
-
return "watch3";
|
|
956
|
-
},
|
|
957
|
-
() => logs.push("watchAction3"),
|
|
958
|
-
);
|
|
959
|
-
|
|
960
|
-
$rootScope.$digest();
|
|
961
|
-
|
|
962
|
-
expect(logs).toEqual([
|
|
963
|
-
"watch1",
|
|
964
|
-
"watchAction1",
|
|
965
|
-
"watch3",
|
|
966
|
-
"watchAction3",
|
|
967
|
-
"watch1",
|
|
968
|
-
"watch3",
|
|
969
|
-
]);
|
|
970
|
-
scope.$destroy();
|
|
971
|
-
logs = [];
|
|
972
|
-
|
|
973
|
-
// scenario: watch2 deregistering watch1
|
|
974
|
-
scope = $rootScope.$new();
|
|
975
|
-
deregWatch1 = scope.$watch(
|
|
976
|
-
() => {
|
|
977
|
-
logs.push("watch1");
|
|
978
|
-
return "watch1";
|
|
979
|
-
},
|
|
980
|
-
() => logs.push("watchAction1"),
|
|
981
|
-
);
|
|
982
|
-
scope.$watch(
|
|
983
|
-
() => {
|
|
984
|
-
logs.push("watch2");
|
|
985
|
-
return "watch2";
|
|
986
|
-
},
|
|
987
|
-
() => {
|
|
988
|
-
deregWatch1();
|
|
989
|
-
logs.push("watchAction2");
|
|
990
|
-
},
|
|
991
|
-
);
|
|
992
|
-
scope.$watch(
|
|
993
|
-
() => {
|
|
994
|
-
logs.push("watch3");
|
|
995
|
-
return "watch3";
|
|
996
|
-
},
|
|
997
|
-
() => logs.push("watchAction3"),
|
|
998
|
-
);
|
|
999
|
-
|
|
1000
|
-
$rootScope.$digest();
|
|
1001
|
-
|
|
1002
|
-
expect(logs).toEqual([
|
|
1003
|
-
"watch1",
|
|
1004
|
-
"watchAction1",
|
|
1005
|
-
"watch2",
|
|
1006
|
-
"watchAction2",
|
|
1007
|
-
"watch3",
|
|
1008
|
-
"watchAction3",
|
|
1009
|
-
"watch2",
|
|
1010
|
-
"watch3",
|
|
1011
|
-
]);
|
|
1012
|
-
});
|
|
1013
|
-
});
|
|
1014
|
-
|
|
1015
200
|
describe("$watchCollection", () => {
|
|
1016
201
|
describe("constiable", () => {
|
|
1017
202
|
let deregister;
|
|
@@ -1029,25 +214,21 @@ describe("Scope", function () {
|
|
|
1029
214
|
});
|
|
1030
215
|
|
|
1031
216
|
it("should not trigger if nothing change", () => {
|
|
1032
|
-
$rootScope.$digest();
|
|
1033
217
|
expect(logs).toEqual([
|
|
1034
218
|
{ newVal: undefined, oldVal: undefined, identical: true },
|
|
1035
219
|
]);
|
|
1036
220
|
logs = [];
|
|
1037
|
-
$rootScope.$digest();
|
|
1038
221
|
expect(logs).toEqual([]);
|
|
1039
222
|
});
|
|
1040
223
|
|
|
1041
224
|
it("should allow deregistration", () => {
|
|
1042
225
|
$rootScope.obj = [];
|
|
1043
|
-
$rootScope.$digest();
|
|
1044
226
|
expect(logs.length).toBe(1);
|
|
1045
227
|
logs = [];
|
|
1046
228
|
|
|
1047
229
|
$rootScope.obj.push("a");
|
|
1048
230
|
deregister();
|
|
1049
231
|
|
|
1050
|
-
$rootScope.$digest();
|
|
1051
232
|
expect(logs).toEqual([]);
|
|
1052
233
|
});
|
|
1053
234
|
|
|
@@ -1055,7 +236,6 @@ describe("Scope", function () {
|
|
|
1055
236
|
it("should return oldCollection === newCollection only on the first listener call", () => {
|
|
1056
237
|
// first time should be identical
|
|
1057
238
|
$rootScope.obj = ["a", "b"];
|
|
1058
|
-
$rootScope.$digest();
|
|
1059
239
|
expect(logs).toEqual([
|
|
1060
240
|
{ newVal: ["a", "b"], oldVal: ["a", "b"], identical: true },
|
|
1061
241
|
]);
|
|
@@ -1063,99 +243,58 @@ describe("Scope", function () {
|
|
|
1063
243
|
|
|
1064
244
|
// second time should be different
|
|
1065
245
|
$rootScope.obj[1] = "c";
|
|
1066
|
-
$rootScope.$digest();
|
|
1067
246
|
expect(logs).toEqual([{ newVal: ["a", "c"], oldVal: ["a", "b"] }]);
|
|
1068
247
|
});
|
|
1069
248
|
|
|
1070
|
-
it("should trigger when property changes into array", () => {
|
|
1071
|
-
$rootScope.obj = "test";
|
|
1072
|
-
$rootScope.$digest();
|
|
1073
|
-
expect(logs).toEqual([
|
|
1074
|
-
{ newVal: "test", oldVal: "test", identical: true },
|
|
1075
|
-
]);
|
|
1076
|
-
|
|
1077
|
-
logs = [];
|
|
1078
|
-
$rootScope.obj = [];
|
|
1079
|
-
$rootScope.$digest();
|
|
1080
|
-
expect(logs).toEqual([{ newVal: [], oldVal: "test" }]);
|
|
1081
|
-
|
|
1082
|
-
logs = [];
|
|
1083
|
-
$rootScope.obj = {};
|
|
1084
|
-
$rootScope.$digest();
|
|
1085
|
-
expect(logs).toEqual([{ newVal: {}, oldVal: [] }]);
|
|
1086
|
-
|
|
1087
|
-
logs = [];
|
|
1088
|
-
$rootScope.obj = [];
|
|
1089
|
-
$rootScope.$digest();
|
|
1090
|
-
expect(logs).toEqual([{ newVal: [], oldVal: {} }]);
|
|
1091
|
-
|
|
1092
|
-
logs = [];
|
|
1093
|
-
$rootScope.obj = undefined;
|
|
1094
|
-
$rootScope.$digest();
|
|
1095
|
-
expect(logs).toEqual([{ newVal: undefined, oldVal: [] }]);
|
|
1096
|
-
});
|
|
1097
|
-
|
|
1098
249
|
it("should not trigger change when object in collection changes", () => {
|
|
1099
250
|
$rootScope.obj = [{}];
|
|
1100
|
-
$rootScope.$digest();
|
|
1101
251
|
expect(logs).toEqual([
|
|
1102
252
|
{ newVal: [{}], oldVal: [{}], identical: true },
|
|
1103
253
|
]);
|
|
1104
254
|
|
|
1105
255
|
logs = [];
|
|
1106
256
|
$rootScope.obj[0].name = "foo";
|
|
1107
|
-
$rootScope.$digest();
|
|
1108
257
|
expect(logs).toEqual([]);
|
|
1109
258
|
});
|
|
1110
259
|
|
|
1111
260
|
it("should watch array properties", () => {
|
|
1112
261
|
$rootScope.obj = [];
|
|
1113
|
-
$rootScope.$digest();
|
|
1114
262
|
expect(logs).toEqual([{ newVal: [], oldVal: [], identical: true }]);
|
|
1115
263
|
|
|
1116
264
|
logs = [];
|
|
1117
265
|
$rootScope.obj.push("a");
|
|
1118
|
-
$rootScope.$digest();
|
|
1119
266
|
expect(logs).toEqual([{ newVal: ["a"], oldVal: [] }]);
|
|
1120
267
|
|
|
1121
268
|
logs = [];
|
|
1122
269
|
$rootScope.obj[0] = "b";
|
|
1123
|
-
$rootScope.$digest();
|
|
1124
270
|
expect(logs).toEqual([{ newVal: ["b"], oldVal: ["a"] }]);
|
|
1125
271
|
|
|
1126
272
|
logs = [];
|
|
1127
273
|
$rootScope.obj.push([]);
|
|
1128
274
|
$rootScope.obj.push({});
|
|
1129
|
-
$rootScope.$digest();
|
|
1130
275
|
expect(logs).toEqual([{ newVal: ["b", [], {}], oldVal: ["b"] }]);
|
|
1131
276
|
|
|
1132
277
|
logs = [];
|
|
1133
278
|
const temp = $rootScope.obj[1];
|
|
1134
279
|
$rootScope.obj[1] = $rootScope.obj[2];
|
|
1135
280
|
$rootScope.obj[2] = temp;
|
|
1136
|
-
$rootScope.$digest();
|
|
1137
281
|
expect(logs).toEqual([
|
|
1138
282
|
{ newVal: ["b", {}, []], oldVal: ["b", [], {}] },
|
|
1139
283
|
]);
|
|
1140
284
|
|
|
1141
285
|
logs = [];
|
|
1142
286
|
$rootScope.obj.shift();
|
|
1143
|
-
$rootScope.$digest();
|
|
1144
287
|
expect(logs).toEqual([{ newVal: [{}, []], oldVal: ["b", {}, []] }]);
|
|
1145
288
|
});
|
|
1146
289
|
|
|
1147
290
|
it("should not infinitely digest when current value is NaN", () => {
|
|
1148
291
|
$rootScope.obj = [NaN];
|
|
1149
|
-
expect(() => {
|
|
1150
|
-
$rootScope.$digest();
|
|
1151
|
-
}).not.toThrow();
|
|
292
|
+
expect(() => {}).not.toThrow();
|
|
1152
293
|
});
|
|
1153
294
|
|
|
1154
295
|
it("should watch array-like objects like arrays", () => {
|
|
1155
296
|
logs = [];
|
|
1156
297
|
$rootScope.obj = document.getElementsByTagName("src");
|
|
1157
|
-
$rootScope.$digest();
|
|
1158
|
-
|
|
1159
298
|
expect(logs.length).toBeTruthy();
|
|
1160
299
|
});
|
|
1161
300
|
});
|
|
@@ -1164,7 +303,6 @@ describe("Scope", function () {
|
|
|
1164
303
|
it("should return oldCollection === newCollection only on the first listener call", () => {
|
|
1165
304
|
$rootScope.obj = { a: "b" };
|
|
1166
305
|
// first time should be identical
|
|
1167
|
-
$rootScope.$digest();
|
|
1168
306
|
expect(logs).toEqual([
|
|
1169
307
|
{ newVal: { a: "b" }, oldVal: { a: "b" }, identical: true },
|
|
1170
308
|
]);
|
|
@@ -1172,54 +310,45 @@ describe("Scope", function () {
|
|
|
1172
310
|
|
|
1173
311
|
// second time not identical
|
|
1174
312
|
$rootScope.obj.a = "c";
|
|
1175
|
-
$rootScope.$digest();
|
|
1176
313
|
expect(logs).toEqual([{ newVal: { a: "c" }, oldVal: { a: "b" } }]);
|
|
1177
314
|
});
|
|
1178
315
|
|
|
1179
316
|
it("should trigger when property changes into object", () => {
|
|
1180
317
|
$rootScope.obj = "test";
|
|
1181
|
-
$rootScope.$digest();
|
|
1182
318
|
expect(logs).toEqual([
|
|
1183
319
|
{ newVal: "test", oldVal: "test", identical: true },
|
|
1184
320
|
]);
|
|
1185
321
|
logs = [];
|
|
1186
322
|
|
|
1187
323
|
$rootScope.obj = {};
|
|
1188
|
-
$rootScope.$digest();
|
|
1189
324
|
expect(logs).toEqual([{ newVal: {}, oldVal: "test" }]);
|
|
1190
325
|
});
|
|
1191
326
|
|
|
1192
327
|
it("should not trigger change when object in collection changes", () => {
|
|
1193
328
|
$rootScope.obj = { name: {} };
|
|
1194
|
-
$rootScope.$digest();
|
|
1195
329
|
expect(logs).toEqual([
|
|
1196
330
|
{ newVal: { name: {} }, oldVal: { name: {} }, identical: true },
|
|
1197
331
|
]);
|
|
1198
332
|
logs = [];
|
|
1199
333
|
|
|
1200
334
|
$rootScope.obj.name.bar = "foo";
|
|
1201
|
-
$rootScope.$digest();
|
|
1202
335
|
expect(logs).toEqual([]);
|
|
1203
336
|
});
|
|
1204
337
|
|
|
1205
338
|
it("should watch object properties", () => {
|
|
1206
339
|
$rootScope.obj = {};
|
|
1207
|
-
$rootScope.$digest();
|
|
1208
340
|
expect(logs).toEqual([{ newVal: {}, oldVal: {}, identical: true }]);
|
|
1209
341
|
logs = [];
|
|
1210
342
|
$rootScope.obj.a = "A";
|
|
1211
|
-
$rootScope.$digest();
|
|
1212
343
|
expect(logs).toEqual([{ newVal: { a: "A" }, oldVal: {} }]);
|
|
1213
344
|
|
|
1214
345
|
logs = [];
|
|
1215
346
|
$rootScope.obj.a = "B";
|
|
1216
|
-
$rootScope.$digest();
|
|
1217
347
|
expect(logs).toEqual([{ newVal: { a: "B" }, oldVal: { a: "A" } }]);
|
|
1218
348
|
|
|
1219
349
|
logs = [];
|
|
1220
350
|
$rootScope.obj.b = [];
|
|
1221
351
|
$rootScope.obj.c = {};
|
|
1222
|
-
$rootScope.$digest();
|
|
1223
352
|
expect(logs).toEqual([
|
|
1224
353
|
{ newVal: { a: "B", b: [], c: {} }, oldVal: { a: "B" } },
|
|
1225
354
|
]);
|
|
@@ -1228,7 +357,6 @@ describe("Scope", function () {
|
|
|
1228
357
|
const temp = $rootScope.obj.a;
|
|
1229
358
|
$rootScope.obj.a = $rootScope.obj.b;
|
|
1230
359
|
$rootScope.obj.c = temp;
|
|
1231
|
-
$rootScope.$digest();
|
|
1232
360
|
expect(logs).toEqual([
|
|
1233
361
|
{
|
|
1234
362
|
newVal: { a: [], b: [], c: "B" },
|
|
@@ -1238,7 +366,6 @@ describe("Scope", function () {
|
|
|
1238
366
|
|
|
1239
367
|
logs = [];
|
|
1240
368
|
delete $rootScope.obj.a;
|
|
1241
|
-
$rootScope.$digest();
|
|
1242
369
|
expect(logs).toEqual([
|
|
1243
370
|
{ newVal: { b: [], c: "B" }, oldVal: { a: [], b: [], c: "B" } },
|
|
1244
371
|
]);
|
|
@@ -1246,22 +373,18 @@ describe("Scope", function () {
|
|
|
1246
373
|
|
|
1247
374
|
it("should not infinitely digest when current value is NaN", () => {
|
|
1248
375
|
$rootScope.obj = { a: NaN };
|
|
1249
|
-
expect(() => {
|
|
1250
|
-
$rootScope.$digest();
|
|
1251
|
-
}).not.toThrow();
|
|
376
|
+
expect(() => {}).not.toThrow();
|
|
1252
377
|
});
|
|
1253
378
|
|
|
1254
379
|
it("should handle objects created using `Object.create(null)`", () => {
|
|
1255
380
|
$rootScope.obj = Object.create(null);
|
|
1256
381
|
$rootScope.obj.a = "a";
|
|
1257
382
|
$rootScope.obj.b = "b";
|
|
1258
|
-
$rootScope.$digest();
|
|
1259
383
|
expect(logs[0].newVal).toEqual(
|
|
1260
384
|
extend(Object.create(null), { a: "a", b: "b" }),
|
|
1261
385
|
);
|
|
1262
386
|
|
|
1263
387
|
delete $rootScope.obj.b;
|
|
1264
|
-
$rootScope.$digest();
|
|
1265
388
|
expect(logs[0].newVal).toEqual(
|
|
1266
389
|
extend(Object.create(null), { a: "a" }),
|
|
1267
390
|
);
|
|
@@ -1287,7 +410,6 @@ describe("Scope", function () {
|
|
|
1287
410
|
it("should return oldCollection === newCollection only on the first listener call", () => {
|
|
1288
411
|
// first time should be identical
|
|
1289
412
|
$rootScope.obj = "a";
|
|
1290
|
-
$rootScope.$digest();
|
|
1291
413
|
expect(logs).toEqual([
|
|
1292
414
|
{ newVal: ["a"], oldVal: ["a"], identical: true },
|
|
1293
415
|
]);
|
|
@@ -1295,56 +417,46 @@ describe("Scope", function () {
|
|
|
1295
417
|
|
|
1296
418
|
// second time should be different
|
|
1297
419
|
$rootScope.obj = "b";
|
|
1298
|
-
$rootScope.$digest();
|
|
1299
420
|
expect(logs).toEqual([{ newVal: ["b"], oldVal: ["a"] }]);
|
|
1300
421
|
});
|
|
1301
422
|
|
|
1302
423
|
it("should trigger when property changes into array", () => {
|
|
1303
424
|
$rootScope.obj = "test";
|
|
1304
|
-
$rootScope.$digest();
|
|
1305
425
|
expect(logs).toEqual([
|
|
1306
426
|
{ newVal: ["test"], oldVal: ["test"], identical: true },
|
|
1307
427
|
]);
|
|
1308
428
|
|
|
1309
429
|
logs = [];
|
|
1310
430
|
$rootScope.obj = [];
|
|
1311
|
-
$rootScope.$digest();
|
|
1312
431
|
expect(logs).toEqual([{ newVal: [[]], oldVal: ["test"] }]);
|
|
1313
432
|
|
|
1314
433
|
logs = [];
|
|
1315
434
|
$rootScope.obj = {};
|
|
1316
|
-
$rootScope.$digest();
|
|
1317
435
|
expect(logs).toEqual([{ newVal: [{}], oldVal: [[]] }]);
|
|
1318
436
|
|
|
1319
437
|
logs = [];
|
|
1320
438
|
$rootScope.obj = [];
|
|
1321
|
-
$rootScope.$digest();
|
|
1322
439
|
expect(logs).toEqual([{ newVal: [[]], oldVal: [{}] }]);
|
|
1323
440
|
|
|
1324
441
|
logs = [];
|
|
1325
442
|
$rootScope.obj = undefined;
|
|
1326
|
-
$rootScope.$digest();
|
|
1327
443
|
expect(logs).toEqual([{ newVal: [undefined], oldVal: [[]] }]);
|
|
1328
444
|
});
|
|
1329
445
|
|
|
1330
446
|
it("should not trigger change when object in collection changes", () => {
|
|
1331
447
|
$rootScope.obj = {};
|
|
1332
|
-
$rootScope.$digest();
|
|
1333
448
|
expect(logs).toEqual([
|
|
1334
449
|
{ newVal: [{}], oldVal: [{}], identical: true },
|
|
1335
450
|
]);
|
|
1336
451
|
|
|
1337
452
|
logs = [];
|
|
1338
453
|
$rootScope.obj.name = "foo";
|
|
1339
|
-
$rootScope.$digest();
|
|
1340
454
|
expect(logs).toEqual([]);
|
|
1341
455
|
});
|
|
1342
456
|
|
|
1343
457
|
it("should not infinitely digest when current value is NaN", () => {
|
|
1344
458
|
$rootScope.obj = NaN;
|
|
1345
|
-
expect(() => {
|
|
1346
|
-
$rootScope.$digest();
|
|
1347
|
-
}).not.toThrow();
|
|
459
|
+
expect(() => {}).not.toThrow();
|
|
1348
460
|
});
|
|
1349
461
|
});
|
|
1350
462
|
|
|
@@ -1365,7 +477,6 @@ describe("Scope", function () {
|
|
|
1365
477
|
it("should return oldCollection === newCollection only on the first listener call", () => {
|
|
1366
478
|
$rootScope.obj = "b";
|
|
1367
479
|
// first time should be identical
|
|
1368
|
-
$rootScope.$digest();
|
|
1369
480
|
expect(logs).toEqual([
|
|
1370
481
|
{ newVal: { a: "b" }, oldVal: { a: "b" }, identical: true },
|
|
1371
482
|
]);
|
|
@@ -1373,20 +484,17 @@ describe("Scope", function () {
|
|
|
1373
484
|
// second time not identical
|
|
1374
485
|
logs = [];
|
|
1375
486
|
$rootScope.obj = "c";
|
|
1376
|
-
$rootScope.$digest();
|
|
1377
487
|
expect(logs).toEqual([{ newVal: { a: "c" }, oldVal: { a: "b" } }]);
|
|
1378
488
|
});
|
|
1379
489
|
|
|
1380
490
|
it("should trigger when property changes into object", () => {
|
|
1381
491
|
$rootScope.obj = "test";
|
|
1382
|
-
$rootScope.$digest();
|
|
1383
492
|
expect(logs).toEqual([
|
|
1384
493
|
{ newVal: { a: "test" }, oldVal: { a: "test" }, identical: true },
|
|
1385
494
|
]);
|
|
1386
495
|
|
|
1387
496
|
logs = [];
|
|
1388
497
|
$rootScope.obj = {};
|
|
1389
|
-
$rootScope.$digest();
|
|
1390
498
|
expect(logs).toEqual([
|
|
1391
499
|
{ newVal: { a: {} }, oldVal: { a: "test" } },
|
|
1392
500
|
]);
|
|
@@ -1394,7 +502,6 @@ describe("Scope", function () {
|
|
|
1394
502
|
|
|
1395
503
|
it("should not trigger change when object in collection changes", () => {
|
|
1396
504
|
$rootScope.obj = { name: "foo" };
|
|
1397
|
-
$rootScope.$digest();
|
|
1398
505
|
expect(logs).toEqual([
|
|
1399
506
|
{
|
|
1400
507
|
newVal: { a: { name: "foo" } },
|
|
@@ -1405,35 +512,29 @@ describe("Scope", function () {
|
|
|
1405
512
|
|
|
1406
513
|
logs = [];
|
|
1407
514
|
$rootScope.obj.name = "bar";
|
|
1408
|
-
$rootScope.$digest();
|
|
1409
515
|
expect(logs).toEqual([]);
|
|
1410
516
|
});
|
|
1411
517
|
|
|
1412
518
|
it("should watch object properties", () => {
|
|
1413
519
|
$rootScope.obj = {};
|
|
1414
|
-
$rootScope.$digest();
|
|
1415
520
|
expect(logs).toEqual([
|
|
1416
521
|
{ newVal: { a: {} }, oldVal: { a: {} }, identical: true },
|
|
1417
522
|
]);
|
|
1418
523
|
|
|
1419
524
|
logs = [];
|
|
1420
525
|
$rootScope.obj = "A";
|
|
1421
|
-
$rootScope.$digest();
|
|
1422
526
|
expect(logs).toEqual([{ newVal: { a: "A" }, oldVal: { a: {} } }]);
|
|
1423
527
|
|
|
1424
528
|
logs = [];
|
|
1425
529
|
$rootScope.obj = "B";
|
|
1426
|
-
$rootScope.$digest();
|
|
1427
530
|
expect(logs).toEqual([{ newVal: { a: "B" }, oldVal: { a: "A" } }]);
|
|
1428
531
|
|
|
1429
532
|
logs = [];
|
|
1430
533
|
$rootScope.obj = [];
|
|
1431
|
-
$rootScope.$digest();
|
|
1432
534
|
expect(logs).toEqual([{ newVal: { a: [] }, oldVal: { a: "B" } }]);
|
|
1433
535
|
|
|
1434
536
|
logs = [];
|
|
1435
537
|
delete $rootScope.obj;
|
|
1436
|
-
$rootScope.$digest();
|
|
1437
538
|
expect(logs).toEqual([
|
|
1438
539
|
{ newVal: { a: undefined }, oldVal: { a: [] } },
|
|
1439
540
|
]);
|
|
@@ -1441,9 +542,7 @@ describe("Scope", function () {
|
|
|
1441
542
|
|
|
1442
543
|
it("should not infinitely digest when current value is NaN", () => {
|
|
1443
544
|
$rootScope.obj = NaN;
|
|
1444
|
-
expect(() => {
|
|
1445
|
-
$rootScope.$digest();
|
|
1446
|
-
}).not.toThrow();
|
|
545
|
+
expect(() => {}).not.toThrow();
|
|
1447
546
|
});
|
|
1448
547
|
});
|
|
1449
548
|
|
|
@@ -1463,7 +562,6 @@ describe("Scope", function () {
|
|
|
1463
562
|
|
|
1464
563
|
it('should default to "undefined" key', () => {
|
|
1465
564
|
$rootScope.obj = "test";
|
|
1466
|
-
$rootScope.$digest();
|
|
1467
565
|
expect(logs).toEqual([
|
|
1468
566
|
{
|
|
1469
567
|
newVal: { undefined: "test" },
|
|
@@ -1476,21 +574,18 @@ describe("Scope", function () {
|
|
|
1476
574
|
it("should trigger when key changes", () => {
|
|
1477
575
|
$rootScope.key = "a";
|
|
1478
576
|
$rootScope.obj = "test";
|
|
1479
|
-
$rootScope.$digest();
|
|
1480
577
|
expect(logs).toEqual([
|
|
1481
578
|
{ newVal: { a: "test" }, oldVal: { a: "test" }, identical: true },
|
|
1482
579
|
]);
|
|
1483
580
|
|
|
1484
581
|
logs = [];
|
|
1485
582
|
$rootScope.key = "b";
|
|
1486
|
-
$rootScope.$digest();
|
|
1487
583
|
expect(logs).toEqual([
|
|
1488
584
|
{ newVal: { b: "test" }, oldVal: { a: "test" } },
|
|
1489
585
|
]);
|
|
1490
586
|
|
|
1491
587
|
logs = [];
|
|
1492
588
|
$rootScope.key = true;
|
|
1493
|
-
$rootScope.$digest();
|
|
1494
589
|
expect(logs).toEqual([
|
|
1495
590
|
{ newVal: { true: "test" }, oldVal: { b: "test" } },
|
|
1496
591
|
]);
|
|
@@ -1499,30 +594,25 @@ describe("Scope", function () {
|
|
|
1499
594
|
it("should not trigger when key changes but stringified key does not", () => {
|
|
1500
595
|
$rootScope.key = 1;
|
|
1501
596
|
$rootScope.obj = "test";
|
|
1502
|
-
$rootScope.$digest();
|
|
1503
597
|
expect(logs).toEqual([
|
|
1504
598
|
{ newVal: { 1: "test" }, oldVal: { 1: "test" }, identical: true },
|
|
1505
599
|
]);
|
|
1506
600
|
|
|
1507
601
|
logs = [];
|
|
1508
602
|
$rootScope.key = "1";
|
|
1509
|
-
$rootScope.$digest();
|
|
1510
603
|
expect(logs).toEqual([]);
|
|
1511
604
|
|
|
1512
605
|
$rootScope.key = true;
|
|
1513
|
-
$rootScope.$digest();
|
|
1514
606
|
expect(logs).toEqual([
|
|
1515
607
|
{ newVal: { true: "test" }, oldVal: { 1: "test" } },
|
|
1516
608
|
]);
|
|
1517
609
|
|
|
1518
610
|
logs = [];
|
|
1519
611
|
$rootScope.key = "true";
|
|
1520
|
-
$rootScope.$digest();
|
|
1521
612
|
expect(logs).toEqual([]);
|
|
1522
613
|
|
|
1523
614
|
logs = [];
|
|
1524
615
|
$rootScope.key = {};
|
|
1525
|
-
$rootScope.$digest();
|
|
1526
616
|
expect(logs).toEqual([
|
|
1527
617
|
{
|
|
1528
618
|
newVal: { "[object Object]": "test" },
|
|
@@ -1532,14 +622,12 @@ describe("Scope", function () {
|
|
|
1532
622
|
|
|
1533
623
|
logs = [];
|
|
1534
624
|
$rootScope.key = {};
|
|
1535
|
-
$rootScope.$digest();
|
|
1536
625
|
expect(logs).toEqual([]);
|
|
1537
626
|
});
|
|
1538
627
|
|
|
1539
628
|
it("should not trigger change when object in collection changes", () => {
|
|
1540
629
|
$rootScope.key = "a";
|
|
1541
630
|
$rootScope.obj = { name: "foo" };
|
|
1542
|
-
$rootScope.$digest();
|
|
1543
631
|
expect(logs).toEqual([
|
|
1544
632
|
{
|
|
1545
633
|
newVal: { a: { name: "foo" } },
|
|
@@ -1550,16 +638,13 @@ describe("Scope", function () {
|
|
|
1550
638
|
logs = [];
|
|
1551
639
|
|
|
1552
640
|
$rootScope.obj.name = "bar";
|
|
1553
|
-
$rootScope.$digest();
|
|
1554
641
|
expect(logs).toEqual([]);
|
|
1555
642
|
});
|
|
1556
643
|
|
|
1557
644
|
it("should not infinitely digest when key value is NaN", () => {
|
|
1558
645
|
$rootScope.key = NaN;
|
|
1559
646
|
$rootScope.obj = NaN;
|
|
1560
|
-
expect(() => {
|
|
1561
|
-
$rootScope.$digest();
|
|
1562
|
-
}).not.toThrow();
|
|
647
|
+
expect(() => {}).not.toThrow();
|
|
1563
648
|
});
|
|
1564
649
|
});
|
|
1565
650
|
});
|
|
@@ -1570,7 +655,6 @@ describe("Scope", function () {
|
|
|
1570
655
|
const watchSpy = jasmine.createSpy("watchSpy");
|
|
1571
656
|
$rootScope.$watch(watchSpy);
|
|
1572
657
|
$rootScope.$suspend();
|
|
1573
|
-
$rootScope.$digest();
|
|
1574
658
|
expect(watchSpy).not.toHaveBeenCalled();
|
|
1575
659
|
});
|
|
1576
660
|
|
|
@@ -1579,7 +663,6 @@ describe("Scope", function () {
|
|
|
1579
663
|
$rootScope.$watch(watchSpy);
|
|
1580
664
|
$rootScope.$suspend();
|
|
1581
665
|
$rootScope.$resume();
|
|
1582
|
-
$rootScope.$digest();
|
|
1583
666
|
expect(watchSpy).toHaveBeenCalled();
|
|
1584
667
|
});
|
|
1585
668
|
|
|
@@ -1588,7 +671,6 @@ describe("Scope", function () {
|
|
|
1588
671
|
const scope = $rootScope.$new(true);
|
|
1589
672
|
scope.$watch(watchSpy);
|
|
1590
673
|
$rootScope.$suspend();
|
|
1591
|
-
$rootScope.$digest();
|
|
1592
674
|
expect(watchSpy).not.toHaveBeenCalled();
|
|
1593
675
|
});
|
|
1594
676
|
|
|
@@ -1598,7 +680,6 @@ describe("Scope", function () {
|
|
|
1598
680
|
scope.$watch(watchSpy);
|
|
1599
681
|
$rootScope.$suspend();
|
|
1600
682
|
$rootScope.$resume();
|
|
1601
|
-
$rootScope.$digest();
|
|
1602
683
|
expect(watchSpy).toHaveBeenCalled();
|
|
1603
684
|
});
|
|
1604
685
|
|
|
@@ -1665,7 +746,6 @@ describe("Scope", function () {
|
|
|
1665
746
|
sibling.$watch(watchSpySibling);
|
|
1666
747
|
|
|
1667
748
|
child.$suspend();
|
|
1668
|
-
$rootScope.$digest();
|
|
1669
749
|
expect(watchSpyParent).toHaveBeenCalled();
|
|
1670
750
|
expect(watchSpyChild).not.toHaveBeenCalled();
|
|
1671
751
|
expect(watchSpySibling).toHaveBeenCalled();
|
|
@@ -1706,123 +786,8 @@ describe("Scope", function () {
|
|
|
1706
786
|
return scope.w3;
|
|
1707
787
|
}, log("w3action"));
|
|
1708
788
|
console.error(logs.length);
|
|
1709
|
-
scope.$digest();
|
|
1710
789
|
logs = [];
|
|
1711
790
|
}
|
|
1712
|
-
|
|
1713
|
-
describe("optimizations", () => {
|
|
1714
|
-
beforeEach(() => (logs = []));
|
|
1715
|
-
it("should check watches only once during an empty digest", () => {
|
|
1716
|
-
setupWatches($rootScope, console.log);
|
|
1717
|
-
$rootScope.$digest();
|
|
1718
|
-
expect(logs).toEqual(["w1", "w2", "w3"]);
|
|
1719
|
-
});
|
|
1720
|
-
|
|
1721
|
-
it("should quit digest early after we check the last watch that was previously dirty", () => {
|
|
1722
|
-
setupWatches($rootScope, console.log);
|
|
1723
|
-
$rootScope.w1 = "x";
|
|
1724
|
-
$rootScope.$digest();
|
|
1725
|
-
expect(logs).toEqual(["w1", "w2", "w3", "w1"]);
|
|
1726
|
-
});
|
|
1727
|
-
|
|
1728
|
-
it("should not quit digest early if a new watch was added from an existing watch action", () => {
|
|
1729
|
-
setupWatches($rootScope, console.log);
|
|
1730
|
-
$rootScope.$watch(
|
|
1731
|
-
() => {
|
|
1732
|
-
logs.push("w4");
|
|
1733
|
-
return "w4";
|
|
1734
|
-
},
|
|
1735
|
-
() => {
|
|
1736
|
-
logs.push("w4action");
|
|
1737
|
-
$rootScope.$watch(
|
|
1738
|
-
() => {
|
|
1739
|
-
logs.push("w5");
|
|
1740
|
-
return "w5";
|
|
1741
|
-
},
|
|
1742
|
-
() => logs.push("w5action"),
|
|
1743
|
-
);
|
|
1744
|
-
},
|
|
1745
|
-
);
|
|
1746
|
-
$rootScope.$digest();
|
|
1747
|
-
expect(logs).toEqual([
|
|
1748
|
-
"w1",
|
|
1749
|
-
"w2",
|
|
1750
|
-
"w3",
|
|
1751
|
-
"w4",
|
|
1752
|
-
"w4action",
|
|
1753
|
-
"w5",
|
|
1754
|
-
"w5action",
|
|
1755
|
-
"w1",
|
|
1756
|
-
"w2",
|
|
1757
|
-
"w3",
|
|
1758
|
-
"w4",
|
|
1759
|
-
"w5",
|
|
1760
|
-
]);
|
|
1761
|
-
});
|
|
1762
|
-
|
|
1763
|
-
it("should not quit digest early if an evalAsync task was scheduled from a watch action", () => {
|
|
1764
|
-
setupWatches($rootScope, console.log);
|
|
1765
|
-
$rootScope.$watch(
|
|
1766
|
-
() => {
|
|
1767
|
-
logs.push("w4");
|
|
1768
|
-
return "w4";
|
|
1769
|
-
},
|
|
1770
|
-
() => {
|
|
1771
|
-
logs.push("w4action");
|
|
1772
|
-
$rootScope.$evalAsync(() => {
|
|
1773
|
-
logs.push("evalAsync");
|
|
1774
|
-
});
|
|
1775
|
-
},
|
|
1776
|
-
);
|
|
1777
|
-
$rootScope.$digest();
|
|
1778
|
-
expect(logs).toEqual([
|
|
1779
|
-
"w1",
|
|
1780
|
-
"w2",
|
|
1781
|
-
"w3",
|
|
1782
|
-
"w4",
|
|
1783
|
-
"w4action",
|
|
1784
|
-
"evalAsync",
|
|
1785
|
-
"w1",
|
|
1786
|
-
"w2",
|
|
1787
|
-
"w3",
|
|
1788
|
-
"w4",
|
|
1789
|
-
]);
|
|
1790
|
-
});
|
|
1791
|
-
|
|
1792
|
-
it("should quit digest early but not too early when constious watches fire", () => {
|
|
1793
|
-
setupWatches($rootScope, console.log);
|
|
1794
|
-
$rootScope.$watch(
|
|
1795
|
-
() => {
|
|
1796
|
-
logs.push("w4");
|
|
1797
|
-
return $rootScope.w4;
|
|
1798
|
-
},
|
|
1799
|
-
(newVal) => {
|
|
1800
|
-
logs.push("w4action");
|
|
1801
|
-
$rootScope.w2 = newVal;
|
|
1802
|
-
},
|
|
1803
|
-
);
|
|
1804
|
-
|
|
1805
|
-
$rootScope.$digest();
|
|
1806
|
-
logs = [];
|
|
1807
|
-
|
|
1808
|
-
$rootScope.w1 = "x";
|
|
1809
|
-
$rootScope.w4 = "x";
|
|
1810
|
-
$rootScope.$digest();
|
|
1811
|
-
expect(logs).toEqual([
|
|
1812
|
-
"w1",
|
|
1813
|
-
"w2",
|
|
1814
|
-
"w3",
|
|
1815
|
-
"w4",
|
|
1816
|
-
"w4action",
|
|
1817
|
-
"w1",
|
|
1818
|
-
"w2",
|
|
1819
|
-
"w3",
|
|
1820
|
-
"w4",
|
|
1821
|
-
"w1",
|
|
1822
|
-
"w2",
|
|
1823
|
-
]);
|
|
1824
|
-
});
|
|
1825
|
-
});
|
|
1826
791
|
});
|
|
1827
792
|
|
|
1828
793
|
describe("$watchGroup", () => {
|
|
@@ -1883,21 +848,17 @@ describe("Scope", function () {
|
|
|
1883
848
|
|
|
1884
849
|
scope.a = "foo";
|
|
1885
850
|
scope.b = "bar";
|
|
1886
|
-
scope.$digest();
|
|
1887
851
|
expect(logs[0]).toEqual("foo,bar >>> foo,bar");
|
|
1888
852
|
|
|
1889
853
|
logs = [];
|
|
1890
|
-
scope.$digest();
|
|
1891
854
|
expect(logs).toEqual([]);
|
|
1892
855
|
|
|
1893
856
|
scope.a = "a";
|
|
1894
|
-
scope.$digest();
|
|
1895
857
|
expect(logs[0]).toEqual("foo,bar >>> a,bar");
|
|
1896
858
|
|
|
1897
859
|
logs = [];
|
|
1898
860
|
scope.a = "A";
|
|
1899
861
|
scope.b = "B";
|
|
1900
|
-
scope.$digest();
|
|
1901
862
|
expect(logs[0]).toEqual("a,bar >>> A,B");
|
|
1902
863
|
});
|
|
1903
864
|
|
|
@@ -1909,15 +870,12 @@ describe("Scope", function () {
|
|
|
1909
870
|
});
|
|
1910
871
|
|
|
1911
872
|
scope.a = "foo";
|
|
1912
|
-
scope.$digest();
|
|
1913
873
|
expect(logs[0]).toEqual("foo >>> foo");
|
|
1914
874
|
|
|
1915
875
|
logs = [];
|
|
1916
|
-
scope.$digest();
|
|
1917
876
|
expect(logs).toEqual([]);
|
|
1918
877
|
|
|
1919
878
|
scope.a = "bar";
|
|
1920
|
-
scope.$digest();
|
|
1921
879
|
expect(logs[0]).toEqual("foo >>> bar");
|
|
1922
880
|
});
|
|
1923
881
|
|
|
@@ -1928,11 +886,9 @@ describe("Scope", function () {
|
|
|
1928
886
|
});
|
|
1929
887
|
|
|
1930
888
|
expect(logs).toEqual([]);
|
|
1931
|
-
scope.$digest();
|
|
1932
889
|
expect(logs[0]).toEqual(" >>> ");
|
|
1933
890
|
|
|
1934
891
|
logs = [];
|
|
1935
|
-
scope.$digest();
|
|
1936
892
|
expect(logs).toEqual([]);
|
|
1937
893
|
});
|
|
1938
894
|
|
|
@@ -1956,7 +912,6 @@ describe("Scope", function () {
|
|
|
1956
912
|
deregisterNone();
|
|
1957
913
|
scope.a = "xxx";
|
|
1958
914
|
scope.b = "yyy";
|
|
1959
|
-
scope.$digest();
|
|
1960
915
|
expect(logs).toEqual([]);
|
|
1961
916
|
});
|
|
1962
917
|
|
|
@@ -2138,7 +1093,6 @@ describe("Scope", function () {
|
|
|
2138
1093
|
log += "3";
|
|
2139
1094
|
});
|
|
2140
1095
|
|
|
2141
|
-
$rootScope.$digest();
|
|
2142
1096
|
log = "";
|
|
2143
1097
|
});
|
|
2144
1098
|
|
|
@@ -2162,7 +1116,6 @@ describe("Scope", function () {
|
|
|
2162
1116
|
const spy = jasmine.createSpy("$watch spy");
|
|
2163
1117
|
$rootScope.$watch(spy);
|
|
2164
1118
|
$rootScope.$destroy();
|
|
2165
|
-
$rootScope.$digest();
|
|
2166
1119
|
expect(spy).not.toHaveBeenCalled();
|
|
2167
1120
|
});
|
|
2168
1121
|
|
|
@@ -2174,19 +1127,16 @@ describe("Scope", function () {
|
|
|
2174
1127
|
|
|
2175
1128
|
it("should remove first", () => {
|
|
2176
1129
|
first.$destroy();
|
|
2177
|
-
$rootScope.$digest();
|
|
2178
1130
|
expect(log).toEqual("23");
|
|
2179
1131
|
});
|
|
2180
1132
|
|
|
2181
1133
|
it("should remove middle", () => {
|
|
2182
1134
|
middle.$destroy();
|
|
2183
|
-
$rootScope.$digest();
|
|
2184
1135
|
expect(log).toEqual("13");
|
|
2185
1136
|
});
|
|
2186
1137
|
|
|
2187
1138
|
it("should remove last", () => {
|
|
2188
1139
|
last.$destroy();
|
|
2189
|
-
$rootScope.$digest();
|
|
2190
1140
|
expect(log).toEqual("12");
|
|
2191
1141
|
});
|
|
2192
1142
|
|
|
@@ -2200,7 +1150,6 @@ describe("Scope", function () {
|
|
|
2200
1150
|
});
|
|
2201
1151
|
|
|
2202
1152
|
it("should $destroy a scope only once and ignore any further destroy calls", () => {
|
|
2203
|
-
$rootScope.$digest();
|
|
2204
1153
|
expect(log).toBe("123");
|
|
2205
1154
|
|
|
2206
1155
|
first.$destroy();
|
|
@@ -2224,27 +1173,6 @@ describe("Scope", function () {
|
|
|
2224
1173
|
expect(logs).toEqual(["event"]);
|
|
2225
1174
|
});
|
|
2226
1175
|
|
|
2227
|
-
it("should decrement ancestor $$listenerCount entries", () => {
|
|
2228
|
-
const EVENT = "fooEvent";
|
|
2229
|
-
const spy = jasmine.createSpy("listener");
|
|
2230
|
-
const firstSecond = first.$new();
|
|
2231
|
-
|
|
2232
|
-
firstSecond.$on(EVENT, spy);
|
|
2233
|
-
firstSecond.$on(EVENT, spy);
|
|
2234
|
-
middle.$on(EVENT, spy);
|
|
2235
|
-
|
|
2236
|
-
expect($rootScope.$$listenerCount[EVENT]).toBe(3);
|
|
2237
|
-
expect(first.$$listenerCount[EVENT]).toBe(2);
|
|
2238
|
-
|
|
2239
|
-
firstSecond.$destroy();
|
|
2240
|
-
|
|
2241
|
-
expect($rootScope.$$listenerCount[EVENT]).toBe(1);
|
|
2242
|
-
expect(first.$$listenerCount[EVENT]).toBeUndefined();
|
|
2243
|
-
|
|
2244
|
-
$rootScope.$broadcast(EVENT);
|
|
2245
|
-
expect(spy).toHaveBeenCalledTimes(1);
|
|
2246
|
-
});
|
|
2247
|
-
|
|
2248
1176
|
it("should do nothing when a child event listener is registered after parent's destruction", () => {
|
|
2249
1177
|
const parent = $rootScope.$new();
|
|
2250
1178
|
const child = parent.$new();
|
|
@@ -2287,20 +1215,6 @@ describe("Scope", function () {
|
|
|
2287
1215
|
expect(called).toBe(false);
|
|
2288
1216
|
});
|
|
2289
1217
|
|
|
2290
|
-
it("should do nothing when $evalAsync()ing after parent's destruction", () => {
|
|
2291
|
-
const parent = $rootScope.$new();
|
|
2292
|
-
const child = parent.$new();
|
|
2293
|
-
|
|
2294
|
-
parent.$destroy();
|
|
2295
|
-
|
|
2296
|
-
let called = false;
|
|
2297
|
-
function applyFunc() {
|
|
2298
|
-
called = true;
|
|
2299
|
-
}
|
|
2300
|
-
child.$evalAsync(applyFunc);
|
|
2301
|
-
expect(called).toBe(false);
|
|
2302
|
-
});
|
|
2303
|
-
|
|
2304
1218
|
it("should preserve all (own and inherited) model properties on a destroyed scope", () => {
|
|
2305
1219
|
// This test simulates an async task (xhr response) interacting with the scope after the scope
|
|
2306
1220
|
// was destroyed. Since we can't abort the request, we should ensure that the task doesn't
|
|
@@ -2319,238 +1233,6 @@ describe("Scope", function () {
|
|
|
2319
1233
|
});
|
|
2320
1234
|
});
|
|
2321
1235
|
|
|
2322
|
-
describe("$eval", () => {
|
|
2323
|
-
it("should eval an expression", () => {
|
|
2324
|
-
expect($rootScope.$eval("a=1")).toEqual(1);
|
|
2325
|
-
expect($rootScope.a).toEqual(1);
|
|
2326
|
-
|
|
2327
|
-
$rootScope.$eval((self) => {
|
|
2328
|
-
self.b = 2;
|
|
2329
|
-
});
|
|
2330
|
-
expect($rootScope.b).toEqual(2);
|
|
2331
|
-
});
|
|
2332
|
-
|
|
2333
|
-
it("should allow passing locals to the expression", () => {
|
|
2334
|
-
expect($rootScope.$eval("a+1", { a: 2 })).toBe(3);
|
|
2335
|
-
|
|
2336
|
-
$rootScope.$eval(
|
|
2337
|
-
(scope, locals) => {
|
|
2338
|
-
scope.c = locals.b + 4;
|
|
2339
|
-
},
|
|
2340
|
-
{ b: 3 },
|
|
2341
|
-
);
|
|
2342
|
-
expect($rootScope.c).toBe(7);
|
|
2343
|
-
});
|
|
2344
|
-
});
|
|
2345
|
-
|
|
2346
|
-
describe("$evalAsync", () => {
|
|
2347
|
-
it("should run callback before $watch", () => {
|
|
2348
|
-
let log = "";
|
|
2349
|
-
const child = $rootScope.$new();
|
|
2350
|
-
$rootScope.$evalAsync((scope) => {
|
|
2351
|
-
log += "parent.async;";
|
|
2352
|
-
});
|
|
2353
|
-
$rootScope.$watch("value", () => {
|
|
2354
|
-
log += "parent.$digest;";
|
|
2355
|
-
});
|
|
2356
|
-
child.$evalAsync((scope) => {
|
|
2357
|
-
log += "child.async;";
|
|
2358
|
-
});
|
|
2359
|
-
child.$watch("value", () => {
|
|
2360
|
-
log += "child.$digest;";
|
|
2361
|
-
});
|
|
2362
|
-
$rootScope.$digest();
|
|
2363
|
-
expect(log).toEqual(
|
|
2364
|
-
"parent.async;child.async;parent.$digest;child.$digest;",
|
|
2365
|
-
);
|
|
2366
|
-
});
|
|
2367
|
-
|
|
2368
|
-
it("should not run another digest for an $$postDigest call", () => {
|
|
2369
|
-
let internalWatchCount = 0;
|
|
2370
|
-
let externalWatchCount = 0;
|
|
2371
|
-
|
|
2372
|
-
$rootScope.internalCount = 0;
|
|
2373
|
-
$rootScope.externalCount = 0;
|
|
2374
|
-
|
|
2375
|
-
$rootScope.$evalAsync((scope) => {
|
|
2376
|
-
$rootScope.internalCount++;
|
|
2377
|
-
});
|
|
2378
|
-
|
|
2379
|
-
$rootScope.$$postDigest((scope) => {
|
|
2380
|
-
$rootScope.externalCount++;
|
|
2381
|
-
});
|
|
2382
|
-
|
|
2383
|
-
$rootScope.$watch("internalCount", (value) => {
|
|
2384
|
-
internalWatchCount = value;
|
|
2385
|
-
});
|
|
2386
|
-
$rootScope.$watch("externalCount", (value) => {
|
|
2387
|
-
externalWatchCount = value;
|
|
2388
|
-
});
|
|
2389
|
-
|
|
2390
|
-
$rootScope.$digest();
|
|
2391
|
-
|
|
2392
|
-
expect(internalWatchCount).toEqual(1);
|
|
2393
|
-
expect(externalWatchCount).toEqual(0);
|
|
2394
|
-
});
|
|
2395
|
-
|
|
2396
|
-
it("should cause a $digest rerun", () => {
|
|
2397
|
-
$rootScope.log = "";
|
|
2398
|
-
$rootScope.value = 0;
|
|
2399
|
-
$rootScope.$watch("value", () => {
|
|
2400
|
-
$rootScope.log += ".";
|
|
2401
|
-
});
|
|
2402
|
-
$rootScope.$watch("init", () => {
|
|
2403
|
-
$rootScope.$evalAsync('value = 123; log = log + "=" ');
|
|
2404
|
-
expect($rootScope.value).toEqual(0);
|
|
2405
|
-
});
|
|
2406
|
-
$rootScope.$digest();
|
|
2407
|
-
expect($rootScope.log).toEqual(".=.");
|
|
2408
|
-
});
|
|
2409
|
-
|
|
2410
|
-
it("should run async in the same order as added", () => {
|
|
2411
|
-
$rootScope.log = "";
|
|
2412
|
-
$rootScope.$evalAsync("log = log + 1");
|
|
2413
|
-
$rootScope.$evalAsync("log = log + 2");
|
|
2414
|
-
$rootScope.$digest();
|
|
2415
|
-
expect($rootScope.log).toBe("12");
|
|
2416
|
-
});
|
|
2417
|
-
|
|
2418
|
-
it("should allow passing locals to the expression", () => {
|
|
2419
|
-
$rootScope.log = "";
|
|
2420
|
-
$rootScope.$evalAsync("log = log + a", { a: 1 });
|
|
2421
|
-
$rootScope.$digest();
|
|
2422
|
-
expect($rootScope.log).toBe("1");
|
|
2423
|
-
});
|
|
2424
|
-
|
|
2425
|
-
it("should run async expressions in their proper context", () => {
|
|
2426
|
-
const child = $rootScope.$new();
|
|
2427
|
-
$rootScope.ctx = "root context";
|
|
2428
|
-
$rootScope.log = "";
|
|
2429
|
-
child.ctx = "child context";
|
|
2430
|
-
child.log = "";
|
|
2431
|
-
child.$evalAsync("log=ctx");
|
|
2432
|
-
$rootScope.$digest();
|
|
2433
|
-
expect($rootScope.log).toBe("");
|
|
2434
|
-
expect(child.log).toBe("child context");
|
|
2435
|
-
});
|
|
2436
|
-
|
|
2437
|
-
it("should operate only with a single queue across all child and isolate scopes", () => {
|
|
2438
|
-
const childScope = $rootScope.$new();
|
|
2439
|
-
const isolateScope = $rootScope.$new(true);
|
|
2440
|
-
|
|
2441
|
-
$rootScope.$evalAsync("rootExpression");
|
|
2442
|
-
childScope.$evalAsync("childExpression");
|
|
2443
|
-
isolateScope.$evalAsync("isolateExpression");
|
|
2444
|
-
expect($$asyncQueue).toEqual([
|
|
2445
|
-
{
|
|
2446
|
-
scope: $rootScope,
|
|
2447
|
-
fn: $parse("rootExpression"),
|
|
2448
|
-
locals: undefined,
|
|
2449
|
-
},
|
|
2450
|
-
{
|
|
2451
|
-
scope: childScope,
|
|
2452
|
-
fn: $parse("childExpression"),
|
|
2453
|
-
locals: undefined,
|
|
2454
|
-
},
|
|
2455
|
-
{
|
|
2456
|
-
scope: isolateScope,
|
|
2457
|
-
fn: $parse("isolateExpression"),
|
|
2458
|
-
locals: undefined,
|
|
2459
|
-
},
|
|
2460
|
-
]);
|
|
2461
|
-
});
|
|
2462
|
-
|
|
2463
|
-
describe("auto-flushing when queueing outside of an $apply", () => {
|
|
2464
|
-
it("should auto-flush the queue asynchronously and trigger digest", () => {
|
|
2465
|
-
logs = [];
|
|
2466
|
-
$rootScope.$evalAsync(() => {
|
|
2467
|
-
logs.push("eval-ed!");
|
|
2468
|
-
return "eval-ed!";
|
|
2469
|
-
});
|
|
2470
|
-
$rootScope.$watch(() => {
|
|
2471
|
-
logs.push("digesting");
|
|
2472
|
-
return "digesting";
|
|
2473
|
-
});
|
|
2474
|
-
expect(logs).toEqual([]);
|
|
2475
|
-
setTimeout(() => {
|
|
2476
|
-
expect(logs).toEqual(["eval-ed!", "digesting", "digesting"]);
|
|
2477
|
-
});
|
|
2478
|
-
});
|
|
2479
|
-
|
|
2480
|
-
it("should not trigger digest asynchronously if the queue is empty in the next tick", () => {
|
|
2481
|
-
logs = [];
|
|
2482
|
-
$rootScope.$evalAsync(() => {
|
|
2483
|
-
logs.push("eval-ed!");
|
|
2484
|
-
return "eval-ed!";
|
|
2485
|
-
});
|
|
2486
|
-
$rootScope.$watch(() => {
|
|
2487
|
-
logs.push("digesting");
|
|
2488
|
-
return "digesting";
|
|
2489
|
-
});
|
|
2490
|
-
expect(logs).toEqual([]);
|
|
2491
|
-
|
|
2492
|
-
$rootScope.$digest();
|
|
2493
|
-
|
|
2494
|
-
expect(logs).toEqual(["eval-ed!", "digesting", "digesting"]);
|
|
2495
|
-
logs = [];
|
|
2496
|
-
|
|
2497
|
-
setTimeout(() => {
|
|
2498
|
-
expect(logs).toEqual([]);
|
|
2499
|
-
});
|
|
2500
|
-
});
|
|
2501
|
-
|
|
2502
|
-
it("should not schedule more than one auto-flush task", () => {
|
|
2503
|
-
logs = [];
|
|
2504
|
-
$rootScope.$evalAsync(() => {
|
|
2505
|
-
logs.push("eval-ed 1!");
|
|
2506
|
-
return "eval-ed 1!";
|
|
2507
|
-
});
|
|
2508
|
-
$rootScope.$evalAsync(() => {
|
|
2509
|
-
logs.push("eval-ed 2!");
|
|
2510
|
-
return "eval-ed 2!";
|
|
2511
|
-
});
|
|
2512
|
-
expect(logs).toEqual([]);
|
|
2513
|
-
setTimeout(() => {
|
|
2514
|
-
expect(logs).toEqual(["eval-ed 1!", "eval-ed 2!"]);
|
|
2515
|
-
});
|
|
2516
|
-
|
|
2517
|
-
setTimeout(() => {
|
|
2518
|
-
expect(logs).toEqual(["eval-ed 1!", "eval-ed 2!"]);
|
|
2519
|
-
});
|
|
2520
|
-
});
|
|
2521
|
-
|
|
2522
|
-
it("should not have execution affected by an explicit $digest call", () => {
|
|
2523
|
-
const scope1 = $rootScope.$new();
|
|
2524
|
-
const scope2 = $rootScope.$new();
|
|
2525
|
-
|
|
2526
|
-
scope1.$watch("value", (value) => {
|
|
2527
|
-
scope1.result = value;
|
|
2528
|
-
});
|
|
2529
|
-
|
|
2530
|
-
scope1.$evalAsync(() => {
|
|
2531
|
-
scope1.value = "bar";
|
|
2532
|
-
});
|
|
2533
|
-
|
|
2534
|
-
expect(scope1.result).toBe(undefined);
|
|
2535
|
-
scope2.$digest();
|
|
2536
|
-
|
|
2537
|
-
setTimeout(() => expect(scope1.result).toBe("bar"));
|
|
2538
|
-
});
|
|
2539
|
-
});
|
|
2540
|
-
|
|
2541
|
-
it("should not pass anything as `this` to scheduled functions", () => {
|
|
2542
|
-
let this1 = {};
|
|
2543
|
-
const this2 = (function () {
|
|
2544
|
-
return this;
|
|
2545
|
-
})();
|
|
2546
|
-
$rootScope.$evalAsync(function () {
|
|
2547
|
-
this1 = this;
|
|
2548
|
-
});
|
|
2549
|
-
$rootScope.$digest();
|
|
2550
|
-
expect(this1).toEqual(this2);
|
|
2551
|
-
});
|
|
2552
|
-
});
|
|
2553
|
-
|
|
2554
1236
|
describe("$apply", () => {
|
|
2555
1237
|
beforeEach(() => (logs = []));
|
|
2556
1238
|
|
|
@@ -2605,7 +1287,6 @@ describe("Scope", function () {
|
|
|
2605
1287
|
$rootScope.$watch(() => {
|
|
2606
1288
|
log += "$digest;";
|
|
2607
1289
|
});
|
|
2608
|
-
$rootScope.$digest();
|
|
2609
1290
|
log = "";
|
|
2610
1291
|
});
|
|
2611
1292
|
|
|
@@ -2755,714 +1436,98 @@ describe("Scope", function () {
|
|
|
2755
1436
|
const expression = jasmine.createSpy("expr");
|
|
2756
1437
|
|
|
2757
1438
|
$rootScope.$applyAsync(expression);
|
|
2758
|
-
$rootScope.$digest();
|
|
2759
1439
|
expect(expression).toHaveBeenCalled();
|
|
2760
1440
|
expect(cancel).toHaveBeenCalled();
|
|
2761
1441
|
expression.calls.reset();
|
|
2762
1442
|
cancel.calls.reset();
|
|
2763
1443
|
|
|
2764
1444
|
// assert that another digest won't call the function again
|
|
2765
|
-
$rootScope.$digest();
|
|
2766
1445
|
expect(expression).not.toHaveBeenCalled();
|
|
2767
1446
|
expect(cancel).not.toHaveBeenCalled();
|
|
2768
1447
|
});
|
|
2769
1448
|
});
|
|
2770
1449
|
|
|
2771
|
-
describe("
|
|
1450
|
+
describe("$postUpdate", () => {
|
|
2772
1451
|
beforeEach(() => (logs = []));
|
|
2773
1452
|
it("should process callbacks as a queue (FIFO) when the scope is digested", () => {
|
|
2774
1453
|
let signature = "";
|
|
2775
1454
|
|
|
2776
|
-
$rootScope
|
|
1455
|
+
$rootScope.$postUpdate(() => {
|
|
2777
1456
|
signature += "A";
|
|
2778
|
-
$rootScope
|
|
1457
|
+
$rootScope.$postUpdate(() => {
|
|
2779
1458
|
signature += "D";
|
|
2780
1459
|
});
|
|
2781
1460
|
});
|
|
2782
1461
|
|
|
2783
|
-
$rootScope
|
|
1462
|
+
$rootScope.$postUpdate(() => {
|
|
2784
1463
|
signature += "B";
|
|
2785
1464
|
});
|
|
2786
1465
|
|
|
2787
|
-
$rootScope
|
|
1466
|
+
$rootScope.$postUpdate(() => {
|
|
2788
1467
|
signature += "C";
|
|
2789
1468
|
});
|
|
2790
1469
|
|
|
2791
1470
|
expect(signature).toBe("");
|
|
2792
|
-
$rootScope.$digest();
|
|
2793
1471
|
expect(signature).toBe("ABCD");
|
|
2794
1472
|
});
|
|
2795
1473
|
|
|
2796
|
-
it("should support $apply calls nested in
|
|
1474
|
+
it("should support $apply calls nested in $postUpdate callbacks", () => {
|
|
2797
1475
|
let signature = "";
|
|
2798
1476
|
|
|
2799
|
-
$rootScope
|
|
1477
|
+
$rootScope.$postUpdate(() => {
|
|
2800
1478
|
signature += "A";
|
|
2801
1479
|
});
|
|
2802
1480
|
|
|
2803
|
-
$rootScope
|
|
1481
|
+
$rootScope.$postUpdate(() => {
|
|
2804
1482
|
signature += "B";
|
|
2805
1483
|
$rootScope.$apply();
|
|
2806
1484
|
signature += "D";
|
|
2807
1485
|
});
|
|
2808
1486
|
|
|
2809
|
-
$rootScope
|
|
1487
|
+
$rootScope.$postUpdate(() => {
|
|
2810
1488
|
signature += "C";
|
|
2811
1489
|
});
|
|
2812
1490
|
|
|
2813
1491
|
expect(signature).toBe("");
|
|
2814
|
-
$rootScope.$digest();
|
|
2815
1492
|
expect(signature).toBe("ABCD");
|
|
2816
1493
|
});
|
|
2817
1494
|
|
|
2818
|
-
it("should run a
|
|
1495
|
+
it("should run a $postUpdate call on all child scopes when a parent scope is digested", () => {
|
|
2819
1496
|
const parent = $rootScope.$new();
|
|
2820
1497
|
const child = parent.$new();
|
|
2821
1498
|
let count = 0;
|
|
2822
1499
|
|
|
2823
|
-
$rootScope
|
|
1500
|
+
$rootScope.$postUpdate(() => {
|
|
2824
1501
|
count++;
|
|
2825
1502
|
});
|
|
2826
1503
|
|
|
2827
|
-
parent
|
|
1504
|
+
parent.$postUpdate(() => {
|
|
2828
1505
|
count++;
|
|
2829
1506
|
});
|
|
2830
1507
|
|
|
2831
|
-
child
|
|
1508
|
+
child.$postUpdate(() => {
|
|
2832
1509
|
count++;
|
|
2833
1510
|
});
|
|
2834
1511
|
|
|
2835
1512
|
expect(count).toBe(0);
|
|
2836
|
-
$rootScope.$digest();
|
|
2837
1513
|
expect(count).toBe(3);
|
|
2838
1514
|
});
|
|
2839
1515
|
|
|
2840
|
-
it("should run a
|
|
1516
|
+
it("should run a $postUpdate call even if the child scope is isolated", () => {
|
|
2841
1517
|
const parent = $rootScope.$new();
|
|
2842
1518
|
const child = parent.$new(true);
|
|
2843
1519
|
let signature = "";
|
|
2844
1520
|
|
|
2845
|
-
parent
|
|
1521
|
+
parent.$postUpdate(() => {
|
|
2846
1522
|
signature += "A";
|
|
2847
1523
|
});
|
|
2848
1524
|
|
|
2849
|
-
child
|
|
1525
|
+
child.$postUpdate(() => {
|
|
2850
1526
|
signature += "B";
|
|
2851
1527
|
});
|
|
2852
1528
|
|
|
2853
1529
|
expect(signature).toBe("");
|
|
2854
|
-
$rootScope.$digest();
|
|
2855
1530
|
expect(signature).toBe("AB");
|
|
2856
1531
|
});
|
|
2857
1532
|
});
|
|
2858
|
-
|
|
2859
|
-
describe("events", () => {
|
|
2860
|
-
describe("$on", () => {
|
|
2861
|
-
it("should add listener for both $emit and $broadcast events", () => {
|
|
2862
|
-
logs = "";
|
|
2863
|
-
const child = $rootScope.$new();
|
|
2864
|
-
|
|
2865
|
-
function eventFn() {
|
|
2866
|
-
logs += "X";
|
|
2867
|
-
}
|
|
2868
|
-
|
|
2869
|
-
child.$on("abc", eventFn);
|
|
2870
|
-
expect(logs).toEqual("");
|
|
2871
|
-
|
|
2872
|
-
child.$emit("abc");
|
|
2873
|
-
expect(logs).toEqual("X");
|
|
2874
|
-
|
|
2875
|
-
child.$broadcast("abc");
|
|
2876
|
-
expect(logs).toEqual("XX");
|
|
2877
|
-
});
|
|
2878
|
-
|
|
2879
|
-
it("should increment ancestor $$listenerCount entries", () => {
|
|
2880
|
-
const child1 = $rootScope.$new();
|
|
2881
|
-
const child2 = child1.$new();
|
|
2882
|
-
const spy = jasmine.createSpy();
|
|
2883
|
-
|
|
2884
|
-
$rootScope.$on("event1", spy);
|
|
2885
|
-
expect($rootScope.$$listenerCount.event1).toEqual(1);
|
|
2886
|
-
|
|
2887
|
-
child1.$on("event1", spy);
|
|
2888
|
-
expect($rootScope.$$listenerCount.event1).toEqual(2);
|
|
2889
|
-
expect(child1.$$listenerCount.event1).toEqual(1);
|
|
2890
|
-
|
|
2891
|
-
child2.$on("event2", spy);
|
|
2892
|
-
expect($rootScope.$$listenerCount.event1).toEqual(2);
|
|
2893
|
-
expect($rootScope.$$listenerCount.event2).toEqual(1);
|
|
2894
|
-
expect(child1.$$listenerCount.event1).toEqual(1);
|
|
2895
|
-
expect(child1.$$listenerCount.event2).toEqual(1);
|
|
2896
|
-
expect(child2.$$listenerCount.event2).toEqual(1);
|
|
2897
|
-
});
|
|
2898
|
-
|
|
2899
|
-
describe("deregistration", () => {
|
|
2900
|
-
it("should return a function that deregisters the listener", () => {
|
|
2901
|
-
let log = "";
|
|
2902
|
-
const child = $rootScope.$new();
|
|
2903
|
-
let listenerRemove;
|
|
2904
|
-
|
|
2905
|
-
function eventFn() {
|
|
2906
|
-
log += "X";
|
|
2907
|
-
}
|
|
2908
|
-
|
|
2909
|
-
listenerRemove = child.$on("abc", eventFn);
|
|
2910
|
-
expect(log).toEqual("");
|
|
2911
|
-
expect(listenerRemove).toBeDefined();
|
|
2912
|
-
|
|
2913
|
-
child.$emit("abc");
|
|
2914
|
-
child.$broadcast("abc");
|
|
2915
|
-
expect(log).toEqual("XX");
|
|
2916
|
-
expect($rootScope.$$listenerCount.abc).toBe(1);
|
|
2917
|
-
|
|
2918
|
-
log = "";
|
|
2919
|
-
listenerRemove();
|
|
2920
|
-
child.$emit("abc");
|
|
2921
|
-
child.$broadcast("abc");
|
|
2922
|
-
expect(log).toEqual("");
|
|
2923
|
-
expect($rootScope.$$listenerCount.abc).toBeUndefined();
|
|
2924
|
-
});
|
|
2925
|
-
|
|
2926
|
-
// See issue https://github.com/angular/angular.js/issues/16135
|
|
2927
|
-
it("should deallocate the listener array entry", () => {
|
|
2928
|
-
const remove1 = $rootScope.$on("abc", () => {});
|
|
2929
|
-
$rootScope.$on("abc", () => {});
|
|
2930
|
-
|
|
2931
|
-
expect($rootScope.$$listeners.get("abc").length).toBe(2);
|
|
2932
|
-
expect(0 in $rootScope.$$listeners.get("abc")).toBe(true);
|
|
2933
|
-
|
|
2934
|
-
remove1();
|
|
2935
|
-
|
|
2936
|
-
expect($rootScope.$$listeners.get("abc").length).toBe(2);
|
|
2937
|
-
expect(0 in $rootScope.$$listeners.get("abc")).toBe(false);
|
|
2938
|
-
});
|
|
2939
|
-
|
|
2940
|
-
it("should call next listener after removing the current listener via its own handler", () => {
|
|
2941
|
-
const listener1 = jasmine.createSpy("listener1").and.callFake(() => {
|
|
2942
|
-
remove1();
|
|
2943
|
-
});
|
|
2944
|
-
let remove1 = $rootScope.$on("abc", listener1);
|
|
2945
|
-
|
|
2946
|
-
const listener2 = jasmine.createSpy("listener2");
|
|
2947
|
-
const remove2 = $rootScope.$on("abc", listener2);
|
|
2948
|
-
|
|
2949
|
-
const listener3 = jasmine.createSpy("listener3");
|
|
2950
|
-
const remove3 = $rootScope.$on("abc", listener3);
|
|
2951
|
-
|
|
2952
|
-
$rootScope.$broadcast("abc");
|
|
2953
|
-
expect(listener1).toHaveBeenCalled();
|
|
2954
|
-
expect(listener2).toHaveBeenCalled();
|
|
2955
|
-
expect(listener3).toHaveBeenCalled();
|
|
2956
|
-
|
|
2957
|
-
listener1.calls.reset();
|
|
2958
|
-
listener2.calls.reset();
|
|
2959
|
-
listener3.calls.reset();
|
|
2960
|
-
|
|
2961
|
-
$rootScope.$broadcast("abc");
|
|
2962
|
-
expect(listener1).not.toHaveBeenCalled();
|
|
2963
|
-
expect(listener2).toHaveBeenCalled();
|
|
2964
|
-
expect(listener3).toHaveBeenCalled();
|
|
2965
|
-
});
|
|
2966
|
-
|
|
2967
|
-
it("should call all subsequent listeners when a previous listener is removed via a handler", () => {
|
|
2968
|
-
const listener1 = jasmine.createSpy();
|
|
2969
|
-
const remove1 = $rootScope.$on("abc", listener1);
|
|
2970
|
-
|
|
2971
|
-
const listener2 = jasmine.createSpy().and.callFake(remove1);
|
|
2972
|
-
const remove2 = $rootScope.$on("abc", listener2);
|
|
2973
|
-
|
|
2974
|
-
const listener3 = jasmine.createSpy();
|
|
2975
|
-
const remove3 = $rootScope.$on("abc", listener3);
|
|
2976
|
-
|
|
2977
|
-
$rootScope.$broadcast("abc");
|
|
2978
|
-
expect(listener1).toHaveBeenCalled();
|
|
2979
|
-
expect(listener2).toHaveBeenCalled();
|
|
2980
|
-
expect(listener3).toHaveBeenCalled();
|
|
2981
|
-
|
|
2982
|
-
listener1.calls.reset();
|
|
2983
|
-
listener2.calls.reset();
|
|
2984
|
-
listener3.calls.reset();
|
|
2985
|
-
|
|
2986
|
-
$rootScope.$broadcast("abc");
|
|
2987
|
-
expect(listener1).not.toHaveBeenCalled();
|
|
2988
|
-
expect(listener2).toHaveBeenCalled();
|
|
2989
|
-
expect(listener3).toHaveBeenCalled();
|
|
2990
|
-
});
|
|
2991
|
-
|
|
2992
|
-
it("should not call listener when removed by previous", () => {
|
|
2993
|
-
const listener1 = jasmine.createSpy("listener1");
|
|
2994
|
-
const remove1 = $rootScope.$on("abc", listener1);
|
|
2995
|
-
|
|
2996
|
-
const listener2 = jasmine.createSpy("listener2").and.callFake(() => {
|
|
2997
|
-
remove3();
|
|
2998
|
-
});
|
|
2999
|
-
const remove2 = $rootScope.$on("abc", listener2);
|
|
3000
|
-
|
|
3001
|
-
const listener3 = jasmine.createSpy("listener3");
|
|
3002
|
-
let remove3 = $rootScope.$on("abc", listener3);
|
|
3003
|
-
|
|
3004
|
-
const listener4 = jasmine.createSpy("listener4");
|
|
3005
|
-
const remove4 = $rootScope.$on("abc", listener4);
|
|
3006
|
-
|
|
3007
|
-
$rootScope.$broadcast("abc");
|
|
3008
|
-
expect(listener1).toHaveBeenCalled();
|
|
3009
|
-
expect(listener2).toHaveBeenCalled();
|
|
3010
|
-
expect(listener3).not.toHaveBeenCalled();
|
|
3011
|
-
expect(listener4).toHaveBeenCalled();
|
|
3012
|
-
|
|
3013
|
-
listener1.calls.reset();
|
|
3014
|
-
listener2.calls.reset();
|
|
3015
|
-
listener3.calls.reset();
|
|
3016
|
-
listener4.calls.reset();
|
|
3017
|
-
|
|
3018
|
-
$rootScope.$broadcast("abc");
|
|
3019
|
-
expect(listener1).toHaveBeenCalled();
|
|
3020
|
-
expect(listener2).toHaveBeenCalled();
|
|
3021
|
-
expect(listener3).not.toHaveBeenCalled();
|
|
3022
|
-
expect(listener4).toHaveBeenCalled();
|
|
3023
|
-
});
|
|
3024
|
-
|
|
3025
|
-
it("should decrement ancestor $$listenerCount entries", () => {
|
|
3026
|
-
const child1 = $rootScope.$new();
|
|
3027
|
-
const child2 = child1.$new();
|
|
3028
|
-
const spy = jasmine.createSpy();
|
|
3029
|
-
|
|
3030
|
-
$rootScope.$on("event1", spy);
|
|
3031
|
-
expect($rootScope.$$listenerCount.event1).toEqual(1);
|
|
3032
|
-
|
|
3033
|
-
child1.$on("event1", spy);
|
|
3034
|
-
expect($rootScope.$$listenerCount.event1).toEqual(2);
|
|
3035
|
-
expect(child1.$$listenerCount.event1).toEqual(1);
|
|
3036
|
-
|
|
3037
|
-
const deregisterEvent2Listener = child2.$on("event2", spy);
|
|
3038
|
-
expect($rootScope.$$listenerCount.event1).toEqual(2);
|
|
3039
|
-
expect($rootScope.$$listenerCount.event2).toEqual(1);
|
|
3040
|
-
expect(child1.$$listenerCount.event1).toEqual(1);
|
|
3041
|
-
expect(child1.$$listenerCount.event2).toEqual(1);
|
|
3042
|
-
expect(child2.$$listenerCount.event2).toEqual(1);
|
|
3043
|
-
|
|
3044
|
-
deregisterEvent2Listener();
|
|
3045
|
-
|
|
3046
|
-
expect($rootScope.$$listenerCount.event1).toEqual(2);
|
|
3047
|
-
expect(child1.$$listenerCount.event1).toEqual(1);
|
|
3048
|
-
expect(child2.$$listenerCount).toBeTruthy();
|
|
3049
|
-
});
|
|
3050
|
-
|
|
3051
|
-
it("should not decrement $$listenerCount when called second time", () => {
|
|
3052
|
-
const child = $rootScope.$new();
|
|
3053
|
-
const listener1Spy = jasmine.createSpy();
|
|
3054
|
-
const listener2Spy = jasmine.createSpy();
|
|
3055
|
-
|
|
3056
|
-
child.$on("abc", listener1Spy);
|
|
3057
|
-
expect($rootScope.$$listenerCount.abc).toEqual(1);
|
|
3058
|
-
expect(child.$$listenerCount.abc).toEqual(1);
|
|
3059
|
-
|
|
3060
|
-
const deregisterEventListener = child.$on("abc", listener2Spy);
|
|
3061
|
-
expect($rootScope.$$listenerCount.abc).toEqual(2);
|
|
3062
|
-
expect(child.$$listenerCount.abc).toEqual(2);
|
|
3063
|
-
|
|
3064
|
-
deregisterEventListener();
|
|
3065
|
-
|
|
3066
|
-
expect($rootScope.$$listenerCount.abc).toEqual(1);
|
|
3067
|
-
expect(child.$$listenerCount.abc).toEqual(1);
|
|
3068
|
-
|
|
3069
|
-
deregisterEventListener();
|
|
3070
|
-
|
|
3071
|
-
expect($rootScope.$$listenerCount.abc).toEqual(1);
|
|
3072
|
-
expect(child.$$listenerCount.abc).toEqual(1);
|
|
3073
|
-
});
|
|
3074
|
-
});
|
|
3075
|
-
});
|
|
3076
|
-
|
|
3077
|
-
describe("$emit", () => {
|
|
3078
|
-
let log;
|
|
3079
|
-
let child;
|
|
3080
|
-
let grandChild;
|
|
3081
|
-
let greatGrandChild;
|
|
3082
|
-
|
|
3083
|
-
function logger(event) {
|
|
3084
|
-
log += `${event.currentScope.id}>`;
|
|
3085
|
-
}
|
|
3086
|
-
|
|
3087
|
-
beforeEach(() => {
|
|
3088
|
-
log = "";
|
|
3089
|
-
logs = [];
|
|
3090
|
-
child = $rootScope.$new();
|
|
3091
|
-
grandChild = child.$new();
|
|
3092
|
-
greatGrandChild = grandChild.$new();
|
|
3093
|
-
|
|
3094
|
-
$rootScope.id = 0;
|
|
3095
|
-
child.id = 1;
|
|
3096
|
-
grandChild.id = 2;
|
|
3097
|
-
greatGrandChild.id = 3;
|
|
3098
|
-
|
|
3099
|
-
$rootScope.$on("myEvent", logger);
|
|
3100
|
-
child.$on("myEvent", logger);
|
|
3101
|
-
grandChild.$on("myEvent", logger);
|
|
3102
|
-
greatGrandChild.$on("myEvent", logger);
|
|
3103
|
-
});
|
|
3104
|
-
|
|
3105
|
-
it("should bubble event up to the root scope", () => {
|
|
3106
|
-
grandChild.$emit("myEvent");
|
|
3107
|
-
expect(log).toEqual("2>1>0>");
|
|
3108
|
-
});
|
|
3109
|
-
|
|
3110
|
-
it("should allow all events on the same scope to run even if stopPropagation is called", () => {
|
|
3111
|
-
child.$on("myEvent", logger);
|
|
3112
|
-
grandChild.$on("myEvent", (e) => {
|
|
3113
|
-
e.stopPropagation();
|
|
3114
|
-
});
|
|
3115
|
-
grandChild.$on("myEvent", logger);
|
|
3116
|
-
grandChild.$on("myEvent", logger);
|
|
3117
|
-
grandChild.$emit("myEvent");
|
|
3118
|
-
expect(log).toEqual("2>2>2>");
|
|
3119
|
-
});
|
|
3120
|
-
|
|
3121
|
-
it("should dispatch exceptions to the $exceptionHandler", () => {
|
|
3122
|
-
child.$on("myEvent", () => {
|
|
3123
|
-
throw "bubbleException";
|
|
3124
|
-
});
|
|
3125
|
-
grandChild.$emit("myEvent");
|
|
3126
|
-
expect(log).toEqual("2>1>0>");
|
|
3127
|
-
expect(logs).toEqual(["bubbleException"]);
|
|
3128
|
-
});
|
|
3129
|
-
|
|
3130
|
-
it("should allow stopping event propagation", () => {
|
|
3131
|
-
child.$on("myEvent", (event) => {
|
|
3132
|
-
event.stopPropagation();
|
|
3133
|
-
});
|
|
3134
|
-
grandChild.$emit("myEvent");
|
|
3135
|
-
expect(log).toEqual("2>1>");
|
|
3136
|
-
});
|
|
3137
|
-
|
|
3138
|
-
it("should forward method arguments", () => {
|
|
3139
|
-
child.$on("abc", (event, arg1, arg2) => {
|
|
3140
|
-
expect(event.name).toBe("abc");
|
|
3141
|
-
expect(arg1).toBe("arg1");
|
|
3142
|
-
expect(arg2).toBe("arg2");
|
|
3143
|
-
});
|
|
3144
|
-
child.$emit("abc", "arg1", "arg2");
|
|
3145
|
-
});
|
|
3146
|
-
|
|
3147
|
-
it("should allow removing event listener inside a listener on $emit", () => {
|
|
3148
|
-
const spy1 = jasmine.createSpy("1st listener");
|
|
3149
|
-
const spy2 = jasmine.createSpy("2nd listener");
|
|
3150
|
-
const spy3 = jasmine.createSpy("3rd listener");
|
|
3151
|
-
|
|
3152
|
-
const remove1 = child.$on("evt", spy1);
|
|
3153
|
-
const remove2 = child.$on("evt", spy2);
|
|
3154
|
-
const remove3 = child.$on("evt", spy3);
|
|
3155
|
-
|
|
3156
|
-
spy1.and.callFake(remove1);
|
|
3157
|
-
|
|
3158
|
-
expect(child.$$listeners.get("evt").length).toBe(3);
|
|
3159
|
-
|
|
3160
|
-
// should call all listeners and remove 1st
|
|
3161
|
-
child.$emit("evt");
|
|
3162
|
-
expect(spy1).toHaveBeenCalled();
|
|
3163
|
-
expect(spy2).toHaveBeenCalled();
|
|
3164
|
-
expect(spy3).toHaveBeenCalled();
|
|
3165
|
-
expect(child.$$listeners.get("evt").length).toBe(3); // cleanup will happen on next $emit
|
|
3166
|
-
|
|
3167
|
-
spy1.calls.reset();
|
|
3168
|
-
spy2.calls.reset();
|
|
3169
|
-
spy3.calls.reset();
|
|
3170
|
-
|
|
3171
|
-
// should call only 2nd because 1st was already removed and 2nd removes 3rd
|
|
3172
|
-
spy2.and.callFake(remove3);
|
|
3173
|
-
child.$emit("evt");
|
|
3174
|
-
expect(spy1).not.toHaveBeenCalled();
|
|
3175
|
-
expect(spy2).toHaveBeenCalled();
|
|
3176
|
-
expect(spy3).not.toHaveBeenCalled();
|
|
3177
|
-
expect(child.$$listeners.get("evt").length).toBe(1);
|
|
3178
|
-
});
|
|
3179
|
-
|
|
3180
|
-
it("should allow removing event listener inside a listener on $broadcast", () => {
|
|
3181
|
-
const spy1 = jasmine.createSpy("1st listener");
|
|
3182
|
-
const spy2 = jasmine.createSpy("2nd listener");
|
|
3183
|
-
const spy3 = jasmine.createSpy("3rd listener");
|
|
3184
|
-
|
|
3185
|
-
const remove1 = child.$on("evt", spy1);
|
|
3186
|
-
const remove2 = child.$on("evt", spy2);
|
|
3187
|
-
const remove3 = child.$on("evt", spy3);
|
|
3188
|
-
|
|
3189
|
-
spy1.and.callFake(remove1);
|
|
3190
|
-
|
|
3191
|
-
expect(child.$$listeners.get("evt").length).toBe(3);
|
|
3192
|
-
|
|
3193
|
-
// should call all listeners and remove 1st
|
|
3194
|
-
child.$broadcast("evt");
|
|
3195
|
-
expect(spy1).toHaveBeenCalled();
|
|
3196
|
-
expect(spy2).toHaveBeenCalled();
|
|
3197
|
-
expect(spy3).toHaveBeenCalled();
|
|
3198
|
-
expect(child.$$listeners.get("evt").length).toBe(3); // cleanup will happen on next $broadcast
|
|
3199
|
-
|
|
3200
|
-
spy1.calls.reset();
|
|
3201
|
-
spy2.calls.reset();
|
|
3202
|
-
spy3.calls.reset();
|
|
3203
|
-
|
|
3204
|
-
// should call only 2nd because 1st was already removed and 2nd removes 3rd
|
|
3205
|
-
spy2.and.callFake(remove3);
|
|
3206
|
-
child.$broadcast("evt");
|
|
3207
|
-
expect(spy1).not.toHaveBeenCalled();
|
|
3208
|
-
expect(spy2).toHaveBeenCalled();
|
|
3209
|
-
expect(spy3).not.toHaveBeenCalled();
|
|
3210
|
-
expect(child.$$listeners.get("evt").length).toBe(1);
|
|
3211
|
-
});
|
|
3212
|
-
|
|
3213
|
-
describe("event object", () => {
|
|
3214
|
-
it("should have methods/properties", () => {
|
|
3215
|
-
let eventFired = false;
|
|
3216
|
-
|
|
3217
|
-
child.$on("myEvent", (e) => {
|
|
3218
|
-
expect(e.targetScope).toBe(grandChild);
|
|
3219
|
-
expect(e.currentScope).toBe(child);
|
|
3220
|
-
expect(e.name).toBe("myEvent");
|
|
3221
|
-
eventFired = true;
|
|
3222
|
-
});
|
|
3223
|
-
grandChild.$emit("myEvent");
|
|
3224
|
-
expect(eventFired).toBe(true);
|
|
3225
|
-
});
|
|
3226
|
-
|
|
3227
|
-
it("should have its `currentScope` property set to null after emit", () => {
|
|
3228
|
-
let event;
|
|
3229
|
-
|
|
3230
|
-
child.$on("myEvent", (e) => {
|
|
3231
|
-
event = e;
|
|
3232
|
-
});
|
|
3233
|
-
grandChild.$emit("myEvent");
|
|
3234
|
-
|
|
3235
|
-
expect(event.currentScope).toBe(null);
|
|
3236
|
-
expect(event.targetScope).toBe(grandChild);
|
|
3237
|
-
expect(event.name).toBe("myEvent");
|
|
3238
|
-
});
|
|
3239
|
-
|
|
3240
|
-
it("should have preventDefault method and defaultPrevented property", () => {
|
|
3241
|
-
let event = grandChild.$emit("myEvent");
|
|
3242
|
-
expect(event.defaultPrevented).toBe(false);
|
|
3243
|
-
|
|
3244
|
-
child.$on("myEvent", (event) => {
|
|
3245
|
-
event.preventDefault();
|
|
3246
|
-
});
|
|
3247
|
-
event = grandChild.$emit("myEvent");
|
|
3248
|
-
expect(event.defaultPrevented).toBe(true);
|
|
3249
|
-
expect(event.currentScope).toBe(null);
|
|
3250
|
-
});
|
|
3251
|
-
});
|
|
3252
|
-
});
|
|
3253
|
-
|
|
3254
|
-
describe("$broadcast", () => {
|
|
3255
|
-
describe("event propagation", () => {
|
|
3256
|
-
let log;
|
|
3257
|
-
let child1;
|
|
3258
|
-
let child2;
|
|
3259
|
-
let child3;
|
|
3260
|
-
let grandChild11;
|
|
3261
|
-
let grandChild21;
|
|
3262
|
-
let grandChild22;
|
|
3263
|
-
let grandChild23;
|
|
3264
|
-
let greatGrandChild211;
|
|
3265
|
-
|
|
3266
|
-
function logger(event) {
|
|
3267
|
-
log += `${event.currentScope.id}>`;
|
|
3268
|
-
}
|
|
3269
|
-
|
|
3270
|
-
beforeEach(() => {
|
|
3271
|
-
log = "";
|
|
3272
|
-
child1 = $rootScope.$new();
|
|
3273
|
-
child2 = $rootScope.$new();
|
|
3274
|
-
child3 = $rootScope.$new();
|
|
3275
|
-
grandChild11 = child1.$new();
|
|
3276
|
-
grandChild21 = child2.$new();
|
|
3277
|
-
grandChild22 = child2.$new();
|
|
3278
|
-
grandChild23 = child2.$new();
|
|
3279
|
-
greatGrandChild211 = grandChild21.$new();
|
|
3280
|
-
|
|
3281
|
-
$rootScope.id = 0;
|
|
3282
|
-
child1.id = 1;
|
|
3283
|
-
child2.id = 2;
|
|
3284
|
-
child3.id = 3;
|
|
3285
|
-
grandChild11.id = 11;
|
|
3286
|
-
grandChild21.id = 21;
|
|
3287
|
-
grandChild22.id = 22;
|
|
3288
|
-
grandChild23.id = 23;
|
|
3289
|
-
greatGrandChild211.id = 211;
|
|
3290
|
-
|
|
3291
|
-
$rootScope.$on("myEvent", logger);
|
|
3292
|
-
child1.$on("myEvent", logger);
|
|
3293
|
-
child2.$on("myEvent", logger);
|
|
3294
|
-
child3.$on("myEvent", logger);
|
|
3295
|
-
grandChild11.$on("myEvent", logger);
|
|
3296
|
-
grandChild21.$on("myEvent", logger);
|
|
3297
|
-
grandChild22.$on("myEvent", logger);
|
|
3298
|
-
grandChild23.$on("myEvent", logger);
|
|
3299
|
-
greatGrandChild211.$on("myEvent", logger);
|
|
3300
|
-
|
|
3301
|
-
// R
|
|
3302
|
-
// / | \
|
|
3303
|
-
// 1 2 3
|
|
3304
|
-
// / / | \
|
|
3305
|
-
// 11 21 22 23
|
|
3306
|
-
// |
|
|
3307
|
-
// 211
|
|
3308
|
-
});
|
|
3309
|
-
|
|
3310
|
-
it("should broadcast an event from the root scope", () => {
|
|
3311
|
-
$rootScope.$broadcast("myEvent");
|
|
3312
|
-
expect(log).toBe("0>1>11>2>21>211>22>23>3>");
|
|
3313
|
-
});
|
|
3314
|
-
|
|
3315
|
-
it("should broadcast an event from a child scope", () => {
|
|
3316
|
-
child2.$broadcast("myEvent");
|
|
3317
|
-
expect(log).toBe("2>21>211>22>23>");
|
|
3318
|
-
});
|
|
3319
|
-
|
|
3320
|
-
it("should broadcast an event from a leaf scope with a sibling", () => {
|
|
3321
|
-
grandChild22.$broadcast("myEvent");
|
|
3322
|
-
expect(log).toBe("22>");
|
|
3323
|
-
});
|
|
3324
|
-
|
|
3325
|
-
it("should broadcast an event from a leaf scope without a sibling", () => {
|
|
3326
|
-
grandChild23.$broadcast("myEvent");
|
|
3327
|
-
expect(log).toBe("23>");
|
|
3328
|
-
});
|
|
3329
|
-
|
|
3330
|
-
it("should not not fire any listeners for other events", () => {
|
|
3331
|
-
$rootScope.$broadcast("fooEvent");
|
|
3332
|
-
expect(log).toBe("");
|
|
3333
|
-
});
|
|
3334
|
-
|
|
3335
|
-
it("should not descend past scopes with a $$listerCount of 0 or undefined", () => {
|
|
3336
|
-
const EVENT = "fooEvent";
|
|
3337
|
-
const spy = jasmine.createSpy("listener");
|
|
3338
|
-
|
|
3339
|
-
// Precondition: There should be no listeners for fooEvent.
|
|
3340
|
-
expect($rootScope.$$listenerCount[EVENT]).toBeUndefined();
|
|
3341
|
-
|
|
3342
|
-
// Add a spy listener to a child scope.
|
|
3343
|
-
$rootScope.$$childHead.$$listeners[EVENT] = [spy];
|
|
3344
|
-
|
|
3345
|
-
// $rootScope's count for 'fooEvent' is undefined, so spy should not be called.
|
|
3346
|
-
$rootScope.$broadcast(EVENT);
|
|
3347
|
-
expect(spy).not.toHaveBeenCalled();
|
|
3348
|
-
});
|
|
3349
|
-
|
|
3350
|
-
it("should return event object", () => {
|
|
3351
|
-
const result = child1.$broadcast("some");
|
|
3352
|
-
|
|
3353
|
-
expect(result).toBeDefined();
|
|
3354
|
-
expect(result.name).toBe("some");
|
|
3355
|
-
expect(result.targetScope).toBe(child1);
|
|
3356
|
-
});
|
|
3357
|
-
});
|
|
3358
|
-
|
|
3359
|
-
describe("listener", () => {
|
|
3360
|
-
it("should receive event object", () => {
|
|
3361
|
-
const scope = $rootScope;
|
|
3362
|
-
const child = scope.$new();
|
|
3363
|
-
let eventFired = false;
|
|
3364
|
-
|
|
3365
|
-
child.$on("fooEvent", (event) => {
|
|
3366
|
-
eventFired = true;
|
|
3367
|
-
expect(event.name).toBe("fooEvent");
|
|
3368
|
-
expect(event.targetScope).toBe(scope);
|
|
3369
|
-
expect(event.currentScope).toBe(child);
|
|
3370
|
-
});
|
|
3371
|
-
scope.$broadcast("fooEvent");
|
|
3372
|
-
|
|
3373
|
-
expect(eventFired).toBe(true);
|
|
3374
|
-
});
|
|
3375
|
-
|
|
3376
|
-
it("should have the event's `currentScope` property set to null after broadcast", () => {
|
|
3377
|
-
const scope = $rootScope;
|
|
3378
|
-
const child = scope.$new();
|
|
3379
|
-
let event;
|
|
3380
|
-
|
|
3381
|
-
child.$on("fooEvent", (e) => {
|
|
3382
|
-
event = e;
|
|
3383
|
-
});
|
|
3384
|
-
scope.$broadcast("fooEvent");
|
|
3385
|
-
|
|
3386
|
-
expect(event.name).toBe("fooEvent");
|
|
3387
|
-
expect(event.targetScope).toBe(scope);
|
|
3388
|
-
expect(event.currentScope).toBe(null);
|
|
3389
|
-
});
|
|
3390
|
-
|
|
3391
|
-
it("should support passing messages as constargs", () => {
|
|
3392
|
-
const scope = $rootScope;
|
|
3393
|
-
const child = scope.$new();
|
|
3394
|
-
let args;
|
|
3395
|
-
|
|
3396
|
-
child.$on("fooEvent", function () {
|
|
3397
|
-
args = arguments;
|
|
3398
|
-
});
|
|
3399
|
-
scope.$broadcast("fooEvent", "do", "re", "me", "fa");
|
|
3400
|
-
|
|
3401
|
-
expect(args.length).toBe(5);
|
|
3402
|
-
expect(sliceArgs(args, 1)).toEqual(["do", "re", "me", "fa"]);
|
|
3403
|
-
});
|
|
3404
|
-
});
|
|
3405
|
-
});
|
|
3406
|
-
|
|
3407
|
-
it("should allow recursive $emit/$broadcast", () => {
|
|
3408
|
-
let callCount = 0;
|
|
3409
|
-
$rootScope.$on("evt", ($event, arg0) => {
|
|
3410
|
-
callCount++;
|
|
3411
|
-
if (arg0 !== 1234) {
|
|
3412
|
-
$rootScope.$emit("evt", 1234);
|
|
3413
|
-
$rootScope.$broadcast("evt", 1234);
|
|
3414
|
-
}
|
|
3415
|
-
});
|
|
3416
|
-
|
|
3417
|
-
$rootScope.$emit("evt");
|
|
3418
|
-
$rootScope.$broadcast("evt");
|
|
3419
|
-
expect(callCount).toBe(6);
|
|
3420
|
-
});
|
|
3421
|
-
|
|
3422
|
-
it("should allow recursive $emit/$broadcast between parent/child", () => {
|
|
3423
|
-
const child = $rootScope.$new();
|
|
3424
|
-
let calls = "";
|
|
3425
|
-
|
|
3426
|
-
$rootScope.$on("evt", ($event, arg0) => {
|
|
3427
|
-
calls += "r"; // For "root".
|
|
3428
|
-
if (arg0 === "fromChild") {
|
|
3429
|
-
$rootScope.$broadcast("evt", "fromRoot2");
|
|
3430
|
-
}
|
|
3431
|
-
});
|
|
3432
|
-
|
|
3433
|
-
child.$on("evt", ($event, arg0) => {
|
|
3434
|
-
calls += "c"; // For "child".
|
|
3435
|
-
if (arg0 === "fromRoot1") {
|
|
3436
|
-
child.$emit("evt", "fromChild");
|
|
3437
|
-
}
|
|
3438
|
-
});
|
|
3439
|
-
|
|
3440
|
-
$rootScope.$broadcast("evt", "fromRoot1");
|
|
3441
|
-
expect(calls).toBe("rccrrc");
|
|
3442
|
-
});
|
|
3443
|
-
});
|
|
3444
|
-
|
|
3445
|
-
describe("doc examples", () => {
|
|
3446
|
-
it("should properly fire off watch listeners upon scope changes", () => {
|
|
3447
|
-
// <docs tag="docs1">
|
|
3448
|
-
const scope = $rootScope.$new();
|
|
3449
|
-
scope.salutation = "Hello";
|
|
3450
|
-
scope.name = "World";
|
|
3451
|
-
|
|
3452
|
-
expect(scope.greeting).toEqual(undefined);
|
|
3453
|
-
|
|
3454
|
-
scope.$watch("name", () => {
|
|
3455
|
-
scope.greeting = `${scope.salutation} ${scope.name}!`;
|
|
3456
|
-
}); // initialize the watch
|
|
3457
|
-
|
|
3458
|
-
expect(scope.greeting).toEqual(undefined);
|
|
3459
|
-
scope.name = "Misko";
|
|
3460
|
-
// still old value, since watches have not been called yet
|
|
3461
|
-
expect(scope.greeting).toEqual(undefined);
|
|
3462
|
-
|
|
3463
|
-
scope.$digest(); // fire all the watches
|
|
3464
|
-
expect(scope.greeting).toEqual("Hello Misko!");
|
|
3465
|
-
// </docs>
|
|
3466
|
-
});
|
|
3467
|
-
});
|
|
3468
1533
|
});
|