Skip to content

Commit 3295bc9

Browse files
author
user378230
committed
fix(parser) allow track by without filter
Previously the parser always attempted to extract a filter from the repeat expression, regardless of whether it was present or not. This resulted in the track by part of the expression being interpreted as a filter. This commit changes the parser regex to capture the entire object source, including its filters, before matching any track by expression. The filters are then extracted separately from the source as this step is only required when using an object as a source. Fixes angular-ui#1233
1 parent 0ddaad2 commit 3295bc9

File tree

2 files changed

+50
-14
lines changed

2 files changed

+50
-14
lines changed

src/uisRepeatParserService.js

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,48 @@ uis.service('uisRepeatParser', ['uiSelectMinErr','$parse', function(uiSelectMinE
2222

2323

2424
var match;
25-
var isObjectCollection = /\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)/.test(expression);
25+
//var isObjectCollection = /\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)/.test(expression);
2626
// If an array is used as collection
2727

2828
// if (isObjectCollection){
29-
//00000000000000000000000000000111111111000000000000000222222222222220033333333333333333333330000444444444444444444000000000000000556666660000077777777777755000000000000000000000088888880000000
30-
match = expression.match(/^\s*(?:([\s\S]+?)\s+as\s+)?(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(([\w\.]+)?\s*(|\s*[\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
29+
// 000000000000000000000000000000111111111000000000000000222222222222220033333333333333333333330000444444444444444444000000000000000055555555555000000000000000000000066666666600000000
30+
match = expression.match(/^\s*(?:([\s\S]+?)\s+as\s+)?(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(\s*[\s\S]+?)?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
3131

3232
// 1 Alias
3333
// 2 Item
3434
// 3 Key on (key,value)
3535
// 4 Value on (key,value)
36-
// 5 Collection expresion (only used when using an array collection)
37-
// 6 Object that will be converted to Array when using (key,value) syntax
38-
// 7 Filters that will be applied to #6 when using (key,value) syntax
39-
// 8 Track by
36+
// 5 Source expression (including filters)
37+
// 6 Track by
4038

4139
if (!match) {
4240
throw uiSelectMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
4341
expression);
4442
}
45-
if (!match[6] && isObjectCollection) {
46-
throw uiSelectMinErr('iexp', "Expected expression in form of '_item_ as (_key_, _item_) in _ObjCollection_ [ track by _id_]' but got '{0}'.",
47-
expression);
43+
44+
var source = match[5],
45+
filters = '';
46+
47+
// When using (key,value) ui-select requires filters to be extracted, since the object
48+
// is converted to an array for $select.items
49+
// (in which case the filters need to be reapplied)
50+
if (match[3]) {
51+
// Remove any enclosing parenthesis
52+
source = match[5].replace(/(^\()|(\)$)/g, '');
53+
// match all after | but not after ||
54+
var filterMatch = match[5].match(/^\s*(?:[\s\S]+?)(?:[^\|]|\|\|)+([\s\S]*)\s*$/);
55+
if(filterMatch && filterMatch[1].trim()) {
56+
filters = filterMatch[1];
57+
source = source.replace(filters, '');
58+
}
4859
}
4960

5061
return {
5162
itemName: match[4] || match[2], // (lhs) Left-hand side,
5263
keyName: match[3], //for (key, value) syntax
53-
source: $parse(!match[3] ? match[5] : match[6]),
54-
sourceName: match[6],
55-
filters: match[7],
56-
trackByExp: match[8],
64+
source: $parse(source),
65+
filters: filters,
66+
trackByExp: match[6],
5767
modelMapper: $parse(match[1] || match[4] || match[2]),
5868
repeatExpression: function (grouped) {
5969
var expression = this.itemName + ' in ' + (grouped ? '$group.items' : '$select.items');

test/select.spec.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,32 @@ describe('ui-select tests', function() {
260260

261261
});
262262

263+
it('should parse simple property binding repeat syntax with a basic filter', function () {
264+
265+
var locals = {};
266+
locals.people = [{ name: 'Wladimir' }, { name: 'Samantha' }];
267+
locals.person = locals.people[1];
268+
269+
var parserResult = uisRepeatParser.parse('person.name as person in people | filter: { name: \'Samantha\' }');
270+
expect(parserResult.itemName).toBe('person');
271+
expect(parserResult.modelMapper(locals)).toBe(locals.person.name);
272+
expect(parserResult.source(locals)).toEqual([locals.person]);
273+
274+
});
275+
276+
it('should parse simple property binding repeat syntax with track by', function () {
277+
278+
var locals = {};
279+
locals.people = [{ name: 'Wladimir' }, { name: 'Samantha' }];
280+
locals.person = locals.people[0];
281+
282+
var parserResult = uisRepeatParser.parse('person.name as person in people track by person.name');
283+
expect(parserResult.itemName).toBe('person');
284+
expect(parserResult.modelMapper(locals)).toBe(locals.person.name);
285+
expect(parserResult.source(locals)).toBe(locals.people);
286+
287+
});
288+
263289
it('should parse (key, value) repeat syntax', function() {
264290

265291
var locals = {};

0 commit comments

Comments
 (0)