0

I have an array of objects, each object has a list of id, like this:

objects: [
    {
        ids: [1,2],
        name: 'alpha'
    },
    {
        ids: [2,3],
        name: 'bravo'
    }
]

I want to list them all down, like for each single id, which is 1, 2 or 3, I list all the objects contains that id in its ids property, and create a property called id for each listed object to hold that single id, like this:

single id array: [1, 2, 3]

id = 1 => [alpha (id = 1)]
id = 2 => [alpha (id = 2), bravo (id = 2)]
id = 3 => [bravo (id = 3)]

But when I run it, all listed objects gets only the last id in their ids which is 2 or 3 only, although I looped through the single id array 1, 2, 3 and assigned each of the id.

single id array: [1, 2, 3]

id = 1 => [alpha (id = 2)]
id = 2 => [alpha (id = 2), bravo (id = 3)]
id = 3 => [bravo (id = 3)]

Here is an example:

new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue.js!',
    
    listData: [
     {
       ids: [1,2],
       name: 'alpha'
      },
      {
       ids: [1,2],
       name: 'bravo'
      },
      {
       ids: [1,2,3],
       name: 'gamma'
      },
      {
       ids: [3,4],
       name: 'delta'
      }
    ],
    
    detailData: []
  },
  created() {
   var ids = [];
    
    this.listData.forEach(data => {
     data.ids.forEach(id => {
       if(!ids.includes(id)) ids.push(id);
      })
    })
    
    ids.forEach(id => {
     this.listData.forEach(data => {
       if(data.ids.includes(id)) {
         var obj = data;
          obj.id = id;
          this.detailData.push(obj);
        }
      })
    })
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>Name</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(data, idx) in detailData">
        <td>{{ data.id }}</td>
        <td>{{ data.name }}</td>
        
      </tr>
    </tbody>
  </table>
</div>

JS Fiddle

I don't know why or how this happened. Hope you guys can find out the problem and explain this for me. Thanks a lot!

Sorry for my bad English.

Brother Eye
  • 689
  • 1
  • 11
  • 27

1 Answers1

1

I think your problem is that objects are passed by reference and when you add an object to detailData it is a reference to that object which you are changing later. If you copy the object before adding it to detailData I think it would solve your problem:

new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue.js!',
    
    listData: [
     {
       ids: [1,2],
       name: 'alpha'
      },
      {
       ids: [1,2],
       name: 'bravo'
      },
      {
       ids: [1,2,3],
       name: 'gamma'
      },
      {
       ids: [3,4],
       name: 'delta'
      }
    ],
    
    detailData: []
  },
  created() {
   var ids = [];
    
    this.listData.forEach(data => {
     data.ids.forEach(id => {
       if(!ids.includes(id)) ids.push(id);
      })
    })
    
    ids.forEach(id => {
     this.listData.forEach(data => {
       if(data.ids.includes(id)) {
          var obj = data;
          obj.id = id;
          this.detailData.push({...obj}); // ... Makes a shallow copy of the object
        }
      })
    })
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>Name</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(data, idx) in detailData">
        <td>{{ data.id }}</td>
        <td>{{ data.name }}</td>
        
      </tr>
    </tbody>
  </table>
</div>

Note: This only creates a shallow copy which means if your id is in a nested object it will not work. See this answer.

If you don't want to make a copy you could just create an object with the properties you need instead:

if(data.ids.includes(id)) {
    var obj = {id: id, name: data.name};
    this.detailData.push(obj);
}

You can also use JSON if you want a deep copy:

if(data.ids.includes(id)) {
    var obj = JSON.parse(JSON.stringify(data));
    obj.id = id;
    this.detailData.push(obj);
}
anbcodes
  • 849
  • 6
  • 15
  • Yes, a shallow copy of the object does solve the problem. I also do think of this as a reference thing. But when the objects in the array have a tons of field and all the fields of each object is not all identical, then this sole-copy becomes really painful. But thank you! – Brother Eye Dec 06 '19 at 01:00