nmy
nmy

Reputation: 498

Filtering objects array by nested values

I'm trying to filter this objects array and keep the original one aside.

{"departments":
 [
  {
    “name": “AAA",
    “selected”: true,            
    "courses": [
        {
            "name": “course1",
            “selected”: true,
            “titles”: 
            [{
              "name": “title1",
              “selected”: true
             },
             {
             "name": “title2",
             “selected”: false
            }]
         },
         {
            "name": “course2",
            “selected”: false,
            “titles”: 
            [{
              "name": “title1",
              “selected”: false
             }]   
          }
    ]
 },
 {
    “name": “BBB",
    “selected”: false,
    "courses": [{...}]

 {...}    
 ]
}

I want to find all the selected departments, courses and titles. And it should be in the same format. I tried with below code, but it change original data. I want to keep that aside too.

const depts = departments.filter((dept: any) => {
    if (dept.selected) {
      dept.courses = dept.courses.filter((course: any) => {
        if (course.selected) {
          if (course.titles) {
            course.titles = course.titles.filter(({selected}: any) => selected);
          }
          return true;
        }
        return false;
      });
      return true;
    }
    return false;
  });

What would be considered the best solution in this case?

Upvotes: 0

Views: 311

Answers (4)

Mateus Gonçalves
Mateus Gonçalves

Reputation: 706

I don't know if you prefer an API false. Here is my tip:

You can to use an API Json Server.

Install JSON Server

npm install -g json-server

Create a db.json file with some data

{
  "posts": [
    { "id": 1, "title": "json-server", "author": "typicode" }
  ],
  "comments": [
    { "id": 1, "body": "some comment", "postId": 1 }
  ],
  "profile": { "name": "typicode" }
}

Start JSON Server

json-server --watch db.json

Now if you go to http://localhost:3000/posts/1, you'll get

{ "id": 1, "title": "json-server", "author": "typicode" }

you can search your array of objects using various shapes and it will come filtered. More about the API here: https://github.com/typicode/json-server

(Use a filter to do your searches on the Angular, it will bring you right what you need, use a method inside your component)

Upvotes: 0

Doug Coburn
Doug Coburn

Reputation: 2575

const filterSelected = obj => {
  return {
    ...obj,
    departments: obj.departments.map(dep => {
      return {
        ...dep,
        courses: dep.courses.map(course => {
          return {
            ...course,
            titles: course.titles.filter(title => title.selected),
          };
        }).filter(course => course.selected),
      };
    }).filter(dep => dep.selected),
  };
}

const all = {
 departments: [
  {
   name: "AAA",
   selected: true,            
   courses: [
    {
     name: "course1",
     selected: true,
     titles: [
      {
       name: "title1",
       selected: true
      }, {
       name: "title1",
       selected: false
      }
     ]
    }, {
     name: "course2",
     selected: false,
     titles: [
      {
       name: "title1",
       selected: false
      }
     ]
    },
   ]
  }
 ]
};

console.log(filterSelected(all));

Upvotes: 0

Slai
Slai

Reputation: 22876

Shorter alternative can be to use the JSON.parse reviver parameter :

var arr = [{ name: "AAA", selected: true, courses: [{name: "course1", selected: true, titles: [{ name: "title1", selected: true }, { name: "title1", selected: false }]}, { name: "course2", selected: false, titles: [{ name: "title1", selected: false }]}]}]

var result = JSON.parse(JSON.stringify(arr), (k, v) => v.map ? v.filter(x => x.selected) : v)

console.log( result )

Upvotes: 1

ysf
ysf

Reputation: 4854

your filtering logic seems to be correct. only problem is that code changes original array. in order to overcome this problem just create a deep clone of original array and run filtering logic on it

  filterArray() {
    const clone = JSON.parse(JSON.stringify(this.departments));
    const depts = clone.filter((dept: any) => {
      if (dept.selected) {
        dept.courses = dept.courses.filter((course: any) => {
          if (course.selected) {
            if (course.titles) {
              course.titles = course.titles.filter(({ selected }: any) => selected);
            }
            return true;
          }
          return false;
        });
        return true;
      }
      return false;
    });

    console.log(depts);
  }

here is a demo https://stackblitz.com/edit/angular-xx1kp4

Upvotes: 1

Related Questions