Brian
Brian

Reputation: 903

Angularjs filter multi level object

I need to create a filter in angularjs

My data looks something like this:

[{
    name: 'account1', 
    accounts: [
      {
        name: 'account2', 
        accounts: []
      }, 
      {
        name: 'account3', 
        accounts: [
          {
            name: 'account4',
            accounts: []
          }
        ]
      }
    ]
 }]

I need the filter return the full object if I use account4 for the search text. Or just the first 2 levels if I use account2 etc.

I have searched all over but cant find anything like this and have no idea where to start.

Upvotes: 0

Views: 1025

Answers (2)

Brian
Brian

Reputation: 903

I got it figured out finally. Here is the custom filter I created in case anyone else finds it useful:

.filter('accountsFilter', function() {

  return function(items, searchStr) {

    function filterAccounts(account, str) {

      //if account name matches
      if (account.name && account.name.toLowerCase().indexOf(str.toLowerCase()) > -1) {

        //expand parent account
        if (account.accounts && account.accounts.length > 0) account.expand = true;

        //return account
        return account;

      } else

      //account name doesnt match. check sub accounts
      if (account.accounts && account.accounts.length > 0) {

        //has accounts
        var fa = [];
        angular.forEach(account.accounts, function(act, k) {
          var a = filterAccounts(act, str);

          //if account was returned
          if (a !== false) {

            //add account to filtered accounts
            fa.push(act);
          }   
        });

        //add accounts to parent account
        account.accounts = fa;

        //if there are sub-accounts
        if (fa.length > 0) {

          //make sure account is expanded to show sub accounts
          if (account.accounts && account.accounts.length > 0) account.expand = true;

          //return account
          return account;

        //no sub accounts left
        } else {

          //check and return if main account matches
          return filterAccounts(account, str);
        }

      //no matches              
      } else {
        return false;
      }
    }

    //copy accounts list to prevent original being altered
    var accounts = angular.copy(items);
    var filtered = [];

    //loop through accounts list
    angular.forEach(accounts, function(account) {

      //check if current account matches
      var a = filterAccounts(account, searchStr.name);
      if (a) {

        //add to filtered list
        filtered.push(a);
      }
    });
    return filtered; 
  };
})    

Upvotes: 1

Michael G
Michael G

Reputation: 6745

You'll need to create a custom filter to do what you're requesting. A controller filter will only allow you to provide an expression to include or exclude an ng-repeat item.

A custom filter will allow you to modify the model dynamically. You can splice the json object accordingly.

I'll provide an example when I'm back in in front of a pc.

Upvotes: 1

Related Questions