AngularJS - How to structure a custom filter with ng-repeat to return items conditionally
Asked Answered
H

3

59

I have an ng-repeat that prints list items. I want to write a custom filter so that the list item will print, only if a condition is true.

I seem to have the structure wrong as it seems the variables are not getting passed through to the filter.

index.php

<div ng-show="userDetails.username" class="nav">
    <p>Menu</p>
    <li ng-repeat="menuItem in menu | matchAccessLevel:$rootScope.userDetails.accessLevel:menuItem.minAccess | orderBy:'position' ">
        <a ng-href="/angular-app/app/{{menuItem.id}}">{{menuItem.name}}</a>
    </li>
</div>

app.js

userApp.filter('matchAccessLevel', function() {
    return function( item, userAccessLevel, minAccessLevel ) {
        if( userAccessLevel >= minAccessLevel ) {
            return item;
        }
    }
});
Hypoglycemia answered 4/3, 2013 at 6:58 Comment(0)
M
125

Filters don't work on individual items in the array, they transform the entire array into another array.

userApp.filter('matchAccessLevel', function() {
  return function( items, userAccessLevel) {
    var filtered = [];
    angular.forEach(items, function(item) {
      if(userAccessLevel >= item.minAccess) {
        filtered.push(item);
      }
    });
    return filtered;
  };
});

See this plnkr

**always inspect the arguments to a function. It's not always obvious what the values are.*

see filters guide

Most answered 4/3, 2013 at 8:18 Comment(10)
Many thanks for the explanation. It seems I understood how filters work incorrectly. That's made it much clearer.Hypoglycemia
what i got not right was the argument thing. is there any documentation about how filter provide arguments/parameters ?Balls
always inspect the arguments to a function. It's not always obvious what the values areChally
Is it possible we make accessLevel dynamic i.e. depending on a text box value? instead of getting it from scope?Paleopsychology
@ons-jjss you can two way bind the scope value to ng-model on the desired inputMost
Ok. I tried to set this from a text box scope variable but filter was not showing correct results when entering different value in the text box.Paleopsychology
@ons-jjss plnkr.co/edit/nuSlCRB6Y7QbuLC67uzW?p=preview remember that you might be overwriting primitive values in child scopes see this https://mcmap.net/q/278301/-why-don-39-t-the-angularjs-docs-use-a-dot-in-the-model-directiveMost
Ok. It is fixed now. Thanks.Paleopsychology
If I add track by in the ng-repeat. It throw error with this solution. Why?Salep
@HughHou please ask a new question as this is not related to this questionMost
C
6

You can use Array.filter for a more concise solution:

app.filter('matchAccessLevel', function() {
    return function( items, userAccessLevel ) {
      return items.filter(function(element){
        return userAccessLevel >= element.minAccess;
      });
    }
});

Check on Plunker

Contralto answered 15/3, 2016 at 21:27 Comment(0)
P
-1

For CoffeeScript lovers:

userApp.filter 'matchAccessLevel', ->
  (items, userAccessLevel) ->
    item for item in items when userAccessLevel >= item.minAccess
Paryavi answered 1/10, 2015 at 13:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.