Tengo una matriz de objetos que tiene una matriz interna que debe filtrarse y devolver una matriz basada en las coincidencias de ambos. search es un evento (de entrada), que se ejecuta con cada pulsación de tecla. enlace de stackblitz stackblitz
list = [ { id: 'abc', data: [ { key: '1', value: 'car' }, { key: '2', value: 'bus' }, { key: '3', value: 'bike' }, { key: '4', value: 'truck' }, { key: '5', value: 'jeep' }, ], }, { id: 'def', data: [ { key: '1', value: 'car' }, { key: '2', value: 'bicycle' }, { key: '3', value: 'train' }, { key: '4', value: 'aeroplane' }, { key: '5', value: 'jeep' }, ], }, ]; handleSearch = (event) => { if (event.target.value.length > 0) { const item = this.list[0].data.filter((items) => items.value.toLowerCase().includes(event.target.value.toLowerCase()) ); this.list[0].data = item; } else { this.list[0].data = this.orgList; } };esperar salida
input = car output = [ { id: 'abc', data: [ { key: '1', value: 'car' }, ], }, { id: 'def', data: [ { key: '1', value: 'car' }, ], }, ]; input = truck output = [ { id: 'abc', data: [ { key: '4', value: 'truck' }, ], }, ]; const list = [{id: 'abc',data: [{ key: '1', value: 'car' },{ key: '2', value: 'bus' },{ key: '3', value: 'bike' },{ key: '4', value: 'truck' },{ key: '5', value: 'jeep' },],},{id: 'def',data: [{ key: '1', value: 'car' },{ key: '2', value: 'bicycle' },{ key: '3', value: 'train' },{ key: '4', value: 'aeroplane' },{ key: '5', value: 'jeep' },],},]; function search(arr, searchVal) { return arr.map((item) => { const data = item.data.filter(({ value }) => value === searchVal); return { ...item, data }; }) .filter(({ data }) => data.length); } console.log(search(list, 'car')); console.log(search(list, 'truck')); .as-console-wrapper { max-height: 100% !important; top: 0 }demostración angular
Sé que podría estar un poco fuera del alcance de sus requisitos aquí, pero simplemente pensé que sería más fácil hacerlo así.
Solo pensé que podría ser algo más escalable de esta manera, si primero aplana la estructura, porque por el bien de los argumentos, digamos que su estructura de datos debe volverse más y más compleja con el tiempo, IDK, los requisitos comerciales cambian. Al menos si tiene alguna capa de abstracción para administrar eso, puede filtrar una matriz de objetos de manera bastante simple, como lo he hecho a continuación.
Dependiendo de sus necesidades, es posible que ni siquiera necesite aplanar la estructura, es solo mi opinión y mi experiencia afirma que esta es una solución más fácil y más fácil de mantener para escalar. Si su estructura de datos evoluciona con la complejidad, donde puede haber estructuras anidadas, siempre puede considerar usar alguna pequeña función recursiva inteligente para aplanar su estructura.
También vale la pena señalar que he agregado algo de validación a la función de search , aunque probablemente no sea un requisito, no es una mala idea incluir dicha lógica, donde podría actualizar el estado en su modelo de vista. Podría incluir algo como una notificación de brindis, indicando que el usuario ha proporcionado un término de búsqueda no válido, podría estar haciendo una solicitud a un servidor para obtener estos datos y podría decir que no hubo resultados, etc. Creo que obtiene el ¿ocurrencia?
Espero que haya ayudado y lo siento si me he vuelto un poco exagerado. 😅
const list = [ { id: 'abc', data: [ { key: '1', value: 'car' }, { key: '2', value: 'bus' }, { key: '3', value: 'bike' }, { key: '4', value: 'truck' }, { key: '5', value: 'jeep' }, ], }, { id: 'def', data: [ { key: '1', value: 'car' }, { key: '2', value: 'bicycle' }, { key: '3', value: 'train' }, { key: '4', value: 'aeroplane' }, { key: '5', value: 'jeep' }, ], }, ]; const flattenStructure = data => { return data.reduce((accumulator, item) => { const items = item.data.reduce((vehicles, vehicle) => { const modified = { ...vehicle, id: item.id }; return vehicles.concat(modified); }, []); return accumulator.concat(items); }, []); }; const search = (array, term) => { const invalidTerm = term == null || typeof term != 'string' || term.replace(/ /g, '') == ''; const invalidArray = array == null || !Array.isArray(array); if (invalidTerm || invalidArray) { console.log("Invalid arguments provided."); return array; } return flattenStructure(array).filter(vehicle => { const match = vehicle.value.toLowerCase() == term.toLowerCase(); const contains = vehicle.value.toLowerCase().indexOf(term.toLowerCase()) > -1; return match || contains; }); }; console.log(search(list, 'car')); console.log(search(list, 'truck'));En términos generales, cuando se trata de filtrado, evite usar la misma matriz original para mostrar los resultados filtrados en la plantilla.
Con respecto a la función de filtrado, esto debería funcionar:
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent implements OnInit { public list: any; public orgList: any; public filteredList: any; ngOnInit() { this.list = this.orgList = [ { id: 'abc', data: [ { key: '1', value: 'car' }, { key: '2', value: 'bus' }, { key: '3', value: 'bike' }, { key: '4', value: 'truck' }, { key: '5', value: 'jeep' }, ], }, { id: 'def', data: [ { key: '1', value: 'car' }, { key: '2', value: 'bicycle' }, { key: '3', value: 'train' }, { key: '4', value: 'aeroplane' }, { key: '5', value: 'jeep' }, ], }, ]; } filterData = (dataItem, term: string) => { return dataItem.value.toLowerCase().indexOf(term.toLowerCase()) !== -1; }; handleSearch = (event) => { if (event.target.value.length === 0) { this.filteredList = []; return; } const term = event.target.value; const temp = this.list.filter((fullItem) => fullItem.data.filter((dataItem) => this.filterData(dataItem, term)) ); this.filteredList = temp .map((fullItem) => ({ ...fullItem, data: fullItem.data.filter((dataItem) => this.filterData(dataItem, term) ), })) .filter((fullItem) => fullItem.data.length > 0); }; }