Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3df7b8e

Browse files
committed
fix(ng:repeat): use transclusion
1 parent 7bd69d0 commit 3df7b8e

File tree

3 files changed

+128
-132
lines changed

3 files changed

+128
-132
lines changed

src/widgets.js

Lines changed: 109 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -310,131 +310,127 @@ var htmlAnchorDirective = valueFn({
310310
</doc:scenario>
311311
</doc:example>
312312
*/
313-
var ngRepeatDirective = ['$compile', function($compile) {
314-
return {
315-
priority: 1000,
316-
terminal: true,
317-
compile: function(element, attr) {
313+
var ngRepeatDirective = valueFn({
314+
transclude: 'element',
315+
priority: 1000,
316+
terminal: true,
317+
compile: function(element, attr, linker) {
318+
return function(scope, iterStartElement, attr){
318319
var expression = attr.ngRepeat;
319-
attr.$set(attr.$attr.ngRepeat);
320-
element.replaceWith(jqLite('<!-- ng:repeat: ' + expression + ' -->'));
321-
var linker = $compile(element);
322-
return function(scope, iterStartElement, attr){
323-
var match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
324-
lhs, rhs, valueIdent, keyIdent;
325-
if (! match) {
326-
throw Error("Expected ng:repeat in form of '_item_ in _collection_' but got '" +
327-
expression + "'.");
328-
}
329-
lhs = match[1];
330-
rhs = match[2];
331-
match = lhs.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
332-
if (!match) {
333-
throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" +
334-
keyValue + "'.");
335-
}
336-
valueIdent = match[3] || match[1];
337-
keyIdent = match[2];
338-
339-
// Store a list of elements from previous run. This is a hash where key is the item from the
340-
// iterator, and the value is an array of objects with following properties.
341-
// - scope: bound scope
342-
// - element: previous element.
343-
// - index: position
344-
// We need an array of these objects since the same object can be returned from the iterator.
345-
// We expect this to be a rare case.
346-
var lastOrder = new HashQueueMap();
347-
scope.$watch(function(scope){
348-
var index, length,
349-
collection = scope.$eval(rhs),
350-
collectionLength = size(collection, true),
351-
childScope,
352-
// Same as lastOrder but it has the current state. It will become the
353-
// lastOrder on the next iteration.
354-
nextOrder = new HashQueueMap(),
355-
key, value, // key/value of iteration
356-
array, last, // last object information {scope, element, index}
357-
cursor = iterStartElement; // current position of the node
358-
359-
if (!isArray(collection)) {
360-
// if object, extract keys, sort them and use to determine order of iteration over obj props
361-
array = [];
362-
for(key in collection) {
363-
if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
364-
array.push(key);
365-
}
320+
var match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/),
321+
lhs, rhs, valueIdent, keyIdent;
322+
if (! match) {
323+
throw Error("Expected ng:repeat in form of '_item_ in _collection_' but got '" +
324+
expression + "'.");
325+
}
326+
lhs = match[1];
327+
rhs = match[2];
328+
match = lhs.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/);
329+
if (!match) {
330+
throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '" +
331+
keyValue + "'.");
332+
}
333+
valueIdent = match[3] || match[1];
334+
keyIdent = match[2];
335+
336+
// Store a list of elements from previous run. This is a hash where key is the item from the
337+
// iterator, and the value is an array of objects with following properties.
338+
// - scope: bound scope
339+
// - element: previous element.
340+
// - index: position
341+
// We need an array of these objects since the same object can be returned from the iterator.
342+
// We expect this to be a rare case.
343+
var lastOrder = new HashQueueMap();
344+
scope.$watch(function(scope){
345+
var index, length,
346+
collection = scope.$eval(rhs),
347+
collectionLength = size(collection, true),
348+
childScope,
349+
// Same as lastOrder but it has the current state. It will become the
350+
// lastOrder on the next iteration.
351+
nextOrder = new HashQueueMap(),
352+
key, value, // key/value of iteration
353+
array, last, // last object information {scope, element, index}
354+
cursor = iterStartElement; // current position of the node
355+
356+
if (!isArray(collection)) {
357+
// if object, extract keys, sort them and use to determine order of iteration over obj props
358+
array = [];
359+
for(key in collection) {
360+
if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
361+
array.push(key);
366362
}
367-
array.sort();
368-
} else {
369-
array = collection || [];
370363
}
364+
array.sort();
365+
} else {
366+
array = collection || [];
367+
}
371368

372-
// we are not using forEach for perf reasons (trying to avoid #call)
373-
for (index = 0, length = array.length; index < length; index++) {
374-
key = (collection === array) ? index : array[index];
375-
value = collection[key];
376-
last = lastOrder.shift(value);
377-
if (last) {
378-
// if we have already seen this object, then we need to reuse the
379-
// associated scope/element
380-
childScope = last.scope;
381-
nextOrder.push(value, last);
382-
383-
if (index === last.index) {
384-
// do nothing
385-
cursor = last.element;
386-
} else {
387-
// existing item which got moved
388-
last.index = index;
389-
// This may be a noop, if the element is next, but I don't know of a good way to
390-
// figure this out, since it would require extra DOM access, so let's just hope that
391-
// the browsers realizes that it is noop, and treats it as such.
392-
cursor.after(last.element);
393-
cursor = last.element;
394-
}
369+
// we are not using forEach for perf reasons (trying to avoid #call)
370+
for (index = 0, length = array.length; index < length; index++) {
371+
key = (collection === array) ? index : array[index];
372+
value = collection[key];
373+
last = lastOrder.shift(value);
374+
if (last) {
375+
// if we have already seen this object, then we need to reuse the
376+
// associated scope/element
377+
childScope = last.scope;
378+
nextOrder.push(value, last);
379+
380+
if (index === last.index) {
381+
// do nothing
382+
cursor = last.element;
395383
} else {
396-
// new item which we don't know about
397-
childScope = scope.$new();
384+
// existing item which got moved
385+
last.index = index;
386+
// This may be a noop, if the element is next, but I don't know of a good way to
387+
// figure this out, since it would require extra DOM access, so let's just hope that
388+
// the browsers realizes that it is noop, and treats it as such.
389+
cursor.after(last.element);
390+
cursor = last.element;
398391
}
392+
} else {
393+
// new item which we don't know about
394+
childScope = scope.$new();
395+
}
399396

400-
childScope[valueIdent] = value;
401-
if (keyIdent) childScope[keyIdent] = key;
402-
childScope.$index = index;
403-
childScope.$position = index === 0 ?
404-
'first' :
405-
(index == collectionLength - 1 ? 'last' : 'middle');
406-
407-
if (!last) {
408-
linker(childScope, function(clone){
409-
cursor.after(clone);
410-
last = {
411-
scope: childScope,
412-
element: (cursor = clone),
413-
index: index
414-
};
415-
nextOrder.push(value, last);
416-
});
417-
}
397+
childScope[valueIdent] = value;
398+
if (keyIdent) childScope[keyIdent] = key;
399+
childScope.$index = index;
400+
childScope.$position = index === 0 ?
401+
'first' :
402+
(index == collectionLength - 1 ? 'last' : 'middle');
403+
404+
if (!last) {
405+
linker(childScope, function(clone){
406+
cursor.after(clone);
407+
last = {
408+
scope: childScope,
409+
element: (cursor = clone),
410+
index: index
411+
};
412+
nextOrder.push(value, last);
413+
});
418414
}
415+
}
419416

420-
//shrink children
421-
for (key in lastOrder) {
422-
if (lastOrder.hasOwnProperty(key)) {
423-
array = lastOrder[key];
424-
while(array.length) {
425-
value = array.pop();
426-
value.element.remove();
427-
value.scope.$destroy();
428-
}
417+
//shrink children
418+
for (key in lastOrder) {
419+
if (lastOrder.hasOwnProperty(key)) {
420+
array = lastOrder[key];
421+
while(array.length) {
422+
value = array.pop();
423+
value.element.remove();
424+
value.scope.$destroy();
429425
}
430426
}
427+
}
431428

432-
lastOrder = nextOrder;
433-
});
434-
};
435-
}
436-
};
437-
}];
429+
lastOrder = nextOrder;
430+
});
431+
};
432+
}
433+
});
438434

439435

440436
/**

test/BinderSpec.js

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -109,27 +109,27 @@ describe('Binder', function() {
109109
expect(sortedHtml(form)).toBe(
110110
'<ul>' +
111111
'<#comment></#comment>' +
112-
'<li ng:bind="item.a">A</li>' +
113-
'<li ng:bind="item.a">B</li>' +
112+
'<li ng:bind="item.a" ng:repeat="item in model.items">A</li>' +
113+
'<li ng:bind="item.a" ng:repeat="item in model.items">B</li>' +
114114
'</ul>');
115115

116116
items.unshift({a: 'C'});
117117
$rootScope.$apply();
118118
expect(sortedHtml(form)).toBe(
119119
'<ul>' +
120120
'<#comment></#comment>' +
121-
'<li ng:bind="item.a">C</li>' +
122-
'<li ng:bind="item.a">A</li>' +
123-
'<li ng:bind="item.a">B</li>' +
121+
'<li ng:bind="item.a" ng:repeat="item in model.items">C</li>' +
122+
'<li ng:bind="item.a" ng:repeat="item in model.items">A</li>' +
123+
'<li ng:bind="item.a" ng:repeat="item in model.items">B</li>' +
124124
'</ul>');
125125

126126
items.shift();
127127
$rootScope.$apply();
128128
expect(sortedHtml(form)).toBe(
129129
'<ul>' +
130130
'<#comment></#comment>' +
131-
'<li ng:bind="item.a">A</li>' +
132-
'<li ng:bind="item.a">B</li>' +
131+
'<li ng:bind="item.a" ng:repeat="item in model.items">A</li>' +
132+
'<li ng:bind="item.a" ng:repeat="item in model.items">B</li>' +
133133
'</ul>');
134134

135135
items.shift();
@@ -147,7 +147,7 @@ describe('Binder', function() {
147147
expect(sortedHtml(element)).toBe(
148148
'<ul>' +
149149
'<#comment></#comment>' +
150-
'<li><span ng:bind="item.a">A</span></li>' +
150+
'<li ng:repeat="item in model.items"><span ng:bind="item.a">A</span></li>' +
151151
'</ul>');
152152
}));
153153

@@ -249,15 +249,15 @@ describe('Binder', function() {
249249
expect(sortedHtml(element)).toBe(
250250
'<div>'+
251251
'<#comment></#comment>'+
252-
'<div name="a">'+
252+
'<div name="a" ng:repeat="m in model">'+
253253
'<#comment></#comment>'+
254-
'<ul name="a1"></ul>'+
255-
'<ul name="a2"></ul>'+
254+
'<ul name="a1" ng:repeat="i in m.item"></ul>'+
255+
'<ul name="a2" ng:repeat="i in m.item"></ul>'+
256256
'</div>'+
257-
'<div name="b">'+
257+
'<div name="b" ng:repeat="m in model">'+
258258
'<#comment></#comment>'+
259-
'<ul name="b1"></ul>'+
260-
'<ul name="b2"></ul>'+
259+
'<ul name="b1" ng:repeat="i in m.item"></ul>'+
260+
'<ul name="b2" ng:repeat="i in m.item"></ul>'+
261261
'</div>' +
262262
'</div>');
263263
}));
@@ -341,8 +341,8 @@ describe('Binder', function() {
341341
expect(d2.hasClass('e')).toBeTruthy();
342342
expect(sortedHtml(element)).toBe(
343343
'<div><#comment></#comment>' +
344-
'<div class="o" ng:class-even="\'e\'" ng:class-odd="\'o\'"></div>' +
345-
'<div class="e" ng:class-even="\'e\'" ng:class-odd="\'o\'"></div></div>');
344+
'<div class="o" ng:class-even="\'e\'" ng:class-odd="\'o\'" ng:repeat="i in [0,1]"></div>' +
345+
'<div class="e" ng:class-even="\'e\'" ng:class-odd="\'o\'" ng:repeat="i in [0,1]"></div></div>');
346346
}));
347347

348348
it('BindStyle', inject(function($rootScope, $compile) {
@@ -469,8 +469,8 @@ describe('Binder', function() {
469469
expect(sortedHtml(element)).toBe(
470470
'<ul>' +
471471
'<#comment></#comment>' +
472-
'<li ng:bind=\"k + v\">a0</li>' +
473-
'<li ng:bind=\"k + v\">b1</li>' +
472+
'<li ng:bind=\"k + v\" ng:repeat="(k,v) in {a:0,b:1}">a0</li>' +
473+
'<li ng:bind=\"k + v\" ng:repeat="(k,v) in {a:0,b:1}">b1</li>' +
474474
'</ul>');
475475
}));
476476

test/widgetsSpec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ describe('widget', function() {
332332
});
333333

334334

335-
describe('@ng:repeat', function() {
335+
describe('ng:repeat', function() {
336336
it('should ng:repeat over array', inject(function($rootScope, $compile) {
337337
element = $compile(
338338
'<ul>' +

0 commit comments

Comments
 (0)