I have an array of json objects like this:
$scope.data = [{ name: "something something", date: 982528 },
{ x: 1, y: { sub: 2}, prop1: "some string" },
{ a: "b", c: "d", e: "some string" }];
and I'm trying to filter it with:
var filteredData = $filter('filter')($scope.data, "some string");
this way in all the properties of the objectes in the array, angular compares with the search string,
in this example it will return the las two objects,
now, what i need is to pass an array of properties like:
var exclude = ['prop1'];
so the filter will omit to compare those properties in each object,
is there an angular filter with this option?
Unfortunately, you should create custom excludeFilter:
angular.module('app', []).controller('ctrl', function($scope){
$scope.data = [
{ name: "something something", date: 982528 },
{ x: 1, y: { sub: 2}, prop1: "some string", prop2: "some string" },
{ a: "b", c: "d", e: "some string" }
];
$scope.search = 'some';
$scope.exclude = ['prop1', 'prop2'];
}).filter('excludeFilter', function(){
return function(data, search, exclude){
if(!search)
return data;
return data.filter(function(x){
for(var prop in x)
if(exclude.indexOf(prop) == -1){
var value = x[prop];
if(value.indexOf && value.indexOf(search) != -1)
return true;
if(!value.indexOf && value == search)
return true;
}
return false;
});
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">
</script>
<div ng-app='app' ng-controller='ctrl'>
search: <input type='text' ng-model='search'/>
<br>
exclude: <input type='text' ng-model='exclude' ng-list/>
<ul>
<li ng-repeat='x in data | excludeFilter : search : exclude'>{{x | json}}</li>
</ul>
</div>
Related
Here is a small example of my html using ng-repeat:
<div ng-repeat="item in vm.templateList | filter: vm.myFilter">
<h3>{{item.Code}}</h3>
</div>
In Js file the vm.templateList is as followed(as an example):
vm.templateList = [{Code: 'a', ID: 1},
{code: 'a', ID: 2},
{code: 'b', ID: 3},
{code: 'c', ID: 4}];
Imagine I want to filter this list for all items that have ID 1 and also items that have ID 2.
What I originaly was doing was like this:
vm.filter = {ID: 1};
But this was I can only filter the list on 1 ID. Can anyone suggest a way?
You can add the following AngularJS filter to your application :
// add a custom filter to your module
angular.module('MyModule').filter('myFilter', function() {
// the filter takes an additional input filterIDs
return function(inputArray, filterIDs) {
// filter your original array to return only the objects that
// have their ID in the filterIDs array
return inputArray.filter(function (entry) {
return this.indexOf(entry.ID) !== -1;
}, filterIDs); // filterIDs here is what "this" is referencing in the line above
};
});
You then declare your filter array in the controller as such :
vm.IDs = [1, 2];
Then your view should look like this :
<div ng-repeat="item in vm.templateList | myFilter: vm.IDs">
<h3>{{item.Code}}</h3>
</div>
You can use something like:
html:
<section>
<div ng-repeat="item in vm.templateList | filter:checkFilterOptions">
<h3>{{item.Code}}</h3>
</div>
</section>
Js:
$scope.vm = {};
$scope.vm.templateList = [
{Code: 'a', ID: 1},
{Code: 'a', ID: 2},
{Code: 'b', ID: 3},
{Code: 'c', ID: 4}
];
$scope.filterOptions = [1,2,3];
$scope.checkFilterOptions = function(value, index) {
return value.ID && $scope.filterOptions.indexOf(value.ID) !== -1;
}
I have an array (1) with some id's and another array (2) with creatures, they have id (like in first array) and names. And I want to create new array (it will be looks like (1) id array, but only with id that in (2)). So I think that I need use filter.
(1)
$scope.main = ['dog', 'cat', 'bird', 'bug', 'human'];
(2)
$scope.creatures = [
{
id: 'cat',
name : 'fluffy'
},
{
id: 'cat',
name : 'mr.Kitty'
},
{
id: 'human',
name: 'Rachel'
},
{
id: 'cat',
name : 'Lucky'
},
{
id: 'cat',
name: 'Tom'
}
];
filter:
$scope.results = $scope.main.filter(function(item) {
angular.forEach($scope.creatures, function(creature) {
return item === creature.id;
});
});
I expect that it will be
$scope.results === ['cat', 'human'];
But I have
$scope.results // [0] empty array
Where I'm wrong? Plnkr example
It is not working because you are returning in the first iteration itself inside forEach loop. You can get it working as shown below :
Updated Plunker
$scope.results = [];
$scope.main.filter(function(item) {
angular.forEach($scope.creatures, function(creature) {
if(item === creature.id){
if( $scope.results.indexOf(item) === -1){
$scope.results.push(item);
}
}
});
});
Instead of looping again inside the filter, we can get the ids out of creatures array first and then filter them in main array like below :
$scope.results = [];
$scope.ids = $scope.creatures.map(function (creature){
return creature.id;
});
$scope.ids.map(function (id){
if($scope.main.indexOf(id) !== -1){
if( $scope.results.indexOf(id) === -1){
$scope.results.push(id);
}
}
});
console.log($scope.results);
Made few changes in your plunker, it is working now. Can you check with this code.
var app = angular.module('App', []);
app.controller('Ctrl', function($scope, $timeout){
$scope.main = ['dog', 'cat', 'bird', 'bug', 'human'];
$scope.creatures = [
{
id: 'cat',
name : 'fluffy'
},
{
id: 'cat',
name : 'mr.Kitty'
},
{
id: 'human',
name: 'Rachel'
},
{
id: 'cat',
name : 'Lucky'
},
{
id: 'cat',
name: 'Tom'
}
];
var array = [];
$scope.call = function() {
angular.forEach($scope.main,function(item){
angular.forEach($scope.creatures, function(creature) {
if(item == creature.id){
// console.log('item',item,' creatureId',creature.id);
if(array.indexOf(item) < 0 ){
array.push(item);
}
console.log(array);
}
});
$scope.results = array;
});
};
$scope.call();
console.log('result ',$scope.results);
});
I have this array of objects. that holds somethings like this.
[
{
id: 1,
name: "Extra Cheese"
},
{
id: 2,
name: "No Cheese"
}
]
im iterating thru the array here
<select ng-model="item.modifiers" multiple chosen class="chosen-select" tabindex="4" ng-options="modifier._id as modifier.name for modifier in modifiers"></select>
The thing item.modifiers model that has an array of this 2 id
[
1,2
]
I want the multi select to auto selected the two ids that are in the item.model
I want the final result to look something like this
Your code is pretty much working already, maybe some of the variables are not assigned correctly (eg. id instead of _id)
angular.module('test', []).controller('Test', Test);
function Test($scope) {
$scope.modifiers = [
{
id: 1,
name: "Extra Cheese"
},
{
id: 2,
name: "No Cheese"
}
]
$scope.item = {};
// add this for pre-selecting both options
$scope.item.modifiers = [1,2];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app='test' ng-controller='Test'>
<select ng-model="item.modifiers" multiple chosen class="chosen-select" tabindex="4" ng-options="modifier.id as modifier.name for modifier in modifiers"></select>
</div>
If I understand the question correctly, you're wanting to pre-select the two options.
To do this you will need to set your ng-model to point to the actual objects you are iterating over.
You will also need to change your ng-options to ng-options="modifier as modifier.name for modifier in modifiers" rather than just iterating over the ids.
Here's the relevant documentation under Complex Models (objects or collections)
https://docs.angularjs.org/api/ng/directive/ngOptions
Something like this should work:
HTML:
<select ng-model="$ctrl.item.modifiers"
ng-options="modifier as modifier.name for modifier in $ctrl.modifiers"
multiple chosen class="chosen-select" tabindex="4" >
</select>
JS:
app.controller("my-controller", function() {
var $ctrl = this;
$ctrl.modifiers = [{
id: 1,
name: "Extra Cheese"
}, {
id: 2,
name: "No Cheese"
}];
$ctrl.item = {
modifiers: []
}
$ctrl.$onInit = function() {
const id1 = 1;
const id2 = 2;
for (const modifier of $ctrl.modifiers) {
if (modifier.id === id1 || modifier.id === id2) {
$ctrl.item.modifiers.push(modifier);
}
}
}
}
Here's a pen showing the result:
http://codepen.io/Lahikainen/pen/WooaEx
I hope this helps...
I am trying to write a small filter to hide from my repeater elements.
Let's say that my scope is:
$scope.test = [
{id: 1,name: "Test number 1"},
{id: 2,name: "Test number 2"},
{id: 3,name: "Test number 3"},
{id: 4,name: "Test number 4"},
{id: 5,name: "Test number 5"},
{id: 6,name: "Test number 6"},
{id: 7,name: "Test number 7"},
{id: 8,name: "Test number 8"},
{id: 9,name: "Test number 9"},
{id: 10,name: "Test number 10"}
]
and in my repeater I am doing something like this:
<div ng-repeat="t in test| hide:[1,6]"></div>
I started to write my filter but I got stuck. This is what I have so far:
filter('hideIDs', function() {
newArray= [];
function(zone, IDS) {
var containsObject, newArray;
containsObject = function(obj, list) {
var i;
i = void 0;
i = 0;
while (i < list.length) {
if (list[i] === obj) {
return true;
}
i++;
}
return false;
};
angular.forEach(IDS, function(hide) {
return angular.forEach(test, function(t) {
if (t.id === hide) {
return
} else {
if (containsObject(t, newArray)) {
return
} else {
newArray.push(t);
}
}
});
});
return newArray;
};
});
What I am trying to do with the filter is:
check if t.id should be hidden, and if yes, return without pushing it to newArray
The problem I've got is:
id to hide is 1 on the first loop, and then 6 gets pushed
on the second loop hovewer, the id to hide is 6 and then 1 gets pushed
And I end up having them both anyway.
Suggestions?
What would you achieve this in an efficient angular way?
thanks a lot
How about this?
https://plnkr.co/edit/hPiOnq7jp4kIP6h8Ox1d?p=preview
<div ng-init="data = [{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}]">
<div ng-repeat="test in data | hideByIds:[2, 4]">
{{ test.id }}
</div>
</div>
You should reuse what you can, in this case the filter filter:
var app = angular.module('app', []);
app.filter( 'hideByIds', function( $filter ) {
return function( input, ids ) {
return $filter('filter')( input, function( it ) {
return ids.indexOf( it.id ) == -1;
} );
}
} );
An alternative is to specify the predicate function on the scope, and simply pass it to the filter in the template.
I need filter for ng-repeat, that explode elements in "general" array, if element exist in "suggest" array (by id field).
$scope.general= [{id: 21323, name: 'alex'}, {id: 8787, name: 'maria'}, {id: 8787, name: 'artem'}];
$scope.suggest = [{id: 21323, name: 'alex'}, {id: 8787, name: 'maria'}];
<div ng-repeat="elem in general">{{elem.name}}</div>
You should create your own custom filter and you'll probably want to use Array.prototype.filter.
You said you wanted to exclude by the property id. The following filler optionally allows specifying a property. If the property is not specified, then the objects are excluded by strict equality (the same method used by the ===, or triple-equals, operator) of the objects.
angular.module('myFilters', [])
.filter('exclude', function() {
return function(input, exclude, prop) {
if (!angular.isArray(input))
return input;
if (!angular.isArray(exclude))
exclude = [];
if (prop) {
exclude = exclude.map(function byProp(item) {
return item[prop];
});
}
return input.filter(function byExclude(item) {
return exclude.indexOf(prop ? item[prop] : item) === -1;
});
};
});
To use this filter in your html:
<div ng-repeat="elem in general | exclude:suggest:'id'">{{elem.name}}</div>
Here is an example jsfiddle:
https://jsfiddle.net/6ov1sjfb/
Note that in your question artem's id matches maria's thus both artem and maria were filtered. I changed artem's id in the plunker to be unique to show that the filter works.
Try this :
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.general = [{
id: 21323,
name: 'alex'
}, {
id: 8787,
name: 'maria'
}, {
id: 8787,
name: 'artem'
}];
$scope.suggest = [{
id: 21323,
name: 'alex'
}, {
id: 8787,
name: 'maria'
}];
$scope.filteredArray = function () {
return $scope.general.filter(function (letter) {
for (i = 0; i < $scope.suggest.length; i++) {
return $scope.suggest[i].id !== letter.id
}
});
};
}
and
<div ng-repeat="elem in filteredArray(letters)">{{elem.name}}</div>
check out the fiddle : http://jsfiddle.net/o2er6msv/
Note: please chk ur id, they are duplicated