Morton
Morton

Reputation: 5760

How to set boolean property value if object id is in another array of objects?

I have two arrays selectedData and allServices

selectedData = [
 { id: 5 },
 { id: 6 }
];

allServices = [
 { id: 3, selected: false },
 { id: 4, selected: false },
 { id: 5, selected: false },
 { id: 6, selected: false },
 { id: 7, selected: false },
];

I use the function to compare and change allServices structure.

const changeStructure = (selectedData, allServices) => {
  selectedData.services.map((_item, index) => {
    allServices.map((value, i) => {
      if (value.id === _item.id) {  
        allServices[i].selected = true;
      } else {
        allServices[i].selected = false;
      }
    }) 
  })
  console.log('final allServices', allServices);
  return allServices;
}

console.log final allServices is

[
  { id: 3, selected: false },
  { id: 4, selected: false },
  { id: 5, selected: false },
  { id: 6, selected: true },
  { id: 7, selected: false },
];

I thought my allServices should be

[
  { id: 3, selected: false },
  { id: 4, selected: false },
  { id: 5, selected: true },
  { id: 6, selected: true },
  { id: 7, selected: false },
];

I have no idea why this is happening. Any suggestion would be appreciated.

Upvotes: 0

Views: 669

Answers (7)

Nick Parsons
Nick Parsons

Reputation: 50684

Your issue is that each time you iterate over your selectedData array using the outer .map() you're changing all the item ids you previously set to true back to false. Instead, you should use .map() by returning a new item each time you iterate. This can be done efficiently by creating a new Set of all ids which are in your selectedData and changing the selected property based on whether the set .has() the id of the current object:

const selectedData = [ { id: 5 }, { id: 6 } ];
const allServices = [ { id: 3, selected: false }, { id: 4, selected: false }, { id: 5, selected: false }, { id: 6, selected: false }, { id: 7, selected: false } ];

const lut = new Set(selectedData.map(({id}) => id));
const res = allServices.map(obj => ({...obj, selected: lut.has(obj.id)}));
console.log(res);

Upvotes: 4

adiga
adiga

Reputation: 35222

It will only consider the last item in selectedData array because every selected: true value set is being reset by the else block.

Another option is to create a Set of all the ids from selectedData. Loop through allServices and update the selected value based on whether the Set has the current object's id

const selectedData=[{id:5},{id:6}],
      allServices=[{id:3,selected:false},{id:4,selected:false},{id:5,selected:false},{id:6,selected:false},{id:7,selected:false},];
      
const set = new Set(selectedData.map(o => o.id));
allServices.forEach(o => o.selected = set.has(o.id))

console.log(allServices)

Upvotes: 2

TopW3
TopW3

Reputation: 1527

Here is my solution. It looks quite simple.

const changeStructure = (selectedData, allServices) => {
    allServices.forEach(item => {
        item.selected = selectedData.some(sel => sel.id === item.id);
    });

    console.log('final allServices', allServices);
    return allServices;
}

Upvotes: 0

Ryan Nghiem
Ryan Nghiem

Reputation: 2438

Can you try simple code:

const selectedData = [
 { id: 5 },
 { id: 6 }
];

const allServices = [
 { id: 3, selected: false },
 { id: 4, selected: false },
 { id: 5, selected: false },
 { id: 6, selected: false },
 { id: 7, selected: false }
];

const res = allServices.map(service => ({...service , selected: selectedData.findIndex(selected => selected.id === service.id) >-1 }));
console.log(res);

Upvotes: 0

Tân
Tân

Reputation: 1

You can make a loop with allServices and compare the id in each element with the id of elements inside selectedData using forEach function. Like this:

var selectedData = [
 { id: 5 },
 { id: 6 }
];

var allServices = [
 { id: 3, selected: false },
 { id: 4, selected: false },
 { id: 5, selected: false },
 { id: 6, selected: false },
 { id: 7, selected: false },
];

allServices.forEach(x => x.selected = selectedData.find(a => a.id === x.id) !== undefined);

console.log(allServices);

Upvotes: 1

Amadan
Amadan

Reputation: 198324

There are no breaks. You inspect all possible pairs, and assign to allServices[i].selected once for each value in selectedData. So allServices[3].selected is assigned with false and again false; allServices[6].selected is assigned with false, then true; but allServices[5].selected is assigned with true, then overwritten by false.

You would want the loops reversed, so that the inner one could be broken out of. Better yet, use some.

const changeStructure = (selectedData, allServices) => {
  allServices.forEach(value => {
    value.selected = selectedData.some(selected => selected.id == value.id)
  })
  console.log('final allServices', allServices);
  return allServices;
}

Upvotes: 1

stud3nt
stud3nt

Reputation: 2143

You need to remove the else block from your code, which is updating the previous ids to false on mismatch.

const changeStructure = (selectedData, allServices) => {
  selectedData.services.map((_item, index) => {
    allServices.map((value, i) => {
      if (value.id === _item.id) {  
        allServices[i].selected = true;
      }
    }) 
  })
  console.log('final allServices', allServices);
  return allServices;
}

Upvotes: 2

Related Questions