missgg
missgg

Reputation: 101

Angular query search for all array objects

I am new to Angular and I need your help writing a custom filter where I can search through all array objects and get my matching results that would ignore period(.) and commas(,). For example, if I type "ashton," I should get "stash" and "ashton marton". But I am at a loss and need some advice. Here's what I have so far.

In my angularSearch.html I have this.

<!DOCTYPE html>
<html>
<head>
    <script src="js/angular.js"></script>x
    <title></title>
</head>
<body ng-app="storeSearch">
<div ng-controller="searchController">
    <label>Search: </label>
    <input type="text" class="search" ng-model="searchString" placeholder="Search"/>
<table>
    <tr ng-repeat="p in products | searchFilter: searchString">
        <td>{{p.product_code}}</td>
        <td>{{p.subname}}</td>
        <td>{{p.description}}</td>
    </tr>
</table>
</div>
<script src="app/app.js"></script>
</body>
</html>

My app.js is shown below.

var app = angular.module("storeSearch", []);

app.controller("searchController", ["$scope", function($scope){
    $scope.products = [
        {
            product_title: "A-2368",           
            description:"Asthon Martin",
            sub_name:"2000 model ashton martin"
        },
        {
            product_title:"S-2310",           
            description:"Stash of money",
            sub_name:"Rolls Royce"
        },
        {
            product_title:"h-2369",           
            description:"Honda Civic 2003",
            sub_name:"Marton Ashton, Honda Series"
        }
    ];

}]);

app.filter('searchFilter', function(){
    return function(arr, searchString){
        if(!searchString){
            return arr;
        }
        var result = [];
        searchString = searchString.toLowerCase();
        angular.forEach(arr, function(products){
            if(products.value.toLowerCase().indexOf(searchString) !== -1){
                result.push(products);
            }
        });
        return result;
    };
});

Upvotes: 0

Views: 2611

Answers (2)

Guido Kitzing
Guido Kitzing

Reputation: 892

One thing you need to change in order to have your filter working, is this:

products.value.toLowerCase().indexOf(searchString) 

value is not a property of your array, so try changing that to:

products.description.toLowerCase().indexOf(searchString) 

This will compare the property description. Now you can implement the details. Your version is causing an error in the console, because products.value is undefined and you try to call toLowerCase() on undefined. My suggestion will fix that.

Update:

If you like to run over all your properties, you can try to extend your loop like this:

angular.forEach(arr, function(products) {
    for (var property in products) {
        if (products.hasOwnProperty(property)) {
            if (products[property].toLowerCase().indexOf(searchString) !== -1) {
                result.push(products);
                break;
            }
        }
    }
});

Update 2

According to your comment you want to modify the comparison of the properties a little, I guess you would also like to choose the properties that you actually want to compare to.

app.filter('searchFilter', function() {
    return function(arr, searchString) {
        var result, property, activePropertyList;

        activePropertyList = ['description', 'product_title', 'sub_name'];
        result = [];

        function isPartofSearchString(propVal, searchString) {
            propVal = propVal.replace(/\W+/g, '').toLowerCase();

            return propVal.indexOf(searchString) !== -1;
        }

        if (!searchString) {
            return arr;
        }

        searchString = searchString.toLowerCase();

        angular.forEach(arr, function(products) {
            for (property in activePropertyList) {
                if (isPartofSearchString(products[property], searchString)) {
                    result.push(products);
                    break;
                }
            }
        });

        return result;
    };
});

Function isPartofSearchString() substitues your critera (this makes things a little cleaner). activePropertyList[] defines the names of all properties, that you want to compare with. Since you have a || expression, it is sufficient, if one property matches your criteria -> hence the break to make it more efficient.

I know, there is still room for improvement here: e.g. you could move parts of your filter to the controller (the comparison function and the definition of the active properties), but I wanted to keep your code in the filter for this example.

Hope that helps.

Upvotes: 3

Bata
Bata

Reputation: 651

app.filter('searchFilter', function(){
    return function(arr, searchString){
        var stripped = searchString.replace(',', '').replace('.', '').toLowerCase();
        return arr.filter(function(member) {
            return member.description.indexOf(stripped) > -1;
        });
    };
});

Upvotes: 0

Related Questions