admin管理员组文章数量:1356842
This is some of sample JSON data.
$scope.Products = [
{
"Variants": [],
"SubCategoryID": "66",
"ProductImagePath": "/images/britannia/887.png",
"SubCategoryName": "Butter",
"BrandName": "Britannia",
"ProductID": "887",
"BrandID": "76",
"ProductName": "Butter"
},
{
"Variants": [],
"SubCategoryID": "71",
"ProductImagePath": "/images/amul/886.png",
"SubCategoryName": "Cheese",
"BrandName": "Amul",
"ProductID": "886",
"BrandID": "47",
"ProductName": "cheese"
},
{
"Variants": [],
"SubCategoryID": "106",
"ProductImagePath": "/images/amul/885.png",
"SubCategoryName": "Curd",
"BrandName": "Amul",
"ProductID": "885",
"BrandID": "47",
"ProductName": "curd"
}
]
And this is How i am rendering to webpage.
<div ng-if="SearchText" class='box' ng-repeat="product in Products | filter:FilterExpr | orderBy:'ProductName'">
<ng-include src="'monTemplate.html'"></ng-include>
</div>
There is a search text box in page. When user start typing in serach text box i assigns value to FilterExpr like this.
$scope.$on('SearchTextChanged', function(event, SearchText) {
if (SearchText.length >=3) {
$scope.FilterExpr = SearchText;
}
});
When user type amul or cheese or butter, It is able to filter the products. Problem is when user types amul curd or curd amul or butter britannia, NO products are displaying on the page.
How to make it work? What change i need to do to so it is able to filter for multiple words.
This is some of sample JSON data.
$scope.Products = [
{
"Variants": [],
"SubCategoryID": "66",
"ProductImagePath": "/images/britannia/887.png",
"SubCategoryName": "Butter",
"BrandName": "Britannia",
"ProductID": "887",
"BrandID": "76",
"ProductName": "Butter"
},
{
"Variants": [],
"SubCategoryID": "71",
"ProductImagePath": "/images/amul/886.png",
"SubCategoryName": "Cheese",
"BrandName": "Amul",
"ProductID": "886",
"BrandID": "47",
"ProductName": "cheese"
},
{
"Variants": [],
"SubCategoryID": "106",
"ProductImagePath": "/images/amul/885.png",
"SubCategoryName": "Curd",
"BrandName": "Amul",
"ProductID": "885",
"BrandID": "47",
"ProductName": "curd"
}
]
And this is How i am rendering to webpage.
<div ng-if="SearchText" class='box' ng-repeat="product in Products | filter:FilterExpr | orderBy:'ProductName'">
<ng-include src="'monTemplate.html'"></ng-include>
</div>
There is a search text box in page. When user start typing in serach text box i assigns value to FilterExpr like this.
$scope.$on('SearchTextChanged', function(event, SearchText) {
if (SearchText.length >=3) {
$scope.FilterExpr = SearchText;
}
});
When user type amul or cheese or butter, It is able to filter the products. Problem is when user types amul curd or curd amul or butter britannia, NO products are displaying on the page.
How to make it work? What change i need to do to so it is able to filter for multiple words.
Share Improve this question asked Jul 2, 2015 at 16:00 Devesh AgrawalDevesh Agrawal 9,21218 gold badges86 silver badges134 bronze badges 1-
You need to write a custom filter method and use that instead of having it filter via
filter:FilterExpr
. – KreepN Commented Jul 2, 2015 at 16:03
2 Answers
Reset to default 8 +25The default parator
used by the default filter
is very simple. It looks for the exact searched string and does not parse the search string in any way.
The simplest way to improve this is implementing another parator
(doc).
<div ng-if="SearchText" class='box' ng-repeat="product in Products | filter:FilterExpr:searchFuncComparator | orderBy:'ProductName'">
<ng-include src="'monTemplate.html'"></ng-include>
</div>
and adding a parator
to the $scope
:
$scope.searchFuncComparator = function(actual, expected) {
// pare actual with expected and return true if match
// otherwise false
};
All there is left is to implement you're favorite search method above :)
You can do this with a custom filter. To create a custom filter, you register a new filter factory function with your module and pass in a name (I chose to call it 'multiFilter'). This factory function returns a filter function, which will automatically receive the input (such as the array from your ng-repeat) as its first value. The subsequent values passed to the filter function are the ones you'll specify in your filter markup.
So, to make our filter nice and reusable, it's going to accept two additional values. The first will be the object keys that we want to search and the second is the search string. So in your html, you would specify this filter as | multiFilter: ['SubCategoryName', 'BrandName'] : SearchText
.
Then you'll need to add your custom filter:
.filter('multiFilter', function(){ //factory function
return function(input, keys, query) { //filter function with input as first argument
var results = [];
var terms, key, value, x, i, j;
if(angular.isDefined(keys) && angular.isDefined(query)) { //1.
keys = angular.isArray(keys) ? keys : keys.split(' '); //3.
terms = query.toLowerCase().split(' '); //4.
for (x=0; x < input.length; x++) { //5.
for (i=0; i < keys.length; i++) { //6.
if (results.indexOf(input[x])===-1) { //7.
key = keys[i];
for (j=0; j < terms.length; j++) { //8.
value = input[x][key].toString().toLowerCase(); //9.
if (value.indexOf(terms[j])!==-1) { //10.
results.push(input[x]);
}
}
}
}
}
return results; //11.
} else {
return input; //2.
}
};
});
How it works:
- To make sure that there are no errors if either the search string or object keys are empty, we'll check that they are both defined with
angular.isDefined()
. - If either is undefined, we can just return the array that the filter receives.
- To make the filter a bit easier to work with, we'll make it so that you can pass either an array of object keys or a single key as a string. If it's a string, we'll convert that to an array with one element using split.
- Next, because you want users to be able to search on multiple terms and match any of the search values, we'll split the search string that we get into an array. To make our filter case insensitive, we'll convert the search string (and later the value that we're going to match it to) to lowercase.
- In Javascript, native for loops are generally faster than other array iterators, so we're going to use three nested for loops. The outermost loop grabs each object in the input array.
- The next loop grabs each key in the array of keys we passed to the filter.
- At this point, since we're potentially looping over multiple keys for the same object, we can make the filter a little more efficient by checking if the object we're working with is already in the result set (this way we can skip the inner loop and move on to the next object in the input array).
- The innermost loop does the work to loop over each of our search terms and check if they exist in the current input array property value.
- Again, to make the filter case insensitive, we'll convert the value of the current input array property to a string and then to lowercase.
- If the search term is found, then we push the current input object to the results array.
- When the loops are done, we return the results array so that it can used in the repeat or piped to the next filter.
Check the snippet below to see it action:
var app = angular.module('filter.demo', []);
app.controller('ProductsController', ['$scope',
function($scope) {
$scope.FilterKeys = ['SubCategoryName', 'BrandName'];
$scope.Products = [{
"Variants": [],
"SubCategoryID": "66",
"ProductImagePath": "/images/britannia/887.png",
"SubCategoryName": "Butter",
"BrandName": "Britannia",
"ProductID": "887",
"BrandID": "76",
"ProductName": "Butter"
}, {
"Variants": [],
"SubCategoryID": "71",
"ProductImagePath": "/images/amul/886.png",
"SubCategoryName": "Cheese",
"BrandName": "Amul",
"ProductID": "886",
"BrandID": "47",
"ProductName": "cheese"
}, {
"Variants": [],
"SubCategoryID": "106",
"ProductImagePath": "/images/amul/885.png",
"SubCategoryName": "Curd",
"BrandName": "Amul",
"ProductID": "885",
"BrandID": "47",
"ProductName": "curd"
}];
}
]);
app.filter('multiFilter', function() {
return function(input, keys, query) {
var results = [];
var terms, key, value, x, i, j;
if (angular.isDefined(keys) && angular.isDefined(query)) {
keys = angular.isArray(keys) ? keys : keys.split(' ');
terms = query.toLowerCase().split(' ');
for (x = 0; x < input.length; x++) {
for (i = 0; i < keys.length; i++) {
if (results.indexOf(input[x]) === -1) {
key = keys[i];
for (j = 0; j < terms.length; j++) {
value = input[x][key].toString().toLowerCase();
if (value.indexOf(terms[j]) !== -1) {
results.push(input[x]);
}
}
}
}
}
return results;
} else {
return input;
}
};
});
@import url('https://maxcdn.bootstrapcdn./bootstrap/3.3.5/css/bootstrap.min.css');
<script src="https://ajax.googleapis./ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="container">
<h2>Demo</h2>
<p><em>use search terms:</em> butter, cheese, amul, britannia, curd</p>
<div ng-app="filter.demo" ng-controller="ProductsController">
<label>Search:
<input type="text" name="search" ng-model="SearchText" class="form-control" />
</label>
<div ng-if="SearchText" class='box' ng-repeat="product in Products | multiFilter: FilterKeys : SearchText | orderBy:'ProductName' track by $index">
<h4 class="text-muted">{{product.SubCategoryName}}</h4>
<p><strong>Brand Name:</strong> {{product.BrandName}}</p>
</div>
</div>
</div>
本文标签: javascriptAngularJS filter is not working for multiple words from 2 different keysStack Overflow
版权声明:本文标题:javascript - AngularJS filter is not working for multiple words from 2 different keys - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744021182a2577236.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论