I've been looking into trying to write filters but its been quite frustrating.
Here are a couple of resources I was following for writing a 'chunk' filter
https://groups.google.com/forum/#!topic/angular/IEIQok-YkpU https://groups.google.com/forum/#!topic/angular/gEv1-YV-Ojg
I tried it out with some success. but found that there is difference in behaviour between versions
The methods described to produce a $$hashKey does not work in the 1.1.5 version. The first fiddle is fine, whilst the second produces in iteration error, even though the code is exactly the same:
http://jsfiddle.net/nRGTX/38/ - 1.0.3 version
http://jsfiddle.net/nRGTX/39/ - 1.1.5 version
Error: 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["fn: $watchCollectionWatch; newVal: 16; oldVal: 14"],["fn: $watchCollectionWatch; newVal: 18; oldVal: 16"],["fn: $watchCollectionWatch; newVal: 20; oldVal: 18"],["fn: $watchCollectionWatch; newVal: 22; oldVal: 20"],["fn: $watchCollectionWatch; newVal: 24; oldVal: 22"]]
Are there any workarounds/proper way to write this?
Starting with version 1.1.4 the ng-repeat
directive has a watch on the collection that you are iterating to make sure it hasn't changed. The way it works is that it compares every item in the array and if the items aren't equal (in the ===
sense), it thinks the collection has been updated. At least this is my understanding from having looked at the code.
If you were using a filter in the typical sense, where you are just returning a subset of the original items, then the items returned would be the same every time. However, because you're building a whole new structure, the items in the array are different every time (even though their content is the same), so the watch thinks the collection is constantly changing.
The only solution I could come up with was to create a cache of previously returned results. Every time the chunk filter is called, it checks to see if you've previously performed a filter with the same array and chunkSize. If so, it returns the cached result.
To do this, you should update your filter function to look something like this:
return function(array, chunkSize) {
if (!(array instanceof Array)) return array;
if (!chunkSize) return array;
// Create empty cache if it doesn't already exist.
if (typeof myApp.chunkCache === "undefined") {
myApp.chunkCache = [];
}
// Search the cache to see if we filtered the given array before.
for (var i = 0; i < myApp.chunkCache.length; i++) {
var cache = myApp.chunkCache[i];
if (cache.array == array && cache.chunkSize == chunkSize) {
return cache.result;
}
}
// If not, construct the chunked result.
var result = chunkArray(array, chunkSize);
defineHashKeys(result);
// And then add that result to the cache.
var cache = {
array: array,
chunkSize: chunkSize,
result: result
};
myApp.chunkCache.push(cache);
return result;
}
I should also point out that you can probably remove the defineHashKeys
call, because I don't think it serves any purpose in this code. I only left it in because it was in your original code. It didn't seem to make any difference when I removed it.
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