简体   繁体   中英

AngularJS - filter for undefined properties in ng-repeat?

For my AngularJS project (v1.2.3), I have a list of routes and am trying to build a navigation bar from the object. What I want to do is display any object with an undefined isRight property in one style, and where the property is defined in another.

In one ng-repeat I would like to filter those objects with an undefined isRight property. How can I accomplish this inside the ng-repeat attribute, without having to resort to creating a custom filter function?

$scope.nav = [
    { path: '/', title: 'Home' },
    { path: '/blog', title: 'Blog' },
    { path: '/about', title: 'About' },
    { path: '/login', title: 'Login', isRight: true }
];

I realize I could just add the attribute isRight: false to each object, or have separate nav objects for right and left side links, and other such simple workarounds, but I am curious if there is a way to accomplish this with the current structure, using something along the lines of:

<li ng-repeat="link in nav | filter:{isRight:undefined}">

This is more a curiosity than a need, but I appreciate any suggestions.

You can negate a filter expression. So instead of dealing with undefined you can just filter out anything where isRight is not ( ! ) true. Like this:

<li ng-repeat="link in nav | filter:{isRight:'!true'} ">

And for the opposite you can, of course, do:

<li ng-repeat="link in nav | filter:{isRight:'true'} ">

demo fiddle

You can also use <li ng-repeat="link in nav | filter:{isRight:'!'}">

see also How to display placeholders in AngularJS for undefined expression values?

 var app = angular.module('myApp', []) app.controller('mainCtrl',['$scope' , function($scope) { $scope.nav = [ { path: '/', title: 'Home' }, { path: '/blog', title: 'Blog' }, { path: '/about', title: 'About' }, { path: '/login', title: 'Login', isRight: true } ]; }]) 
 <div ng-app="myApp" ng-controller="mainCtrl"> <h3>!isRight</h3> <ul> <li ng-repeat="link in nav | filter:{isRight:'!'}">{{link.title}}</li> </ul> <h3>isRight</h3> <ul> <li ng-repeat="link in nav | filter:{isRight:'!!'}">{{link.title}}</li> </ul> </div> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 

Edit

I just reread the question, and this is not the answer you are looking for. I will leave it here for documentation purposes, but I do not think there is a way to get the functionality you desire without either building a custom filter or using a custom filter function.

To expand on why looking for undefined will not work with the default filter we take a look at this code from the AngularJS filter implementation.

switch (typeof expression) {
  ...
  case "object":
    // jshint +W086
    for (var key in expression) {
      (function(path) {
        if (typeof expression[path] == 'undefined') return;
        predicates.push(function(value) {
          return search(path == '$' ? value : getter(value, path), expression[path]);
        });
      })(key);
    }
    break;
  ...
}

If a value for the filter object's property is undefined , no predicate function is added to the predicates array. In your case you are setting the value of the isRight property to undefined (your filter expression is {isRight:undefined} ).

Original Answer

You can always use a predicate function to create arbitrary filters ( documentation ).

A predicate function can be used to write arbitrary filters. The function is called for each element of array. The final result is an array of those elements that the predicate returned true for.

In your controller create a method to pick the items you want

$scope.isRightUndefined = function(item) {
  return item.isRight === undefined;
}

and change your repeat to be

<li ng-repeat="link in nav | filter:isRightUndefined">
module.filter('notNullOrUndefined', [function () {
    return function (items, property) {
        var arrayToReturn = [];
        for (var i = 0; i < items.length; i++) {
            var test = property !== undefined ? items[i][property] : items[i];
            if (test !== undefined && test !== null) {
                arrayToReturn.push(items[i]);
            }
        }
        return arrayToReturn;
    };
}]);

Usage:

<div class="col-md-12" ng-repeat="style in styles | notNullOrUndefined:'background'">
    <span class="ed-item">{{style.name}} Background</span>
</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM