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

Commit 1d38867

Browse files
maxmartIgorMinar
authored andcommitted
fix(ngRepeat): expose $first, $middle and $last instead of $position
$position marker doesn't work well in cases when we have just one item in the list because then the item is both the first and last. To solve this properly we need to expose individual $first and $middle and $last flags. BREAKING CHANGE: $position is not exposed in repeater scopes any more To update, search for $position and replace it with one of $first, $middle or $last. Closes #912
1 parent 84542d2 commit 1d38867

File tree

2 files changed

+34
-18
lines changed

2 files changed

+34
-18
lines changed

src/ng/directive/ngRepeat.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@
1212
* Special properties are exposed on the local scope of each template instance, including:
1313
*
1414
* * `$index` – `{number}` – iterator offset of the repeated element (0..length-1)
15-
* * `$position` – `{string}` – position of the repeated element in the iterator. One of:
16-
* * `'first'`,
17-
* * `'middle'`
18-
* * `'last'`
15+
* * `$first` – `{boolean}` – true if the repeated element is first in the iterator.
16+
* * `$middle` – `{boolean}` – true if the repeated element is between the first and last in the iterator.
17+
* * `$last` – `{boolean}` – true if the repeated element is last in the iterator.
1918
*
2019
*
2120
* @element ANY
@@ -145,9 +144,10 @@ var ngRepeatDirective = ngDirective({
145144
childScope[valueIdent] = value;
146145
if (keyIdent) childScope[keyIdent] = key;
147146
childScope.$index = index;
148-
childScope.$position = index === 0 ?
149-
'first' :
150-
(index == collectionLength - 1 ? 'last' : 'middle');
147+
148+
childScope.$first = (index === 0);
149+
childScope.$last = (index === (collectionLength - 1));
150+
childScope.$middle = !(childScope.$first || childScope.$last);
151151

152152
if (!last) {
153153
linker(childScope, function(clone){

test/ng/directive/ngRepeatSpec.js

+27-11
Original file line numberDiff line numberDiff line change
@@ -104,42 +104,58 @@ describe('ngRepeat', function() {
104104
}));
105105

106106

107-
it('should expose iterator position as $position when iterating over arrays',
107+
it('should expose iterator position as $first, $middle and $last when iterating over arrays',
108108
inject(function($rootScope, $compile) {
109109
element = $compile(
110110
'<ul>' +
111-
'<li ng-repeat="item in items" ng-bind="item + \':\' + $position + \'|\'"></li>' +
111+
'<li ng-repeat="item in items">{{item}}:{{$first}}-{{$middle}}-{{$last}}|</li>' +
112112
'</ul>')($rootScope);
113113
$rootScope.items = ['misko', 'shyam', 'doug'];
114114
$rootScope.$digest();
115-
expect(element.text()).toEqual('misko:first|shyam:middle|doug:last|');
115+
expect(element.text()).
116+
toEqual('misko:true-false-false|shyam:false-true-false|doug:false-false-true|');
116117

117118
$rootScope.items.push('frodo');
118119
$rootScope.$digest();
119-
expect(element.text()).toEqual('misko:first|shyam:middle|doug:middle|frodo:last|');
120+
expect(element.text()).
121+
toEqual('misko:true-false-false|' +
122+
'shyam:false-true-false|' +
123+
'doug:false-true-false|' +
124+
'frodo:false-false-true|');
120125

121126
$rootScope.items.pop();
122127
$rootScope.items.pop();
123128
$rootScope.$digest();
124-
expect(element.text()).toEqual('misko:first|shyam:last|');
129+
expect(element.text()).toEqual('misko:true-false-false|shyam:false-false-true|');
130+
131+
$rootScope.items.pop();
132+
$rootScope.$digest();
133+
expect(element.text()).toEqual('misko:true-false-true|');
125134
}));
126135

127136

128-
it('should expose iterator position as $position when iterating over objects',
137+
it('should expose iterator position as $first, $middle and $last when iterating over objects',
129138
inject(function($rootScope, $compile) {
130139
element = $compile(
131140
'<ul>' +
132-
'<li ng-repeat="(key, val) in items" ng-bind="key + \':\' + val + \':\' + $position + \'|\'">' +
133-
'</li>' +
141+
'<li ng-repeat="(key, val) in items">{{key}}:{{val}}:{{$first}}-{{$middle}}-{{$last}}|</li>' +
134142
'</ul>')($rootScope);
135143
$rootScope.items = {'misko':'m', 'shyam':'s', 'doug':'d', 'frodo':'f'};
136144
$rootScope.$digest();
137-
expect(element.text()).toEqual('doug:d:first|frodo:f:middle|misko:m:middle|shyam:s:last|');
145+
expect(element.text()).
146+
toEqual('doug:d:true-false-false|' +
147+
'frodo:f:false-true-false|' +
148+
'misko:m:false-true-false|' +
149+
'shyam:s:false-false-true|');
138150

139151
delete $rootScope.items.doug;
140152
delete $rootScope.items.frodo;
141153
$rootScope.$digest();
142-
expect(element.text()).toEqual('misko:m:first|shyam:s:last|');
154+
expect(element.text()).toEqual('misko:m:true-false-false|shyam:s:false-false-true|');
155+
156+
delete $rootScope.items.shyam;
157+
$rootScope.$digest();
158+
expect(element.text()).toEqual('misko:m:true-false-true|');
143159
}));
144160

145161

@@ -207,7 +223,7 @@ describe('ngRepeat', function() {
207223
beforeEach(inject(function($rootScope, $compile) {
208224
element = $compile(
209225
'<ul>' +
210-
'<li ng-repeat="item in items" ng-bind="key + \':\' + val + \':\' + $position + \'|\'"></li>' +
226+
'<li ng-repeat="item in items">{{key}}:{{val}}|></li>' +
211227
'</ul>')($rootScope);
212228
a = {};
213229
b = {};

0 commit comments

Comments
 (0)