I have a store setup that has multiple arrays
I'm trying to search all arrays at once, via a textfield.
I can get this done, by calling a selector function on keyup, that filters the 4 arrays and pushes to a new array.
I've thought about merging all the arrays to one array before filtering, but I want to keep the results separate, as they are going to be displayed in categories.
Just trying to see if I can streamline the performance at all and if there's a more concise way of doing this, in case I need to do something similar with larger arrays.
my textField function:
this.renderer.listen(this.serachField.nativeElement, 'keyup', (event) => {
if (this.serachField.nativeElement.value.length < 3) { return; }
this.store.pipe(select(search(this.serachField.nativeElement.value)),take(1))
.subscribe(data => {
console.log(data);
});
})
The selector function:
export const search = (searchString: string): any => {
return createSelector(
appState,
(state: AppState) => {
let arr: any = [];
let s = searchString.toUpperCase();
const comics = state.comics.results.filter((item: Comic) => {
let title = item.title.toUpperCase();
console.log(title);
return title.includes(s);
});
const music = state.music.items.filter((item: Album) => {
let title = item.name.toUpperCase();
console.log(title);
return title.includes(s);
});
const movies = state.movies.results.filter((item: Movie) => {
let title = item.title.toUpperCase();
console.log(title);
return title.includes(s);
});
const games = state.games.filter((item: Game) => {
let title = item.title.toUpperCase();
console.log(title);
return title.includes(s);
});
arr.push(comics, music, movies, games);
return arr;
}
);
};
EDIT: After @GustavMH correct answer I had to slightly change the code to be a little more dynamic in terms of the array naming as follows
export const search = (searchString: string): any => {
return createSelector(
appState,
(state: any) => {
let s = searchString.toUpperCase();
const keys = [{state: "comics", item: "title", array: 'results'},
{state: "music", item: "name", array: 'items'},
{state: "movies", item: "title", array: 'results'},
{state: "games", item: "title", array: ''}]
return keys.map((key) => {
let arr = key.array ? state[key.state][key.array] : state[key.state];
return arr.filter((item: any) => {
const title = item[key.item].toUpperCase();
console.log(item);
return title.includes(s);
})})
}
);
};
This should implement the selector function with less code and make it more adaptable to kinds of data, if needed you can specify a more precise type in the filter function.
export const search = (searchString: string): any => {
return createSelector(
appState,
(state: AppState) => {
let s = searchString.toUpperCase();
const keys = [{state: "comics", item: "title"},
{state: "music", item: "name"},
{state: "movies", item: "title"},
{state: "games", item: "title"}]
return keys.map(key => state[key.state].results.filter((item: any) => {
const title = item[key.item].toUpperCase();
console.log(title);
return title.includes(s);
}))
}
);
};