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

feat(ngRepeat): provide support for aliasing filtered repeater results as a scope member #8046

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions src/ng/directive/ngRepeat.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@
* For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
* will be associated by item identity in the array.
*
* * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
* intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
* when a filter is active on the repeater, but the filtered result set is empty.
*
* For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
* the items have been processed through the filter.
*
* For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
* `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
* with the corresponding item in the array by identity. Moving the same object in array would move the DOM
Expand Down Expand Up @@ -132,9 +139,12 @@
I have {{friends.length}} friends. They are:
<input type="search" ng-model="q" placeholder="filter friends..." />
<ul class="example-animate-container">
<li class="animate-repeat" ng-repeat="friend in friends | filter:q">
<li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
[{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
</li>
<li class="animate-repeat" ng-if="results.length == 0">
<strong>No results found...</strong>
</li>
</ul>
</div>
</file>
Expand Down Expand Up @@ -209,8 +219,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
$$tlb: true,
link: function($scope, $element, $attr, ctrl, $transclude){
var expression = $attr.ngRepeat;
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
trackByExp, trackByExpGetter, aliasAs, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
lhs, rhs, valueIdentifier, keyIdentifier,
hashFnLocals = {$id: hashKey};

Expand All @@ -221,7 +231,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {

lhs = match[1];
rhs = match[2];
trackByExp = match[3];
aliasAs = match[3];
trackByExp = match[4];

if (trackByExp) {
trackByExpGetter = $parse(trackByExp);
Expand Down Expand Up @@ -273,6 +284,10 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
nextBlockOrder = [],
elementsToRemove;

if (aliasAs) {
$scope[aliasAs] = collection;
}

var updateScope = function(scope, index) {
scope[valueIdentifier] = value;
if (keyIdentifier) scope[keyIdentifier] = key;
Expand Down
52 changes: 52 additions & 0 deletions test/ng/directive/ngRepeatSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,58 @@ describe('ngRepeat', function() {
});
});

describe('alias as', function() {
it('should assigned the filtered to the target scope property if an alias is provided', function() {
element = $compile(
'<div ng-repeat="item in items | filter:x as results track by $index">{{item.name}}/</div>')(scope);

scope.items = [
{ name : 'red' },
{ name : 'blue' },
{ name : 'green' },
{ name : 'black' },
{ name : 'orange' },
{ name : 'blonde' }
];

expect(scope.results).toBeUndefined();
scope.$digest();

scope.x = 'bl';
scope.$digest();

expect(scope.results).toEqual([
{ name : 'blue' },
{ name : 'black' },
{ name : 'blonde' }
]);

scope.items = [];
scope.$digest();

expect(scope.results).toEqual([]);
});

it('should render a message when the repeat list is empty', function() {
element = $compile(
'<div>' +
' <div ng-repeat="item in items | filter:x as results">{{item}}</div>' +
' <div ng-if="results.length == 0">' +
' No results found...' +
' </div>' +
'</div>')(scope);

scope.items = [1,2,3,4,5,6];
scope.$digest();
expect(trim(element.text())).toEqual('123456');

scope.x = '0';
scope.$digest();

expect(trim(element.text())).toEqual('No results found...');
});
});


it('should allow expressions over multiple lines', function() {
element = $compile(
Expand Down