DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • An Introduction to Bloom Filters
  • Angular Component Tree With Tables in the Leaves and a Flexible JPA Criteria Backend
  • Dataweave Exercise: Filter Like Functions in Arrays Module - Part 1
  • DataWeave Interview Question: Compare IDs From Two Arrays and Create a New Array

Trending

  • Vibe Coding With GitHub Copilot: Optimizing API Performance in Fintech Microservices
  • The Cypress Edge: Next-Level Testing Strategies for React Developers
  • Event-Driven Architectures: Designing Scalable and Resilient Cloud Solutions
  • Comprehensive Guide to Property-Based Testing in Go: Principles and Implementation
  1. DZone
  2. Data Engineering
  3. Data
  4. AngularJS: Different Ways of Using Array Filters

AngularJS: Different Ways of Using Array Filters

In this article, we learn how to utilize AngularJS's array filter features in a variety of use cases. Read on to get started.

By 
Siva Prasad Reddy Katamreddy user avatar
Siva Prasad Reddy Katamreddy
·
Oct. 24, 14 · Tutorial
Likes (5)
Comment
Save
Tweet
Share
315.1K Views

Join the DZone community and get the full member experience.

Join For Free

AngularJS provides a filter feature which can be used to format input value or to filter an array with the given matching input criteria. For example, you can use the 'date' filter to format a date value into a human-readable date representation like MM-DD-YYYY as {{dob | date}}.

On the other hand, there are array filtering features that are very useful while filtering data from an array of JavaScript objects. Array filtering is commonly used with a table and an ng-repeat directive. 

For example, we can have a list of Todos that we display in a table using the ng-repeat tag. And we can have a text field to search todos that match any one of the data properties of the todo object as follows:

$scope.todos = [
    {id: 1,title: 'Learn AngularJS', description: 'Learn AngularJS', done: true, date: new Date()}  ,
    {id: 2,title: 'Explore ui-router', description: 'Explore and use ui-router instead of ngRoute', done: true, date: new Date()}  ,
    {id: 3,title: 'Play with Restangular', description: 'Restangular seems better than $resource, have a look', done: false, date: new Date()}  ,
    {id: 4,title: 'Try yeoman', description: 'No more labour work..use Yeoman', done: false, date: new Date()}  ,
    {id: 5,title: 'Try MEANJS', description: 'Aah..MEANJS stack seems cool..why dont u try once', done: false, date: new Date()}                
            ];


<input type="text" ng-model="searchTodos">
 <table class="table table-striped table-bordered">
 <thead>
  <tr>
   <th>#</th>
   <th>Title</th>
   <th>Description</th>
   <th>Done?</th>
   <th>Date</th>
  </tr>
 </thead>
 <tbody>
  <tr ng-repeat="todo in todos| filter: searchTodos">
   <td>{{$index + 1}}</td>
   <td>{{todo.title}}</td>
   <td>{{todo.description}}</td> 
   <td>{{todo.done}}</td>
   <td>{{todo.date | date}}</td> 
  </tr>

 </tbody>

</table>

Observe that our search input field's ng-model attribute is set to 'searchTodos' which we have used to filter on the ng-repeat attribute. As you type in the search input field, the $scope.todos array will be filtered and only matching records will show up. This is a "match anything" type filter, which means the search criteria will be checked against all properties (id, title, description, date) of the todo object.

If you want to search only one field, like 'description', you can apply a filter as follows:

<tr ng-repeat="todo in todos| filter: {description: searchTodos}">

If you want to only display Todos which aren't done yet then you can do as follows:

<tr ng-repeat="todo in todos| filter: {description: searchTodos, done: false}">

Note that the two conditions will be applied using AND conditions. 

If you want to display only Todos that aren't done yet and you want to search on all fields, not just on 'description,' then you can do it like this:

<tr ng-repeat="todo in todos| filter: {$: searchTodos, done: false}">

Here $ means all fields. So far so good. It's a simple and straightforward case.

How about having nested objects in our array objects that we want to search based on a nested object property?

Use Cases

Let's look at such a scenario. In order to explain these scenarios, I am using some code examples from my ebuddy application.

