I have a simple button that when clicked, it will filter a list and return the filtered list:
var originalArray = [{name: "A", number: 1},{name: "B", number: 2},....]
And here is the filter function
function filterList(filterName, filterNumber) {
var filteredList = angular.copy(originalArray);
filteredList = filteredList.filter(function(item){
return item.name === name
}
return filteredList
}
My question is am I using the right way to implement this feature? suppose that user clicks search button 10000 times ! do I have a 10000 copy of my originalArray?
As filter returns just an array, use that instead and you won't need to use angular.copy
function filterList(filterName, filterNumber) {
return originalArray.filter(function(item){
return item.name === name
}
}
That said there are better ways of doing this if you're doing this from a view. Angular already has built in tools for filtering.
As str commented - you don't need to copy the array, filter returns you a new array with only the appropriate items.
You should take a look at ngFilter - there is an example there and it looks very much what you are looking for, effortless.
Related
so I am trying to make an app that has two search criterias. The front-end app basically fetches data and you have two search bars to filter out the incoming data.
One search is by name and the other is by school name, the tricky part is that the either of the search also takes into account if there is some value in the other search parameter.
For example, if you search for "California University" and "Bob", you should get only Bobs that go to California University to render on the screen. But it seems like right now my DOM only renders the most recent search Ive made. What is the best way to go about a filter that filters both student name and school name using an event listener (keyup) on the search inputs?
searchByNameInput.addEventListener("keyup", (e) => {
const filterNameArray = studentArray.filter((student) => {
// code here to filter students with this name and render it on DOM
}
}
searchBySchoolName.addEventListener("keyup", (e) => {
//filters students who go to this school and render it on DOM
}
}
Write a single filtering function that checks both inputs, and call it from both event listeners.
function filterStudents() {
const nameFilter = searchByNameInput.value;
const schoolFilter = searchBySchoolName.value;
const filterArray = studentArray.filter(student =>
(nameFilter == '' || student.name.includes(nameFilter) &&
(schoolFilter == '' || student.school.includes(schoolFilter))
}
searchByNameInput.addEventListener("keyup", filterStudents);
searchBySchoolNameInput.addEventListener("keyup", filterStudents);
first filter your object and please try it include() method instead of filter().
as a above example
here filterData is my new filtered object and stu_data is my array.
get all search value from search input.
Example:-
var filterData = stu_data.filter((stu_filter) => {
return (stu_filter.firstname.toLowerCase().includes(filter) ||
stu_filter.lastname.toLowerCase().includes(filter))})
I hope this is help for you!
happy coding :)
I built a custom component that filters an array of objects. The filter uses buttons, sets from active to non-active and allows more than one option on/off at the same time.
StackBlitz of my attempt - https://stackblitz.com/edit/timeline-angular-7-ut6fxu
In my demo you will see 3 buttons/options of north, south and east. By clicking on one you make it active and the result should include or exclude a matching "location" either north, south and east.
I have created my methods and structure to do the filtering, I'm struggling with the final piece of logic.
So far I have created a method to create an array of filtered locations depending on what the user clicks from the 3 buttons.
Next this passes to my "filter array" that gets the logic that should compare this filtered array against the original to bring back the array of results that are still remaining.
Its not quite working and not sure why - I originally got this piece of functionality working by using a pipe, but fore reasons do not want to go in that direction.
//the action
toggle(location) {
let indexLocation = this.filteredLocations.indexOf(location);
if (indexLocation >= 0) {
this.filteredLocations = this.filteredLocations.filter(
i => i !== location
);
} else {
this.filteredLocations.push({ location });
}
this.filterTimeLine();
}
// the filter
filterTimeLine() {
this.filteredTimeline = this.timeLine.filter(x =>
this.contactMethodFilter(x)
);
}
//the logic
private contactMethodFilter(entry) {
const myArrayFiltered = this.timeLine.filter(el => {
return this.filteredLocations.some(f => {
return f.location === el.location;
});
});
}
https://stackblitz.com/edit/timeline-angular-7-ut6fxu
Sorry for my expression but u have a disaster in your code. jajaja!. maybe u lost that what u need but the logic in your functions in so wrong. comparing string with objects. filter a array that filter the same array inside... soo u need make a few changes.
One:
this.filteredLocations.push({location});
Your are pushing object. u need push only the string.
this.filteredLocations.push(location);
Two:
filterTimeLine() {
this.filteredTimeline = this.timeLine.filter(x =>
this.contactMethodFilter(x)
);
}
in this function you filter the timeLine array. and inside of contactMethodFilter you call filter method to timeLine again....
See a functional solution:
https://stackblitz.com/edit/timeline-angular-7-rg7k3j
private contactMethodFilter(entry) {
const myArrayFiltered = this.timeLine.filter(el => {
return this.filteredLocations.some(f => {
return f.location === el.location;
});
});
}
This function is not returning any value and is passed to the .filter
Consider returning a boolean based on your logic. Currently the filter gets undefined(falsy) and everything would be filtered out
Beginner in Angular, so it might sound a little silly question, but couldn't find an answer yet.
I have two select boxes -
one which describes a module which I use as ng-model=module ([x,y,z]).
The second one is an array which in each index I have an array with 3 attributes - id, name and module( [1, "first", x])
I am using ng-repeat for my second select box and I want to filter according to the module and the third index.
Basically, it's something like that: "option in options | filter: module === secondbox[2]", but obviously I'm doing something wrong, maybe by syntax.
Please assist me to execute it right. Thanks!
I think it would be best to write a custom filter for this:
.filter('moduleMatch', function() {
return function(items, module, itemIndex, moduleIndex) {
let out = [];
// make sure a filter value was supplied
if (module) {
items.forEach(i => {
if (i[itemIndex] === module[moduleIndex]) {
out.push(i);
}
});
// return the items that matched the filter value
return out;
}
// no filter value was supplied - return the unfiltered collection
return items;
}
})
Then use it in the second select:
"option in options | moduleMatch: module:2:2"
I have a complex object (a user object) that has nested arrays and nested objects within it.
I have a search filter that is relatively complicated as well (checkboxes determining which items are returned, along with a search input).
Currently I search in an object like so:
for(var key in item){
if(item[key] && item[key].length && String(item[key]).toLowerCase().indexOf($rootScope.filt.searchFilter.toLowerCase()) !== -1){
realSave = true;
}
}
However, this only works for the first layer of objects within an item; I need to also search for objects within objects.
How can i do this? Is this a simpler way than the above? (Note, I can't just use ng-repeat="item in items | searchFilter" as this needs to also parse checkboxes and return values accordingly.
Try
realSave = (JSON.stringify(item).indexOf($rootScope.filt.searchFilter.toLowerCase()) !== -1)
(It's a long line, scroll to the right)
It will transform your whole object into a single string, then you can search for the sub-string you're looking for anywhere inside it.
You can use angular filter like this:
app.controller('MainCtrl', function($scope, $filter) {
$scope.a = [{name : 'pit'}, {name : {a : 'pit'}}, {name : { a : { b : 'pit'}}}];
$scope.find = $filter('filter')($scope.a, 'pit');
});
http://plnkr.co/edit/TenLILkXJ0zwqMVtAj35?p=preview
I have a collection of movies that sit under categories, but I have a view that is suppose to show them all.
When I'm showing all, I have a few duplicates because these movies are in multiple categories.
I am trying to use this code in the helper (client side).
I've found this code that gets me all the titles without duplicates:
var distinctMovies = _.uniq(Movies.find({}, {
sort: {"title": 1},
}).fetch().map(function(x) {
return x.title;
}), true);
This seems to work in removing the duplications because I get an array of 241 titles instead of 251.
However, I want an array with whole objects, instead of an array with only the titles, but when I switch x.title per x I get the same 251 items.
I am trying to change this code to get the whole movie object and also trying not to run additional loops.
How to achieve this?
According to _.uniq documentation:
If you want to compute unique items based on a transformation, pass an iteratee function.
Do this:
_.uniq(Movies.find({}, { sort: { title: 1 } }).fetch(), function (movie) {
return movie.title;
});
It works for me:
Template.theater_list.theater=function(){
var cities = _.uniq(Theater.find({}, {sort: {city:1}, fields: {city:true}}).fetch().map(function(x) {
return x.city
}),true);
return cities;