141

I am trying to create a custom filter in AngularJS that will filter a list of objects by the values of a specific property. In this case, I want to filter by the "polarity" property(possible values of "Positive", "Neutral", "Negative").

Here is my working code without the filter:

HTML:

<div class="total">
    <h2 id="totalTitle"></h2>
    <div>{{tweets.length}}</div>
    <div id="totalPos">{{tweets.length|posFilter}}</div>
    <div id="totalNeut">{{tweets.length|neutFilter}}</div>
    <div id="totalNeg">{{tweets.length|negFilter}}</div>
</div>

Here is the "$scope.tweets" array in JSON format:

{{created_at: "Date", text: "tweet text", user:{name: "user name", screen_name: "user       screen name", profile_image_url: "profile pic"}, retweet_count: "retweet count", polarity: "Positive"},
 {created_at: "Date", text: "tweet text", user:{name: "user name", screen_name: "user screen name", profile_image_url: "profile pic"}, retweet_count: "retweet count", polarity: "Positive"},
 {created_at: "Date", text: "tweet text", user:{name: "user name", screen_name: "user screen name", profile_image_url: "profile pic"}, retweet_count: "retweet count", polarity: "Positive"}}

The best filter I could come up with as follows:

myAppModule.filter('posFilter', function(){
return function(tweets){
    var polarity;
    var posFilterArray = [];
    angular.forEach(tweets, function(tweet){
        polarity = tweet.polarity;
        console.log(polarity);
        if(polarity==='Positive'){
              posFilterArray.push(tweet);
        }
        //console.log(polarity);
    });
    return posFilterArray;
};
});

This method returns an empty array. And nothing is printed from the "console.log(polarity)" statement. It seems like I am not inserting the correct parameters to access the object property of "polarity."

Any ideas? Your response is greatly appreciated.

sh3nan1gans
  • 2,246
  • 5
  • 19
  • 23
  • 3
    Nice question, but code could be reduced, big part of it is not relevant to the question. – setec Dec 04 '14 at 08:26

5 Answers5

219

You simply have to use the filter filter (see the documentation) :

<div id="totalPos">{{(tweets | filter:{polarity:'Positive'}).length}}</div>
<div id="totalNeut">{{(tweets | filter:{polarity:'Neutral'}).length}}</div>
<div id="totalNeg">{{(tweets | filter:{polarity:'Negative'}).length}}</div>

Fiddle

Blackhole
  • 20,129
  • 7
  • 70
  • 68
  • 1
    Is there a way to filter the item list by passing a custom filter to an ng-click event outside of the ng-repeat statement? In this case, I want to place three "polarity" buttons above the results that filter based on the rating. – sh3nan1gans Jul 22 '13 at 19:54
  • 2
    I'm not sure to understand. If you want to choose the polarity to filter, you can pass a scope variable instead of a plain text : ```filter:{polarity:polarityToFilter}``` where ```$scope.polarityToFilter``` is filled by a click on one of the three buttons. Is this what you are trying to do ? – Blackhole Jul 22 '13 at 21:43
  • That seems like it could work. However, my app also needs to be able to delete individual list items. – sh3nan1gans Jul 23 '13 at 18:55
  • The problem with filtering is that a new array is created every time a filter is applied which breaks the tie between a filtered item and its original index in the unfiltered array. Is there a way to maintain the tie or is ng-hide my only option? Here's a tutorial for an alternative to filtering by using ng-hide: http://www.bennadel.com/blog/2487-Filter-vs-ngHide-With-ngRepeat-In-AngularJS.htm – sh3nan1gans Jul 23 '13 at 19:43
  • [ngRepeat](http://docs.angularjs.org/api/ng.directive:ngRepeat) exposes an `$index` propertie on the local scope that you can also use. – Blackhole Jul 24 '13 at 11:48
  • I was able to filter using ng-hide. My current delete method looks like this: $scope.delete = function (idx) { $scope.tweets.splice(idx, 1); While using a regular filter, this method does not delete the current list item while using the filter. For instance, if I filter the array, and delete an item at index 0 of the new filtered array, then the item at index 0 of the unfiltered array is removed. This problem is fixed with the ng-hide method. – sh3nan1gans Jul 24 '13 at 17:20
  • Thanks, Your fiddle really helped a lot. – shaikh Aug 31 '16 at 07:38
  • In my case `tweets` was an array, so filter returned an array with one element. I had to use `(tweets | filter:{polarity:'Positive'})[0].length`. – DavidC Sep 12 '20 at 00:37
27

The documentation has the complete answer. Anyway this is how it is done:

<input type="text" ng-model="filterValue">
<li ng-repeat="i in data | filter:{age:filterValue}:true"> {{i | json }}</li>

will filter only age in data array and true is for exact match.

For deep filtering,

<li ng-repeat="i in data | filter:{$:filterValue}:true"> {{i}}</li>

The $ is a special property for deep filter and the true is for exact match like above.

Mo.
  • 26,306
  • 36
  • 159
  • 225
Abel Terefe
  • 1,440
  • 20
  • 17
23

You could also do this to make it more dynamic.

<input name="filterByPolarity" data-ng-model="text.polarity"/>

Then you ng-repeat will look like this

<div class="tweet" data-ng-repeat="tweet in tweets | filter:text"></div>

This filter will of course only be used to filter by polarity

Llewellyn Collins
  • 2,243
  • 2
  • 23
  • 37
5

We have Collection as below:


enter image description here

Syntax:

{{(Collection/array/list | filter:{Value : (object value)})[0].KeyName}}

Example:

{{(Collectionstatus | filter:{Value:dt.Status})[0].KeyName}}

-OR-

Syntax:

ng-bind="(input | filter)"

Example:

ng-bind="(Collectionstatus | filter:{Value:dt.Status})[0].KeyName"
Alex Romanov
  • 11,453
  • 6
  • 48
  • 51
Rahul Modi
  • 748
  • 11
  • 21
4

You can try this. its working for me 'name' is a property in arr.

repeat="item in (tagWordOptions | filter:{ name: $select.search } ) track by $index
Satish Singh
  • 2,169
  • 3
  • 23
  • 32