Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don't AngularJS Filters work when inside an ng-if?

I have a simple AngularJS page with different sections that I show & hide when links are clicked. One of these areas has a repeated list that can be filtered.

When the section containing the list is shows/hidden with ng-show or ng-hide it behaves normally. When ng-if is used, the list cannot be filtered.

Demos

  • This version does not work due to the use of ng-if
  • This version does work due to the use of ng-show

Sample HTML

<nav>
    <a href="javascript:{}" ng-click="area='one';">Area 1</a>
    <a href="javascript:{}" ng-click="area='two';">Area 2</a>
</nav>

<div ng-if="area==='one'">
    <h3>Area 1!</h3>
    <input type="text" placeholder="filter list..." ng-model="filterText" />
    <ul>
       <li ng-repeat="item in list | filter: listFilter">
           {{item.id}} - {{item.name}}
       </li>
    </ul>
</div>

<div ng-if="area==='two'">
    <h3>Area 2!</h3>
    <p>Stuff here...</p>
</div>

Sample Angular

$scope.area="one";
$scope.filterText="";

$scope.list = [
    {id:1, name:"banana"},
    {id:2, name:"apple"},
    {id:3, name:"orange"},
    {id:4, name:"pear"},
    {id:5, name:"apricot"}
];

$scope.listFilter = function(item){
    var term = $scope.filterText.trim().toLowerCase();
    return item.id.toString().indexOf(term) > -1 || item.name.indexOf(term) > -1;
};
like image 836
FiniteLooper Avatar asked Jan 22 '15 19:01

FiniteLooper


1 Answers

I don't hold a Masters degree on the subject of Prototypal Inheritance myself but I'll try my best to explain it shortly (there's a ton of resources on the subject);

  • Number
  • String
  • Boolean
  • null
  • undefined
  • Symbol (as of ES6)

are considered primitives (MDN).

Now - when you 'inherit' a primitive from your parent scope, what is actually happening is that the child scope 'mirrors' or 'shadows' the given primitive value. As such, you can think of it as a copy of the above.

That is roughly the nature of primitives in the context of Prototypal Inheritance.

This can clearly be observed in a modified version of your broken fiddle.

Try playing with the two inputs and you can see that there is a connection of the two values when you only touch the outside input (i.e. the child value 'shadows' the parent value). But once you touch the inside input, the values disconnect from one another.


The recommended way to get around this is to use a reference to a property on your model (I say model, but really it's just a JS object) that is defined further up the prototype chain;

$parentScope.obj = { filterText: '' };

ng-model="obj.filterText"

Now you should be good to go with ngIf, ngSwitch, ngRepeat to name a few of the angular supplied directives that create a new scope.

Resources on the subject

  • understanding scopes @ angular
  • presentation by misko on the subject
  • stackoverflow answer by Mark Rajcok
  • the dot @egghead.io
  • google search 'dot ng model'
like image 75
Kasper Lewau Avatar answered Oct 12 '22 23:10

Kasper Lewau