M
M
MilanV2021-06-27 19:21:08
Vue.js
MilanV, 2021-06-27 19:21:08

VUE, how to solve the strange behavior of binding two properties?

Good day, I ask you to assist in solving the problem of automatically linking two properties.
There are two components (main and child). Basically, there are two identical arrays of objects (I use to compare the presence of changes):

componentListWorksItems: [],
componentListWorksItemsForComparison: [],

Next, for each object from the first array (componentListWorksItems), I generate a child component:
<tr v-for="(itemWork, indexWork) in componentListWorksItems" :key="indexWork">
                            <td>
                                <work-item-component v-model="componentListWorksItems[indexWork]"
                                    @onUpdateEquipmentQuantityByMonth="handlerUpdateEquipmentQuantityByMonth(indexWork, $event)"
                                    @onChangingTotalsEquipmentItems="handlerOnChangingTotalsEquipmentItems(indexWork, $event)"
                                    @onSaveWorkItemInDatabase="handlerOnSaveWorkItemInDatabase(true,  $event)"
                                    :comparison-list-item="componentListWorksItemsForComparison[indexWork]['pivot']"
                                    :index="indexWork"
                                />
                            </td>
                        </tr>

I bind changes in the child component with the unit of the first array of the main component as follows:
handlerOnChangingTotalsEquipmentItems(workItemIndex, {newSumEquipment, yearLaborCost}) {
this.$set(this.componentListWorksItems[workItemIndex]['pivot'], 'year_estimated_quantity', newSumEquipment);
this.$set(this.componentListWorksItems[workItemIndex]['pivot'], 'year_labor_cost', yearLaborCost);
}

Checking to compare changes in a child component is done as follows:
computed: {
        isChanged: function () {
            return JSON.stringify(this.value['pivot']) !== JSON.stringify(this.comparisonListItem);
        }

Before saving the data to the server, everything works as expected
I save the data to the server, I get the result (an object unit to insert into the array)
I insert a fresh record into both arrays while maintaining reactivity:
updateSingleWorkItemInLocalListFromDatabase(workItemIndex, workItemData) {
            this.$set(this.componentListWorksItems[workItemIndex], 'pivot', workItemData);
            this.$set(this.componentListWorksItemsForComparison[workItemIndex], 'pivot', workItemData);
        }

After this manipulation, the problem begins:
When the data in the child component changes, along with the unit from the first array (componentListWorksItems), the same unit in the second array (componentListWorksItemsForComparison) also changes

Answer the question

In order to leave comments, you need to log in

2 answer(s)
ⓒⓢⓢ, 2021-06-27
@MilanV

After this manipulation, the problem begins:

the full implementation is not visible - but if we assume that an object is pushed into the arrays, then make a separate copy of the object for each array, through the same "JSON.stringify \ parse"
because not the object itself gets into the array, but only a link to this an object.
Because of this - changing an object by reference in one of the array leads to a change in the object in another array.
in fact, the same object is in two arrays
upd
and the isChanged getter you have turned out to be weakly resistant to changes. If the order of the fields in the object changes, then there may be an unexpected result:
// два объекта с одинаковыми данными
let a = { a: 1, b: 1 }
let b = { b: 1, a: 1 }
let isChange = JSON.stringify(a) !== JSON.stringify(b);
// isChange будет равно true
// потому что строка будет отличаться из-за разной позиции свойств объекта

M
MilanV, 2021-06-27
@MilanV

because the array does not get the object itself, but only a reference to this object.

Thank you! Gave me the right direction. Currently, changing the locations of fields in different arrays is not possible. The object has a lot of fields, I see no reason to keep track of them separately.
I did this by copying the object:
updateSingleWorkItemInLocalListFromDatabase(workItemIndex, workItemData) {
            let workItemDataForComparison = Object.assign({}, workItemData);
            this.$set(this.componentListWorksItems[workItemIndex], 'pivot', workItemData);
            this.$set(this.componentListWorksItemsForComparison[workItemIndex], 'pivot', workItemDataForComparison);
        }

In the case of processing the results of a bulk save action, I do this:
updateAllWorksItemsInLocalListFromDatabase(worksItemsData) {
            let worksItemsDataForComparison = JSON.parse(JSON.stringify(worksItemsData));
            this.componentListWorksItems = worksItemsData;
            this.componentListWorksItemsForComparison = worksItemsDataForComparison;
        }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question