I have a simple <input>
search filter set up for a list of itemnames in AngularJS
.
My list looks like this:
var uniqueLists = { category1: ['item1', 'item2', 'item3' ... 'item180' ], // Real list contains ~180 items category2: ['itemA', 'itemB', 'itemC' ... 'itemZZZ' ], // Real list contains ~1080 items category3: ['otheritem1', 'otheritem2', 'otheritem3' ] // Real list contains 6 items }
I iterate through this list in Angular and print out the results in a <ul>
for each category.
<div ng-repeat="(key,val) in uniqueLists"> <form ng-model="uniqueLists[index][0]"> <input ng-model="searchFilter" type="text" /> <ul> <li ng-repeat="value in val | filter: searchFilter"> <label> <input type="checkbox" ng-model="selectedData[key][value]" /> {{value}} </label> </li> </ul> </form> </div>
For clarity, selectedData looks like this:
var selectedData = {category1: [item1:true], category2: [], category3: []); // if 'item1's checkbox is checked.
This list is working just fine, although the filter
is quite laggy, even on my quite-fast computer. Typing a letter into the input takes 1-2 seconds for the list to update.
I'm aware that this is likely because I'm filtering through around about 1000 items at a time, but I haven't seen any discussion of this elsewhere.
Is there any way to get better performance out of the filter?
Filters can be applied to the result of another filter. This is called "chaining" and uses the following syntax: {{ expression | filter1 | filter2 | ... }} E.g. the markup {{ 1234 | number:2 }} formats the number 1234 with 2 decimal points using the number filter.
The “filter” Filter in AngularJS is used to filter the array and object elements and return the filtered items. In other words, this filter selects a subset (a smaller array containing elements that meet the filter criteria) of an array from the original array.
The ng-repeat values can be filtered according to the ng-model in AngularJS by using the value of the input field as an expression in a filter. We can set the ng-model directive on an input field to filter ng-repeat values. The below illustrations describes the approach for the implementation.
The main problem with the filter approach is that upon each change the dom is manipulated, so it's not the filter that's slow but the consequences. An alternative is to use something like:
ng-show="([item] | filter:searchFilter).length > 0"
on the repeated element.
Lending some code from @OverZealous, you can use the following to compare the behaviour:
Update: With Angular v1.2 came the track by
syntax. Which also helps with such problems. Provided the elements have some unique attribute, one can use:
ng-repeat="item in items | filter:searchFilter track by item.id"
Where item.id
has to be unique across all items. With track by
only those dom-elements will be removed which are no longer the in the final list, others will be remembered. Whereas without track by
the whole list is redrawn everytime. In short: much less dom manipulation = quicker redraw.
Another interesting optimization is to 'not trigger' the model change until a certain time.
Adding this to your search input field: ng-model-options="{debounce: 500}"
This will trigger the filter if the user stop typing during 500ms.
I updated the above fiddle:
http://jsfiddle.net/CXBN4/14/
<input ng-model="searchFilter" type="text" ng-model-options="{debounce: 500}" />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With