7

I have a JSON object which is as follows

[{
    "id": 1,
    "firstName": "Jennifer",
    "middleName": null,
    "lastName": "Aniston",
    "address": "New York City",
}, {
    "id": 2,
    "firstName": "Angelina",
    "middleName": null,
    "lastName": "Jolie",
    "address": "Beverley Hills",
}, {
    "id": 3,
    "firstName": "Emma",
    "middleName": null,
    "lastName": "Watson",
    "address": "London",
}]

I'm populating this data in view using ng-repeat.

<td ng-repeat="row in list | filter:filterBeauties">
{{row.firstName}} {{row.lastName}}
</td>

Now I have an input box which I'd like to use to filter these names. I would like to use same input box to filter firstName and then filter lastName and don't filter anything else (eg. address).

<input type="text" placeholder="Filter" ng-model="filterBeauties.firstName">

Any idea how can I achieve it?

6
  • (firstName and lastName) or would you like (firstName or lastName) Commented Jan 7, 2014 at 17:21
  • firstName and lastName. So if I type Jennifer Aniston in input box it must filter to Jennifer Aniston . Commented Jan 7, 2014 at 17:27
  • ok, i think this can only be done by writing a custom filter - because you need to parse the input query parameter... Commented Jan 7, 2014 at 17:29
  • I understand what you want to do, but from an architecture standpoint, I would suggest having firstAndLastName in your view and have your search model be on that. Commented Jan 7, 2014 at 17:30
  • @ChrisStory you mean I should change backend? Commented Jan 7, 2014 at 17:36

5 Answers 5

6

Try this fiddle.

Essentially, I created a sub-structure for filtering within the data structure being displayed and filter only on that property (e.g. 'filterTerms'):

HTML:

<div ng-controller="MyCtrl">
   <input type="text" ng-model="search.filterTerms">
   <table border="1">
      <tr ng-repeat="row in list | filter:search">
         <td>{{row.firstName}} {{row.lastName}}</td>
      </tr>
   </table>
</div>

JavaScript:

var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.list = [{
    "id": 1,
    "address": "New York City",
    "firstName": "Jennifer",
    "middleName": null,
    "lastName": "Aniston",
    "filterTerms": {
        "firstName": "Jennifer",
        "middleName": null,
        "lastName": "Aniston",
    }
}, {
    "id": 1,
    "address": "New York City",
    "firstName": "Jennifer",
    "middleName": null,
    "lastName": "Leela",
    "filterTerms": {
        "firstName": "Jennifer",
        "middleName": null,
        "lastName": "Leela",            
    }
}, {
    "id": 2,
    "address": "Beverley Hills",
    "firstName": "Angelina",
    "middleName": null,
    "lastName": "Jolie",
    "filterTerms": {
        "firstName": "Angelina",
        "middleName": null,
        "lastName": "Jolie",            
    }
}, {
    "id": 3,
    "address": "London",
    "firstName": "Emma",
    "middleName": null,
    "lastName": "Watson",
    "filterTerms": {
        "firstName": "Emma",
        "middleName": null,
        "lastName": "Watson",            
    }
}];
}

You could simplify this even further for this case by putting all the names into one field (see fiddle here:

HTML:

<div ng-controller="MyCtrl">
    <input type="text" ng-model="search.filterTerm" />
    <table border="1">
        <tr ng-repeat="row in list | filter:search">
            <td>{{row.first}} {{row.last}} {{row.address}}</td>
        </tr>
    </table>
</div>

JavaScript:

var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
    $scope.list = [{
        "id": 0, "first": "Jenny", "last": "Sorenson", "address": "123 W. Wallnut St.",
        "filterTerm": "Jenny Sorenson"
    },{
        "id": 0, "first": "Susan", "last": "Hinkle", "address": "456 W. Doorbell Dr.",
        "filterTerm": "Susan Hinkle"
    },{
        "id": 0, "first": "Rachel", "last": "Karlyle", "address": "789 W. Sunset Blvd.",
        "filterTerm": "Rachel Karlyle"
    },{
        "id": 0, "first": "Gwen", "last": "Lippi", "address": "0 W. Silly Cir.",
        "filterTerm": "Gwen Lippi"
    }]
}
Sign up to request clarification or add additional context in comments.

1 Comment

its like creating an index for the list. good idea. thanks.
6

