Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS - custom filter errors due to undefined arrays and still filters properly?

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 items to the filters? Where else could these filters be getting called if they are only explicitly getting called in my two ng-repeats?

like image 395
Scott Avatar asked Nov 13 '12 15:11

Scott


1 Answers

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.

like image 180
dnc253 Avatar answered Oct 29 '22 20:10

dnc253