Home > front end >  VueJS2: How to update objects in an array and pass back to parent?
VueJS2: How to update objects in an array and pass back to parent?

Time:03-08

I have a parent component that is passing down some API data to a child component in order to pre-populate some input fields. When the user changes some of this data on the child component, that child component emits the data back to the parent where we will process it for server submission on user form submit.

To handle the updates for processing, I am sending the child data back as an object which the parent stores in an array (array of objects). This array is what I am sending to the server for processing.

I am struggling with how to update object properties in an array of objects.

Codesandbox: https://codesandbox.io/s/romantic-mestorf-yc0i1h?file=/src/components/Parent.vue

Let me explain in detail. I have 3 components:

<App>
    <Parent>
        <Child />
    </Parent>
</App>

App.vue:

    <template>
  <div id="app">
    <form @submit.prevent="submitForm()">
      <Parent
        :localShortNames="formValues.localShortNames"
        @save-form-data="saveFormData"
      />
      <button type="submit">Submit</button>
    </form>
  </div>
</template>

<script>
import Parent from "./components/Parent.vue";
import data from "./assets/data.json"; // <--- will be an actual API request
export default {
  components: {
    Parent,
  },
  data() {
    return {
      formValues: {
        localShortNames: data,
      },
    };
  },
  methods: {
    saveFormData(x) {
      // TO DO
    },
    submitForm() {
      // TO DO: save data to server
    },
  },
};
</script>

Parent.vue:

<template>
  <div>
    <h5>List of Data</h5>
    <Child
      v-for="item in localShortNames"
      :key="item.localSnameID"
      :localShortName="item"
      @save-form-data="saveFormData"
    />
  </div>
</template>

<script>
import Child from "./Child.vue";
export default {
  props: {
    localShortNames: {
      type: Array,
    },
  },
  components: {
    Child,
  },
  data() {
    return {
      newLocalShortNamesArr: this.localShortNames,
    };
  },
  methods: {
    saveFormData(x) {
      let elementId = (el) => el.localSnameID === x.localSnameID;

      const newArr = this.newLocalShortNamesArr.map((obj) => {
        if (elementId) {
          // I need to update the existing object in newLocalShortNamesArr with updated user submitted properties
          // ...
        } else {
          // item does not exist, lets push it to newLocalShortNamesArr
          // TO DO LATER: create "add new data" button for adding new objects to array
    },
  },
},
},
}
</script>

Child.vue:

<template>
  <div>
    <label for="name-input">Name:</label>
    <input
      type="text"
      id="name-input"
      v-model="formValues.name"
      @input="$emit('save-form-data', formValues)"
    />

    <label for="dialect-input">Dialect:</label>
    <input
      type="text"
      id="dialect-input"
      v-model="formValues.iso6393Char3Code"
      @input="$emit('save-form-data', formValues)"
    />
  </div>
</template>

<script>
export default {
  props: {
    localShortName: {
      type: Object,
    },
  },
  data() {
    return {
      formValues: {
        localSnameID: this.localShortName
          ? this.localShortName.localSnameID
          : null,
        name: this.localShortName ? this.localShortName.name : null,
        iso6393Char3Code: this.localShortName
          ? this.localShortName.iso6393Char3Code
          : null,
      },
    };
  },
};
</script>

Question: How to handle the update of objects in an array and "overwrite" those properties (name, and iso6393Char3Code) if the same id exists in the original array?

In the parent.vue, I was thinking of doing something like this, but I don't know:

    saveFormData(x) {
      // console.log(x);
      let elementId = (el) => el.localSnameID === x.localSnameID;

      const newArr = this.newLocalShortNamesArr.map((obj) => {
        if (elementId) {
          // I need to update the existing object in newLocalShortNamesArr with updated user submitted properties
          // ...
        } else {
          // item does not exist, lets push it to newLocalShortNamesArr
          // ...
        }
      });

Would Object.assign be better here vs map()? All I am trying to do is provide an array to the API called localShortNames that contains all the objects whether they have been updated or not. Hope this makes sense!

I have a codesandbox here with the above code: https://codesandbox.io/s/romantic-mestorf-yc0i1h?file=/src/components/Parent.vue

CodePudding user response:

The first problem in Parent Component in saveFormData if you want to check if the object exist in array or not you can use findIndex() method it loop through array and return the object index if exists else return -1 if not exist if exist objectIndex will be greater than -1 and update that index with the object from child component and then we emit the array after updated to App.vue component

  saveFormData(x) {
      const objectIndex = this.newLocalShortNamesArr.findIndex((ele) => {
            return ele.localSnameID == x.localSnameID
      });
      
      if (objectIndex > -1) {
        // the object exists
        this.newLocalShortNamesArr[objectIndex] = { ...x };
      } else {
        // this case need new html form for add new item in array 
        this.newLocalShortNamesArr.push(x);
      }
      this.$emit("save-form-data", this.newLocalShortNamesArr);
  },

in App.vue component we update the main array with the data that emitted from parent component

 saveFormData(x) {
      this.formValues.localShortNames = [...x];
 },

i updated the codesandbox with the new code .. I hope the solution will be clear to you

https://codesandbox.io/s/dreamy-clarke-v04wfl?file=/src/App.vue:595-734

  • Related