I have an array of objects getting assigned to $scope
within a controller, and is being filtered in a series of divs within a partial template:
<div class="entity-list">
<!-- Folders -->
<div class="entity-listing folder" ng-repeat="child in folders | filterName:nameFilter | entityType:filterType | orderBy:orderProp:orderAscDesc">
<!-- Some HTML -->
</div>
<!-- Files -->
<div class="entity-listing document" ng-repeat="child in documents | filterName:nameFilter | entityType:filterType | orderBy:orderProp:orderAscDesc">
<!-- Some HTML -->
</div>
</div>
The filters are displayed in a separate fieldset
element:
<fieldset id="filters">
<legend>Filters</legend>
<label for="filter-name">Name Contains:</label>
<input id="filter-name" ng-model="nameFilter">
<label for="filter-type">Show:</label>
<select id="filter-type" ng-model="filterType">
<!-- some options -->
</select>
<label for="sort-field">Sort By:</label>
<select id="sort-field" ng-model="orderProp">
<!-- some options -->
</select>
<select ng-model="orderAscDesc">
<!-- some options -->
</select>
</fieldset>
I have a module set up with two filters, and pass that module on to my app:
angular.module('widget', ['filters']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/homefolder', {templateUrl: 'widget/partial/entity-list.html', controller: HomeFolderCtrl}).
when('/folder/:uuid', {templateUrl: 'widget/partial/entity-list.html', controller: FolderCtrl}).
otherwise({redirectTo: '/homefolder'});
}]);
angular.module('filters', []).
filter('entityType', function() {
return function(items, type) {
var returnArray = [];
for (var i=0,ii=items.length;i<ii;i++) {
if (type == "both") {
returnArray.push(items[i]);
} else if (items[i].type == type) {
returnArray.push(items[i]);
}
}
return returnArray;
}
}).
filter('filterName', function() {
return function(items, str) {
var returnArray = [];
if (str != '') {
for (var i=0,ii=items.length;i<ii;i++) {
if (items[i].name.indexOf(str) !== -1) {
returnArray.push(items[i]);
}
}
} else {
returnArray = items;
}
return returnArray;
}
});
I'm concerned that this code works, yet when looking at the error console, I get a bunch of errors saying Cannot read property 'length' of undefined
regarding the filterName
and entityType
filters' for loops. If I wrap those filter in an if statement to check if items
is defined (take for example filterName
):
filter('filterName', function() {
return function(items, str) {
var returnArray = [];
if (items) {
if (str != '') {
for (var i=0,ii=items.length;i<ii;i++) {
if (items[i].name.indexOf(str) !== -1) {
returnArray.push(items[i]);
}
}
} else {
returnArray = items;
}
}
return returnArray;
}
});
It gets rid of the error and works as well. Why would AngularJS pass in undefined item
s to the filters? Where else could these filters be getting called if they are only explicitly getting called in my two ng-repeat
s?
Is it safe to assume that the data going through your filters is retrieved from the server asynchronously? When the page first renders, and angular goes through everything, there is no data yet, so it is undefined. Once the data returns, it goes through the digest cycle again, and then there is data this time, so it all works. For this reason, it's a good idea to have the defined check at the beginning of the filter function.
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