javascriptangularjssearch

Angular smart search on wildcard


Say you have an array filled with the following objects:

{id: Integer, name:'String'}

Take for instance the following array:

   $scope.users = [{
            id: 1, name: 'Marc Edgelund main'
    }]

You then show these objects in the following way:

Then you have the following html:

      <input type="text" ng-model="search.$"/>
  
  <table>
    <thead>
      <th>id</th>
      <th>Name</th>
    </thead>
    <tbody>
      <tr ng-repeat="user in users | filter:search">
        <td>
          {{user.id}}
        </td>
        <td>
          {{user.name}}
        </td>
      </tr>
    </tbody>
  </table>

Now say you search for the string : Marc Main the result will turn up empty.

This is because angular checks the value of the object and matches it to the string. However in the above example clients of a system might not use "middle" names as a search parameter which means that the search will be inconsistent and annoy the end user since they won't be able to find what they are looking for.

My question is, how do you create a smart search function that allows the above functionality?

Here is a fiddle that shows my example:

Fiddle


Solution

  • I have found something similar to your question here: AngularJS filter for multiple strings.

    I combined surfbuds' answer to pass the property name you want to filter on, with the looping logic of Matthew Berg's answer to get a working solution. Full credit to these two for the great explanations in their posts. Combined, it becomes

    var app = angular.module('myApp', []);
    
    app.filter('filterByObjectName', function () {
    return function (input, searchText, propertyName) {
        var returnArray = [];
        var searchTextSplit = searchText.toLowerCase().split(' ');
        for (var x = 0; x < input.length; x++) {
            var count = 0;
            for (var y = 0; y < searchTextSplit.length; y++) {
                let propertyValue = input[x][propertyName];
                if (propertyValue.toLowerCase().indexOf(searchTextSplit[y]) !== -1) {
                    count++;
                }
            }
            if (count == searchTextSplit.length) {
                returnArray.push(input[x]);
            }
        }
        return returnArray;
    }
    });
    
    app.controller('mainController', ['$scope', function ($scope) {
    $scope.search = 'Marc';
    $scope.users = [
        {
            id: 1,
            name: 'Marc Edgelund main'
        }
    ];
    }]);
    

    And your html becomes:

    <table>
     <thead>
      <th>id</th>
      <th>Name</th>
     </thead>
     <tbody>
     <tr ng-repeat="user in users | matchAccessLevel:search:'name'">
      <td>{{user.id}}</td>
      <td>{{user.name}}</td>
     </tr>
     </tbody>
    </table>