In my ebuddy application, I have an ExpenseManager module where I will keep track of my expenses as follows:

  • I will have a list of accounts such as Cash, Savings Bank Account, credit card, etc., with the current balance details. 
  • I will have a list of payees such as rent, Power Bill, Salary, etc., which fall into INCOME or EXPENDITURE categories. 
  • I will record all my transactions by picking one of the accounts and a payee and the amount. 

This application is just to record my financial transactions so that I can see monthly reports by account or payee. I hope you get an idea about the domain model.

Now let us create a simple AngularJS application and set some sample data.

<!DOCTYPE html>
 <html ng-app="myApp">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>My AngularJS App</title>
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
  <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/js/bootstrap.min.js"></script>

  <script>
      var myApp = angular.module('myApp',[]);
      myApp.controller('SampleController', function($scope){
            $scope.accounts = [ 
                    {id: 1, name: 'Cash'}, 
                    {id: 2, name: 'Bank Savings'} 
                  ];
            $scope.payees = [
                    {id:'1',name:'HouseRent', txnType:'EXPENDITURE'},
                    {id: '2', name:'InternetBill', txnType:'EXPENDITURE'}, 
                    {id:'3', name: 'PowerBill', txnType:'EXPENDITURE'}, 
                    {id:'4', name: 'Salary', txnType:'INCOME'}
                  ];
            $scope.transactions = [
                {id:'1', txnType:'EXPENDITURE', amount: 1000, account: $scope.accounts[0], payee: $scope.payees[0]},
                {id:'2', txnType:'EXPENDITURE', amount: 500, account: $scope.accounts[1], payee: $scope.payees[1]},
                {id:'3', txnType:'EXPENDITURE', amount: 1200, account: $scope.accounts[0], payee: $scope.payees[1]},
                {id:'4', txnType:'INCOME', amount: 5000, account: $scope.accounts[1], payee: $scope.payees[3]},
                {id:'5', txnType:'EXPENDITURE', amount:200, account: $scope.accounts[0], payee: $scope.payees[2]}
            ];

      });

  </script>  
</head>
<body ng-controller="SampleController">


 <div class="col-md-8 col-md-offset-2">

    <h3>Transaction Details</h3>
    <table class="table table-striped table-bordered">
        <thead>
            <tr>
                <th>#</th>
                <th>Account</th>
                <th>Type</th>
                <th>Payee</th>
                <th>Amount</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="txn in transactions">
                <td>{{$index + 1}}</td>
                <td>{{txn.account.name}}</td>
                <td>{{txn.txnType}}</td> 
                <td>{{txn.payee.name}}</td> 
                <td>{{txn.amount}}</td> 
            </tr>
        </tbody>
    </table>
</div>

</body>
</html>

This is a very simple AngularJS page which is displaying a list of transactions in a table. Observe that the transactions contain nested objects (account, payee) and we are displaying nested properties (txn.account.name, txn.payee.name) in our table.

Now, we want to filter the transactions in a variety of ways, so let's look at them, case by case. 

Use Case #1: Search by Payee Name 

In our transaction object, we have a nested payee object which contains the name property on which we want to perform a search. 

Let's create a form which will contain all our filters before the transactions table.

The first thought that came to my mind was to perform a search on a nested property in use in the nested property path in the filter as follows:

<input type="text" ng-model="payeeName">
...
<tr ng-repeat="txn in transactions| filter: {payee.name : payeeName}">

But THIS WON'T WORK. 

To search on a nested property we can name our input field ng-model  to match the target property path and use the root object name as a filter, as follows:

<div class="col-md-8 col-md-offset-2">
     <form class="form-horizontal" role="form">
        <div class="form-group">
          <label for="input1" class="col-sm-4 control-label">Search by Payee</label>
          <div class="col-sm-6">
            <input type="text" class="form-control" id="input1" placeholder="Payee Name" ng-model="filterTxn.payee.name">
          </div>
        </div>
  <!-- additional filters will come here -->
 </form>
 <h3>Transaction Details</h3>
 <table class="table table-striped table-bordered">
  ...
  <tbody>
            <tr ng-repeat="txn in transactions| filter: filterTxn">
                ...
    ...
            </tr>
  </tbody>
 </table>
