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

Commit 6d0b325

Browse files
R. Merkertpetebacondarwin
R. Merkert
authored andcommitted
fix(angular): do not copy $$hashKey in copy/extend functions.
Copying the $$hashKey as part of copy/extend operations makes little sense since hashkey is used primarily as an object id, especially in the context of the ngRepeat directive. This change maintains the existing $$hashKey of an object that is being copied into (likewise for extend). It is not uncommon to take an item in a collection, copy it, and then append it to the collection. By copying the $$hashKey, this leads to duplicate object errors with the current ngRepeat. Closes #1875
1 parent cf4729f commit 6d0b325

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

src/Angular.js

+20
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,21 @@ function nextUid() {
215215
return uid.join('');
216216
}
217217

218+
219+
/**
220+
* Set or clear the hashkey for an object.
221+
* @param obj object
222+
* @param h the hashkey (!truthy to delete the hashkey)
223+
*/
224+
function setHashKey(obj, h) {
225+
if (h) {
226+
obj.$$hashKey = h;
227+
}
228+
else {
229+
delete obj.$$hashKey;
230+
}
231+
}
232+
218233
/**
219234
* @ngdoc function
220235
* @name angular.extend
@@ -228,13 +243,16 @@ function nextUid() {
228243
* @param {...Object} src Source object(s).
229244
*/
230245
function extend(dst) {
246+
var h = dst.$$hashKey;
231247
forEach(arguments, function(obj){
232248
if (obj !== dst) {
233249
forEach(obj, function(value, key){
234250
dst[key] = value;
235251
});
236252
}
237253
});
254+
255+
setHashKey(dst,h);
238256
return dst;
239257
}
240258

@@ -594,12 +612,14 @@ function copy(source, destination){
594612
destination.push(copy(source[i]));
595613
}
596614
} else {
615+
var h = destination.$$hashKey;
597616
forEach(destination, function(value, key){
598617
delete destination[key];
599618
});
600619
for ( var key in source) {
601620
destination[key] = copy(source[key]);
602621
}
622+
setHashKey(destination,h);
603623
}
604624
}
605625
return destination;

test/AngularSpec.js

+57
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,63 @@ describe('angular', function() {
9898
src = dst = [2, 4];
9999
expect(function() { copy(src, dst); }).toThrow("Can't copy equivalent objects or arrays");
100100
});
101+
102+
it('should not copy the private $$hashKey', function() {
103+
var src,dst;
104+
src = {};
105+
hashKey(src);
106+
dst = copy(src);
107+
expect(hashKey(dst)).not.toEqual(hashKey(src));
108+
});
109+
110+
it('should retain the previous $$hashKey', function() {
111+
var src,dst,h;
112+
src = {};
113+
dst = {};
114+
// force creation of a hashkey
115+
h = hashKey(dst);
116+
hashKey(src);
117+
dst = copy(src,dst);
118+
119+
// make sure we don't copy the key
120+
expect(hashKey(dst)).not.toEqual(hashKey(src));
121+
// make sure we retain the old key
122+
expect(hashKey(dst)).toEqual(h);
123+
});
124+
});
125+
126+
describe("extend", function() {
127+
128+
it('should not copy the private $$hashKey', function() {
129+
var src,dst;
130+
src = {};
131+
dst = {};
132+
hashKey(src);
133+
dst = extend(dst,src);
134+
expect(hashKey(dst)).not.toEqual(hashKey(src));
135+
});
136+
137+
it('should retain the previous $$hashKey', function() {
138+
var src,dst,h;
139+
src = {};
140+
dst = {};
141+
h = hashKey(dst);
142+
hashKey(src);
143+
dst = extend(dst,src);
144+
// make sure we don't copy the key
145+
expect(hashKey(dst)).not.toEqual(hashKey(src));
146+
// make sure we retain the old key
147+
expect(hashKey(dst)).toEqual(h);
148+
});
149+
150+
it('should work when extending with itself', function() {
151+
var src,dst,h;
152+
dst = src = {};
153+
h = hashKey(dst);
154+
dst = extend(dst,src);
155+
// make sure we retain the old key
156+
expect(hashKey(dst)).toEqual(h);
157+
});
101158
});
102159

103160
describe('shallow copy', function() {

0 commit comments

Comments
 (0)