简体   繁体   中英

Javascript filtering nested arrays

I'm trying to filter a on a nested array inside an array of objects in an Angular app. Here's a snippet of the component code -

var teams = [
  { name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] }, 
  { name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] }, 
  { name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] }
];

What I'm trying to achieve is if I search for m5 for example my result should be -

var teams = [
  { name: 'Team1', members: [] }, 
  { name: 'Team2', members: [{ name: 'm5' }] }, 
  { name: 'Team3', members: [] }
];

So I've got teams and filteredTeams properties and in my search function I'm doing -

onSearchChange(event: any): void {
  let value = event.target.value;
  this.filteredTeams = this.teams.map(t => {
    t.members = t.members.filter(d => d.name.toLowerCase().includes(value));
    return t;
  })
}

Now this does work to some extent however because I'm replacing the members it's destroying the array on each call (if that makes sense). I understand why this is happening but my question is what would be the best way to achieve this filter?

you were very close, the only thing that you did wrong was mutating the source objects in teams

basically you can use spread operator to generate a new entry and then return a whole new array with new values.

 const teams = [ { name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] }, { name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] }, { name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] } ]; const value = 'm5'; const result = this.teams.map(t => { const members = t.members.filter(d => d.name.toLowerCase().includes(value)); return { ...t, members }; }) console.log(result) 

Check this. Instead of hard coded m5 pass your value.

 const teams = [ { name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] }, { name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] }, { name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] } ]; const filteredTeams = teams.map(team => ({ name: team.name, members: team.members.filter(member => member.name.includes('m5')) })); console.log(filteredTeams); 

You are mutating the original objects, but you could assing new properties to the result object for mapping instead.

 var teams = [{ name: 'Team1', members: [{ name: 'm1' }, { name: 'm2' }, { name: 'm3' }] }, { name: 'Team2', members: [{ name: 'm4' }, { name: 'm5' }, { name: 'm6' }] }, { name: 'Team3', members: [{ name: 'm7' }, { name: 'm8' }, { name: 'm9' }] }], result = teams.map(o => Object.assign( {}, o, { members: o.members.filter(({ name }) => name === 'm5') } )); console.log(result); console.log(teams); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

Try to seperate your filter function first:

const filterTeamMembers = (teams, filterArr) => {
    const useFilter = filterArr.map(x => x.toLowerCase());

    return teams.map(team => ({
        ...team,
        members: team.members.filter(member => useFilter.includes(member.name))
    }))
};
// =========== And then:

onSearchChange(event: any): void {
    let value = event.target.value;
    this.filteredTeams = filterTeamMembers(this.teams, [value]);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM