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?

8 Answers 8

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]
Sign up to request clarification or add additional context in comments.

2 Comments

i am sorry i am not following that second filter ('filter') can you explain that one a little more?
@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: docs.angularjs.org/api/ng/filter
138
<div ng-repeat="subject in results.subjects | filter:{grade:'C'}">
    <input ng-model="subject.title" />
</div>

4 Comments

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.
this is a tutorial for italian people :) dev.stasbranger.com/post/77190983049/…
this was very helpful, and for inverse (everything other than C), this would work: filter:{grade:'!'+'C'}
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.
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">

1 Comment

This is the real deal. This is the power. This is the way. I went with this and now I'm happy.
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.

1 Comment

I had the same error like you, thanks for the hint with third boolean parameter. Was not aware of it.
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'});

3 Comments

what is filterFilter ? is it any service or directive? where is the code for filterFilter?
it is an angular service. Have a look at the first example in the link above. (in the scripts.js file)
although they have changed the documentation filterFilter still works..
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.

Comments

4

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

var foo = $filter('filter')($scope.results.subjects, function (item) {
  return item.grade !== 'A';
});

Comments

0

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

 variable = (array | filter : {Lookup1Id : subject.Lookup1Id, Lookup2Id : subject.Lookup2Id} : true)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.