Considering that your user have this form:

{
  "id": 2,
  "firstName": "Angelina",
  "middleName": null,
  "lastName": "Jolie",
  "address": "Beverley Hills"
}

If you want to search one of your user by his firstname, his lastname or both at the same time, you need to concat them together.

$scope.query = '';

$scope.search = function (user) {
  var query = $scope.query.toLowerCase(),
  fullname = user.firstName.toLowerCase() + ' ' + user.lastName.toLowerCase();

  if (fullname.indexOf(query) != -1) {
    return true;
  }
  return false;
};

This function will return true if the current user satisfies your query and false if not. Inside of the function, I recommend to put your query in lowercases so you won't have to deal with the uppercases your user will enter in the search input.

Here is the HTML:

<input type="text" placeholder="Search" ng-model="query">
<table>
   <tr ng-repeat="user in users | filter:search">
      <td>{{user.firstName}} {{user.lastName}}</td>
   </tr>
</table>

This technic will only work if you try to search Angelina Jolie, Angelina, Jolie or even InA JOLIe (why not after all). If you try to search first the lastname like Jolie Angelina, it won't work. You can easily fix it by creating a second fullname in your function (e.g. a reverseFullname), concat in first the lastName and then the firstName and test it just like the first fullname string.

1 Comment

Here is the Plunker for the above solution https://plnkr.co/edit/eGSMxheRdEUwHzdwRsTu?p=preview OR try this [Plunker][plnkr.co/edit/eGSMxheRdEUwHzdwRsTu?p=preview]
4

Okay So this is what I did to solve it.

I added a new item in json object (using angular.forEach function) and filtered by it.

$scope.list = beauties.query(function(response) {
    angular.forEach(response, function(value, key) {
          var fullName = value.firstName + ' ' + value.lastName;
          $scope.list[key].fullName = fullName;
   });
});

input box code:

<input type="text" placeholder="Filter" ng-model="filterBeauties.fullName">

ng-repeat

<td ng-repeat="row in list | filter:filterBeauties">
{{row.firstName}} {{row.lastName}}
</td>

Comments

3

You can pass the third argument to the filter function:

$filter('filter')(list, {'firstName':search});

I would have done something like below:

<input type="text" ng-model="search">
<table border="1">
    <tr ng-repeat="row in list | filterBoth:search">
        <td>{{row.firstName}} {{row.lastName}}</td>
    </tr>
</table>

And then write the custom filter as:

myApp.filter('filterBoth', function($filter) {
  return function(list, search) {
    if (!search) return list;

    var arrSearch = search.split(' '),
        lookup = '',
        result = [];

    arrSearch.forEach(function(item) {
      lookup = $filter('filter')(list, {'firstName': item});console.log(lookup);
      if (lookup.length > 0) result = result.concat(lookup);
    });

    return result;
  };
});

Demo: http://jsfiddle.net/wAp4S/1/

The only issue is you will get duplicate rows as you are concatenating two similar arrays which can easily be fixed using _.uniq underscore.js method.

5 Comments

Hi the jsFiddle you shared doesnt really work the way I want it to. If you write "Jennifer Aniston" in input box it doesnt return anything in result.
Oh. In that case, you have to split the search by space, filter each word separately, group the result, make it unique, and finally update the scope. The current demo is good enough for you to go ahead and explore it as per your expectation.
This is not working. Check your jsfiddle. If I type Ang I can only see Angelina not Aniston.
I don't think 'Ang' should match 'Aniston'. However, 'An' also does NOT return 'Aniston'. It appears last names are not being filtered in the fiddle.
This does not really work the way it should. It also filters on the address, even though this is not the wanted behaviour.
3

Try the angular-filter library instead of writing complex filters. The searchField filter can be helpful here.

https://github.com/a8m/angular-filter

CONTROLLER

$scope.users = [
  { first_name: 'Sharon', last_name: 'Melendez' },
  { first_name: 'Edmundo', last_name: 'Hepler' },
  { first_name: 'Marsha', last_name: 'Letourneau' }
];

HTML

<input ng-model="search" placeholder="search by full name"/>
<th ng-repeat="user in users | searchField: 'first_name': 'last_name' | filter: search">
  {{ user.first_name }} {{ user.last_name }}
</th>
<!-- so now you can search by full name -->

Good Luck.

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.