</div>

Observe that we bound the input field ng-model to "filterTxn.payee.name" and used the filter, filterTxn, as a filter. So txn.payee.name will be matched against filterTxn.payee.name.

Use Case #2: Filter by Accounts Dropdown 

We would like to filter the transactions by using Accounts Select dropdown. First, we need to populate a select dropdown using $scope.accounts and use it as a filter.

Add the following filter after our first filter.

<div class="form-group">
  <label for="input2" class="col-sm-4 control-label">Search By Account</label>
  <div class="col-sm-6">
  <select id="input2" class="form-control" ng-model="filterTxn.account">
   <option value="">All Accounts</option>
   <option ng-repeat="item in accounts" value="{{item.id}}">{{item.name}}</option>
  </select>
  </div>
</div>

Here we are populating a <select> field with the $scope.accounts array by displaying the Account Name and using the id as a value.

The key part here is we have to bind ng-model to filterTxn.account. When we select an account, the selected account object reference will be stored in filterTxn.account. As we already have filterTxn as a filter, the account filter will also be applied along with payee name filter.

Also note that the first option "All Accounts" value is empty ("") which will be treated as null by AngularJS, so when the "All Accounts" option is selected no account filter will be applied.

Use Case #3: Search by Transaction Type 

We want to filter the transaction by transaction type (INCOME or EXPENDITURE):

Add the following filter after the second filter:

<div class="form-group">
  <label for="input3" class="col-sm-4 control-label">Search By Type</label>
  <div class="col-sm-6">
  <select id="input3" class="form-control" ng-model="filterTxn.txnType">
   <option value="">All Types</option>
   <option value="EXPENDITURE">EXPENDITURE</option>
   <option value="INCOME">INCOME</option>
  </select>
  </div>
</div>

I hope no further explanation is needed for this one!

Use Case #4: Search by Payees of Expenditure Type 

Ah, this is interesting! We want to search by Payee names but only in the EXPENDITURE type.

We can't simply apply a filter like filter: expPayeeFilter | filter: {txnType: 'EXPENDITURE'} because it will always filter by EXPENDITURE.

So we will create a custom filter to perform a search by payee name in the EXPENDITURE type only when some filtered text is entered as follows:

myApp.filter('expenditurePayeeFilter', [function($filter) {
 return function(inputArray, searchCriteria, txnType){         
  if(!angular.isDefined(searchCriteria) || searchCriteria == ''){
   return inputArray;
  }         
  var data=[];
  angular.forEach(inputArray, function(item){             
   if(item.txnType == txnType){
    if(item.payee.name.toLowerCase().indexOf(searchCriteria.toLowerCase()) != -1){
     data.push(item);
    }
   }
  });      
  return data;
 };
}]);

We have created a custom filter using myApp.filter() and inside it we have used angular.forEach() to iterate over the input array. The rest is plain JavaScript... no magic.

Now we will apply this custom filter as follows:

<tr ng-repeat="txn in transactions| filter: filterTxn | expenditurePayeeFilter:searchCriteria:'EXPENDITURE'">
 <td>{{$index + 1}}</td>
 <td>{{txn.account.name}}</td>
 <td>{{txn.txnType}}</td> 
 <td>{{txn.payee.name}}</td> 
 <td>{{txn.amount}}</td> 
</tr>

Observer the syntax: customFilterName:param1:param2:..:paramN.

These parameters will be passed as arguments to the function inside our custom directive.

Conclusion

We have seen a few interesting options on how to use the AngularJS array filtering features.

You can find the complete code at https://gist.github.com/sivaprasadreddy/fbee047803d14631fafd

Hope this helps!


If you enjoyed this article and want to learn more about Angular, check out our compendium of tutorials and articles from JS to 8.

Filter (software) Data structure AngularJS

Published at DZone with permission of Siva Prasad Reddy Katamreddy, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • An Introduction to Bloom Filters
  • Angular Component Tree With Tables in the Leaves and a Flexible JPA Criteria Backend
  • Dataweave Exercise: Filter Like Functions in Arrays Module - Part 1
  • DataWeave Interview Question: Compare IDs From Two Arrays and Create a New Array

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!