How do I filter an array with AngularJS and use a property of the filtered object as the ng-model attribute?

Angularjs

Angularjs Problem Overview


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?

Angularjs Solutions


Solution 1 - Angularjs

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]

Solution 2 - Angularjs

<div ng-repeat="subject in results.subjects | filter:{grade:'C'}">
    <input ng-model="subject.title" />
</div>

Solution 3 - Angularjs

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">

Solution 4 - Angularjs

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.

Solution 5 - Angularjs

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'});

Solution 6 - Angularjs

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.

Solution 7 - Angularjs

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

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

Solution 8 - Angularjs

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

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBernhard HofmannView Question on Stackoverflow
Solution 1 - AngularjsOliverView Answer on Stackoverflow
Solution 2 - AngularjsJB NizetView Answer on Stackoverflow
Solution 3 - AngularjslukeCzView Answer on Stackoverflow
Solution 4 - AngularjsDaniel MorrisView Answer on Stackoverflow
Solution 5 - AngularjsKieranView Answer on Stackoverflow
Solution 6 - AngularjsDiego VenâncioView Answer on Stackoverflow
Solution 7 - AngularjsNeluView Answer on Stackoverflow
Solution 8 - AngularjsAmay KulkarniView Answer on Stackoverflow