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.

1 Answer 1

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);
}
Sign up to request clarification or add additional context in comments.

1 Comment

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!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.