Skip to content

Commit 016e1e6

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 angular#1875
1 parent 1240641 commit 016e1e6

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

src/Angular.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,21 @@ function nextUid() {
195195
return uid.join('');
196196
}
197197

198+
199+
/**
200+
* Set or clear the hashkey for an object.
201+
* @param obj object
202+
* @param h the hashkey (!truthy to delete the hashkey)
203+
*/
204+
function setHashKey(obj, h) {
205+
if (h) {
206+
obj.$$hashKey = h;
207+
}
208+
else {
209+
delete obj.$$hashKey;
210+
}
211+
}
212+
198213
/**
199214
* @ngdoc function
200215
* @name angular.extend
@@ -208,13 +223,16 @@ function nextUid() {
208223
* @param {...Object} src Source object(s).
209224
*/
210225
function extend(dst) {
226+
var h = dst.$$hashKey;
211227
forEach(arguments, function(obj){
212228
if (obj !== dst) {
213229
forEach(obj, function(value, key){
214230
dst[key] = value;
215231
});
216232
}
217233
});
234+
235+
setHashKey(dst,h);
218236
return dst;
219237
}
220238

@@ -569,12 +587,14 @@ function copy(source, destination){
569587
destination.push(copy(source[i]));
570588
}
571589
} else {
590+
var h = destination.$$hashKey;
572591
forEach(destination, function(value, key){
573592
delete destination[key];
574593
});
575594
for ( var key in source) {
576595
destination[key] = copy(source[key]);
577596
}
597+
setHashKey(destination,h);
578598
}
579599
}
580600
return destination;

test/AngularSpec.js

Lines changed: 57 additions & 0 deletions
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)