Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.

Commit 706d1b7

Browse files
committed
Merge pull request #104 from gary-b/scopeModelChanges
fix(scopes): check all scopes for changes on apply
2 parents 1c83935 + 3569f12 commit 706d1b7

File tree

2 files changed

+132
-23
lines changed

2 files changed

+132
-23
lines changed

src/modules/scopes.js

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function decorateRootScope($delegate, $parse) {
1919
var scopes = {},
2020
watching = {};
2121

22-
var debouncedEmitModelChange = debounceOn(emitModelChange, 10, byScopeId);
22+
var debouncedEmitModelChange = debounceOn(emitModelChange, 10);
2323

2424
hint.watch = function (scopeId, path) {
2525
path = typeof path === 'string' ? path.split('.') : path;
@@ -201,7 +201,7 @@ function decorateRootScope($delegate, $parse) {
201201
var ret = _apply.apply(this, arguments);
202202
// var end = perf.now();
203203
// hint.emit('scope:apply', { id: this.$id, time: end - start });
204-
debouncedEmitModelChange(this);
204+
debouncedEmitModelChange();
205205
return ret;
206206
};
207207

@@ -218,23 +218,22 @@ function decorateRootScope($delegate, $parse) {
218218
};
219219
}
220220

221-
function emitModelChange (scope) {
222-
var scopeId = scope.$id;
223-
if (watching[scopeId]) {
221+
function emitModelChange () {
222+
Object.keys(watching).forEach(function (scopeId) {
224223
Object.keys(watching[scopeId]).forEach(function (path) {
225224
var model = watching[scopeId][path];
226225
var value = summarize(model.get());
227226
if (value !== model.value) {
228227
hint.emit('model:change', {
229-
id: scope.$id,
228+
id: (angular.version.minor < 3) ? scopeId : parseInt(scopeId),
230229
path: path,
231230
oldValue: model.value,
232231
value: value
233232
});
234233
model.value = value;
235234
}
236235
});
237-
}
236+
});
238237
}
239238

240239
hint.emit('scope:new', {
@@ -299,10 +298,6 @@ function scopeDescriptor (elt, scope) {
299298
}
300299
}
301300

302-
function byScopeId (scope) {
303-
return scope.$id;
304-
}
305-
306301
function humanReadableWatchExpression (fn) {
307302
if (fn.exp) {
308303
fn = fn.exp;

test/scopes.spec.js

Lines changed: 126 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,135 @@ describe('ngHintScopes', function() {
132132
});
133133
});
134134

135-
// describe('$rootScope.$apply', function() {
136-
// it('should fire a message when called', function() {
137-
// var scope = $rootScope.$new();
138-
// spyOn(hint, 'emit');
135+
describe('$rootScope.$apply', function() {
136+
beforeEach(function () {
137+
jasmine.clock().install();
138+
});
139139

140-
// scope.$apply();
140+
afterEach(function() {
141+
jasmine.clock().uninstall();
142+
});
141143

142-
// expect(hint.emit).toHaveBeenCalled();
143-
// var args = hint.emit.calls[1].args;
144+
// it('should fire a message when called', function() {
145+
// var scope = $rootScope.$new();
146+
// spyOn(hint, 'emit');
144147

145-
// expect(args[0]).toBe('scope:apply');
146-
// expect(args[1].id).toBe(scope.$id);
147-
// expect(args[1].time).toBeDefined();
148-
// });
149-
// });
148+
// scope.$apply();
149+
150+
// expect(hint.emit).toHaveBeenCalled();
151+
// var args = hint.emit.calls[1].args;
152+
153+
// expect(args[0]).toBe('scope:apply');
154+
// expect(args[1].id).toBe(scope.$id);
155+
// expect(args[1].time).toBeDefined();
156+
// });
157+
158+
it('should cause model:change events to be emitted for all paths on current scope', function() {
159+
var scope = $rootScope.$new();
160+
scope.a = { b: { c: 1 } };
161+
hint.watch(scope.$id, 'a.b.c');
162+
jasmine.clock().tick(10);
163+
spyOn(hint, 'emit');
164+
scope.a.b.c = 2;
165+
scope.$apply();
166+
jasmine.clock().tick(10);
167+
168+
expect(hint.emit.calls.count()).toEqual(3);
169+
170+
var args = getArgsOfNthCall(0);
171+
expect(args[0]).toBe('scope:digest');
172+
173+
args = getArgsOfNthCall(1);
174+
expect(args[0]).toBe('model:change');
175+
expect(args[1]).toEqual({
176+
id : scope.$id,
177+
path : 'a.b',
178+
oldValue : '{"c":1}',
179+
value : '{"c":2}'
180+
});
181+
182+
args = getArgsOfNthCall(2);
183+
expect(args[0]).toBe('model:change');
184+
expect(args[1]).toEqual({
185+
id : scope.$id,
186+
path : 'a.b.c',
187+
oldValue : 1,
188+
value : 2
189+
});
190+
});
191+
192+
it('should cause model:change events to be emitted for all other watched scopes', function() {
193+
var parentScope = $rootScope.$new();
194+
var targetScope = parentScope.$new();
195+
var childScope = targetScope.$new();
196+
var siblingScope = parentScope.$new();
197+
198+
parentScope.a = 1;
199+
childScope.b = 1;
200+
siblingScope.c = 1;
201+
202+
hint.watch(parentScope.$id, 'a');
203+
hint.watch(childScope.$id, 'b');
204+
hint.watch(siblingScope.$id, 'c');
205+
jasmine.clock().tick(10);
206+
spyOn(hint, 'emit');
207+
parentScope.a = 2;
208+
childScope.b = 2;
209+
siblingScope.c = 2;
210+
targetScope.$apply();
211+
jasmine.clock().tick(10);
212+
213+
expect(hint.emit.calls.count()).toEqual(4);
214+
215+
var args = getArgsOfNthCall(0);
216+
expect(args[0]).toBe('scope:digest');
217+
218+
args = getArgsOfNthCall(1);
219+
expect(args[0]).toBe('model:change');
220+
expect(args[1]).toEqual({
221+
id : parentScope.$id,
222+
path : 'a',
223+
oldValue : 1,
224+
value : 2
225+
});
226+
227+
args = getArgsOfNthCall(2);
228+
expect(args[0]).toBe('model:change');
229+
expect(args[1]).toEqual({
230+
id : childScope.$id,
231+
path : 'b',
232+
oldValue : 1,
233+
value : 2
234+
});
235+
236+
args = getArgsOfNthCall(3);
237+
expect(args[0]).toBe('model:change');
238+
expect(args[1]).toEqual({
239+
id : siblingScope.$id,
240+
path : 'c',
241+
oldValue : 1,
242+
value : 2
243+
});
244+
});
245+
246+
it('should maintain the data type of the $id for the current angular version', function() {
247+
var targetScope = $rootScope.$new();
248+
targetScope.a = 1;
249+
hint.watch(targetScope.$id, 'a');
250+
jasmine.clock().tick(10);
251+
spyOn(hint, 'emit');
252+
targetScope.a = 2;
253+
254+
targetScope.$apply();
255+
jasmine.clock().tick(10);
256+
257+
var args = getArgsOfNthCall(1);
258+
expect(args[0]).toBe('model:change');
259+
260+
// expect strings for angular 1.2, integers for 1.3+
261+
expect(args[1].id).toBe(targetScope.$id);
262+
});
263+
});
150264

151265
describe('hint.watch', function() {
152266
var scope;

0 commit comments

Comments
 (0)