Vue V-for binding array to wrong components - vuejs2

In my Vuex state I have an object containing an array of orderLines, in my model I access that object using a getter and loop over the orderLines creating for each one a component.
Now when I trigger a remove mutation, I request an update of the order object as well and swap the old with the correct new one. So far so good.. all my components get the new order object and update their lists.
But they do not Create/Recreate the components in the loop they just seem to update the indexes -> resulting in the next problem:
If i remove the top item all the next item's data is bound to the 'removed' component and its state :/
<div v-for="orderLine in order.order_lines">
<order-line :order-line="orderLine" ></order-line>
</div>

Use a key.
<div v-for="orderLine in order.order_lines" :key="orderLine">
<order-line :order-line="orderLine" ></order-line>
</div>
If each order_line has an id that would be an even better key.

Related

Vue.js v-for loop binding items objects in array and update on change

I have a component and am using a v-for loop to loop through and object array at the $root level of my app to populate a list.
In other components in my app I'll EventBus.$emit data to update tables in my database. That means the $root array data updates.
Is there a way to bind or map the v-for list I created to detect and update using the index or another method?
Here is the example loop and example $root data.
I guess I'm hoping there's a way to connect an object in an array by using [index]
<v-list-item-content v-if="this.$root.people">
<div v-for="(item, index) in this.$root.people" :key="item.id">
<div>
<span v-html="this.$root.people[index].value"></span>
</div>
</div>
</v-list-item-content>
My array looks like this.
people:Array[2]
0:Object
event_id:6
submission_values:Array[4]
0:Object
value:"Danny"
1:Object
2:Object
3:Object
I suppose if people is already reactive then you should look at how you update this array. There are some caveats about updating a reactive array in VueJS, please take a look at the official documentation

Using inner component in a loop in Shopware 6 does not persist the values uniquely for each looped component

I am using a v-for over a custom component and passing the item as a prop. But the issue is that each component instance in the loop takes the same item prop. For e.g in the 1st loop a component field has text "abc", then the second looped component also will have the same "abc" text. If I change the text in the 2nd one, it changes in the 1st component too. Is there a way to make the prop unique for each loop ?
For e.g this is the code which calls the inner component:
<template v-for="(businesscase, index) in businessCase.fields">
<custom-case-freetext-field #field-changed="updateFields"
:key="index"
#field-removed="removeFields"
:fields="businessCase.fields"
:index="index">
</custom-case-freetext-field>
</template>
and inside this component I have a basic form
<sw-field :label="$tc('rma.modules.case.freetext.nameLabel')"
:placeholder="$tc('rma.modules.case.freetext.nameLabel')"
required
v-model="fields[index].name">
</sw-field>
<sw-single-select
labelValue="label"
valueProperty="label"
:options="fieldTypes"
:label="$tc('rma.modules.case.freetext.fieldType')"
:placeholder="$tc('rma.modules.case.freetext.fieldType')"
v-model="fields[index].type"
#input="changeType"
required>
</sw-single-select>
If I do :value instead of v-model, the entered value disappears as soon as the element loses focus.
If I use v-model, the data stays there, but then both (or as many are there in the loop) component instances, have data binding between them, so it defeats the purpose of having a loop for multiple components. As seen in the screenshot, I am typing in the 2nd component, but it changes the text for the first one too.
In the above example I am sending the whole array as prop, but I have also tried with individual field element instead of fields
Your are not using the businesscase variable inside your components. And since every component always works on the upper scope property, they will all change the same. Use the innerscope property. If you have problems with reactivity, because you try to mutate props directly work with events emitting the key and the changed value to the upperscope component.

build a v-checkbox list in Vue

I need to build a to-do list with check boxes but instead of using an array that pulls each items as if it was a separate row these are all separate columns. So the object looks like
[{"InterProgramatic":false,"IntraProgramatic":false,"MultiInstitution":false,"Accepted":true,"Rejected":false,"Cancer_Related":true}]
How can I build the Checkboxes using a v-for loop?
my array is simply
statusItems: []
If each item was in a separate row then I can assign a separate id, but is there an easier way to do this in Vue? To save the data I planned on just sending back to the Web API the statusItems object and parsing it there so I was hoping to bind it if possible.
I can use
v-for="(item, index) in statusItems" :key="index"
<v-checkbox
:key="index"
:label="item"
color="success"
v-bind:id="status"
v-model="statusItems[key].checked"
#change="statusChange(statusItems[key])"
>></v-checkbox>
to build the checkboxes but not sure how to bind it. Thanks for the help
Is that what your trying to do ?
https://codesandbox.io/s/vue-template-tkx60?fontsize=14
To bind the v-model, you need to use the array index or the object key.

Vue remove child component with it state

I want delete child component. I use this.rows.splice(index, 1)
When i call this.rows.splice(index, 1) VueJs always remove last component from this.$children and save internal state in component.$data ;
Example is here
`https://jsfiddle.net/abratko/gc7h1r34/3/`
How fix it?
Vue associates each data item with each vnode according to the item's index by default. This results in existing Vue components being reused, but bound to different items, when re-rendering the list after an item was removed from the array.
This is why you should always bind key to a value which uniquely identifies that particular item. In your example, since each item is a unique string you can just bind to that:
<row-component v-for="(row, index) in rows" :key="row">
^^^^^^^^^^

In VueJS, v-for doesn't create discrete items when new data is assigned

Currently, when I have a v-for loop like this:
<li v-for="record in records">
<my-vue-list-item :vue-title="record.title"></my-vue-list-item>
</li>
and I update the data driving the v-for (i.e. assign a new value to records), it doesn't actually create new list items based on the new data. It just updates some of the properties on the list item components components.
Here is a JSFiddle illustrating what I'm talking about. Try expanding one of the buttons (e.g. click "Expand Apple"), then click on "Set 2" to see that even when the list items switch, the component stays expanded.
What's the recommended way of getting around this behavior? I want each new list item (when the data is swapped out) to appear like new. (In the fiddle example, which I load a new set, it should not be already expanded.)
You need to let the Vue components know that the item is different. As far as they know, they're still rendering the same element index from the same list.
You can do this by specifying the key in your v-for iterator...
<li v-for="item in items" :key="item">
https://jsfiddle.net/ahxf44jk/21/