132

If I have an array of objects, and I want to bind the Angular model to a property of one of the elements based on a filter, how do I do that? I can explain better with a concrete example:

HTML:

<!DOCTYPE html>
<html ng-app>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
        <meta charset=utf-8 />
        <title>JS Bin</title>
    </head>
    <body ng-controller="MyCtrl">
        <input ng-model="results.year">
        <input ng-model="results.subjects.title | filter:{grade:'C'}">
    </body>
</html>

Controller:

function MyCtrl($scope) {
  $scope.results = {
    year:2013,
    subjects:[
      {title:'English',grade:'A'},
      {title:'Maths',grade:'A'},
      {title:'Science',grade:'B'},
      {title:'Geography',grade:'C'}
    ]
  };
}

JSBin: http://jsbin.com/adisax/1/edit

I want to filter the second input to the subject with a grade 'C', but I don't want to bind the model to the grade; I want to bind it to the title of the subject that has grade 'C'.

Is this possible, and if so, how is it done?

Lukasz Koziara
  • 4,274
  • 5
  • 32
  • 43
Bernhard Hofmann
  • 10,321
  • 12
  • 59
  • 78

8 Answers8

164

You can use the "filter" filter in your controller to get all the "C" grades. Getting the first element of the result array will give you the title of the subject that has grade "C".

$scope.gradeC = $filter('filter')($scope.results.subjects, {grade: 'C'})[0];

http://jsbin.com/ewitun/1/edit

The same with plain ES6:

$scope.gradeC = $scope.results.subjects.filter((subject) => subject.grade === 'C')[0]
Oliver
  • 4,471
  • 2
  • 21
  • 18
  • i am sorry i am not following that second filter ('filter') can you explain that one a little more? – Winnemucca Sep 23 '16 at 05:19
  • 1
    @stevek That's the name of the filter. The filter() method gives you the filter. It's just it that filter is called filter because it filters an array. It would look like this with the currency filter: $filter('currency')(amount, symbol, fractionSize) Check the docs here: https://docs.angularjs.org/api/ng/filter – Oliver Oct 12 '16 at 15:52
137
<div ng-repeat="subject in results.subjects | filter:{grade:'C'}">
    <input ng-model="subject.title" />
</div>
dadoonet
  • 14,109
  • 3
  • 42
  • 49
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • 1
    I see where you're going with that, but I really didn't want a repeater. The property I'll actually be filtering by is an identity column, so it's unique. But I see that this would be the correct way to solve the generic problem. – Bernhard Hofmann Jul 30 '13 at 12:08
  • 1
    this is a tutorial for italian people :) http://dev.stasbranger.com/post/77190983049/lista-di-filtri-in-angularjs – Silvio Troia Mar 07 '14 at 16:28
  • 11
    this was very helpful, and for inverse (everything other than C), this would work: `filter:{grade:'!'+'C'}` – pulkitsinghal May 29 '15 at 00:50
  • 2
    Can you do the same with a `grade array`? In my case I build my grade array from a treeview and want filter the result for those in the array. – Juan Carlos Oropeza Mar 17 '16 at 19:59
63

Here is a modified JSBin with a working sample:

http://jsbin.com/sezamuja/1/edit

Here is what I did with filters in the input:

<input ng-model="(results.subjects | filter:{grade:'C'})[0].title">
luke-at-work
  • 761
  • 5
  • 5
17

please note, if you use $filter like this:

$scope.failedSubjects = $filter('filter')($scope.results.subjects, {'grade':'C'});

and you happened to have another grade for, Oh I don't know, CC or AC or C+ or CCC it pulls them in to. you need to append a requirement for an exact match:

$scope.failedSubjects = $filter('filter')($scope.results.subjects, {'grade':'C'}, true);

This really killed me when I was pulling in some commission details like this:

var obj = this.$filter('filter')(this.CommissionTypes, { commission_type_id: 6}))[0];

only get called in for a bug because it was pulling in the commission ID 56 rather than 6.

Adding the true forces an exact match.

var obj = this.$filter('filter')(this.CommissionTypes, { commission_type_id: 6}, true))[0];

Yet still, I prefer this (I use typescript, hence the "Let" and =>):

let obj = this.$filter('filter')(this.CommissionTypes, (item) =>{ 
             return item.commission_type_id === 6;
           })[0];

I do that because, at some point down the road, I might want to get some more info from that filtered data, etc... having the function right in there kind of leaves the hood open.

peterh
  • 11,875
  • 18
  • 85
  • 108
Daniel Morris
  • 329
  • 3
  • 4
13

if you wanted to create a separate list of results in the controller you could apply a filter

function MyCtrl($scope, filterFilter) {
  $scope.results = {
    year:2013,
    subjects:[
      {title:'English',grade:'A'},
      {title:'Maths',grade:'A'},
      {title:'Science',grade:'B'},
      {title:'Geography',grade:'C'}
    ]
  };
  //create a filtered array of results 
  //with grade 'C' or subjects that have been failed
  $scope.failedSubjects = filterFilter($scope.results.subjects, {'grade':'C'});
}

Then you can reference failedSubjects the same way you would reference the results object

you can read more about it here https://docs.angularjs.org/guide/filter

since this answer angular have updated the documentation they now recommend calling the filter

// update 
// eg: $filter('filter')(array, expression, comparator, anyPropertyKey);
// becomes
$scope.failedSubjects = $filter('filter')($scope.results.subjects, {'grade':'C'});
Kieran
  • 17,572
  • 7
  • 45
  • 53
  • what is filterFilter ? is it any service or directive? where is the code for filterFilter? – Mou Apr 18 '16 at 18:27
  • it is an angular service. Have a look at the first example in the link above. (in the scripts.js file) – Kieran Apr 20 '16 at 11:53
  • although they have changed the documentation filterFilter still works.. – Kieran Oct 18 '16 at 05:39
6

If you are using ES6 you can:

var sample = [1, 2, 3]

var result = sample.filter(elem => elem !== 2)

/* output */
[1, 3]

Also take notice filter does not update the existing array it will return a new filtered array every time.

Diego Venâncio
  • 5,698
  • 2
  • 49
  • 68
4

You can also use functions with $filter('filter'):

var foo = $filter('filter')($scope.results.subjects, function (item) {
  return item.grade !== 'A';
});
Nelu
  • 16,644
  • 10
  • 80
  • 88
0

Applying same filter in HTML with multiple columns, just example:

 variable = (array | filter : {Lookup1Id : subject.Lookup1Id, Lookup2Id : subject.Lookup2Id} : true)
Amay Kulkarni
  • 828
  • 13
  • 16