Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update parent model from child component Vue

Tags:

vue.js

I have a very small app that has a donation form. The form walks the user through the steps of filling in information. I have a main component, which is the form wrapper and the main Vue instance which holds all of the form data (model). All of the child components are steps within the donation process. Each child component has input fields that are to be filled out and those field will update the parent model so that I have all of the form data in the parent model when I submit the form. Here is how the components are put together:

<donation-form></donation-form> // Main/Parent component

Inside the donation-form component:

<template>
    <form action="/" id="give">
        <div id="inner-form-wrapper" :class="sliderClass">
            <step1></step1>
            <step2></step2>
            <step3></step3>
        </div>
        <nav-buttons></nav-buttons>
    </form>
</template>

Right now, I am setting the data from the inputs in each child component and then I have a watch method that is watching for fields to update and then I am pushing them to the $root by doing this...

watch: {
    amount() {
        this.$root.donation.amount = this.amount;
    }
}

The problem is that one of my steps I have a lot of fields and I seem to be writing some repetitive code. Also, I'm sure this is not the best way to do this.

I tried passing the data as a prop to my child components but it seems that I cannot change the props in my child component.

What would be a better way to update the root instance, or even a parent instance besides add a watch to every value in my child components?

More examples Here is my step2.vue file - step2 vue file Here is my donation-form.vue file - donation-form vue file

like image 312
dericcain Avatar asked Jan 15 '17 15:01

dericcain


2 Answers

You can use custom events to send the data back.

To work with custom events, your data should be in the parent component, and pass down to children as props:

<step1 :someValue="value" />

and now you want to receive updated data from child, so add an event to it:

<step1 :someValue="value" @update="onStep1Update" />

your child components will emit the event and pass data as arguments:

this.$emit('update', newData)

the parent component:

methods: {
  onStep1Update (newData) {
    this.value = newData
  }
}

Here is a simple example with custom events:
http://codepen.io/CodinCat/pen/QdKKBa?editors=1010


And if all the step1, step2 and step3 contain tons of fields and data, you can just encapsulate these data in child components (if the parent component doesn't care about these row data).

So each child has its own data and bind with <input />

<input v-model="data1" />
<input v-model="data2" />

But the same, you will send the result data back via events.

const result = this.data1 * 10 + this.data2 * 5
this.$emit('update', result)

(again, if your application becomes more and more complex, vuex will be the solution.

like image 162
CodinCat Avatar answered Nov 19 '22 17:11

CodinCat


Personally I prefer having a generic function for updating the parent, when working with forms, instead of writing a method for every child. To illustrate – a bit condensed – like this in the parent:

<template lang="pug">
  child-component(:field="form.name" fieldname="name" @update="sync")
</template>
<script>
export default {
  methods: {
    sync: function(args) { 
      this.form[args.field] = args.value
    }
  }
}
</script>

And in the child component:

<template lang="pug">
  input(@input="refresh($event.target.value)")
</template>
<script>
export default {
  props: ['field', 'fieldname'],
  methods: {
    refresh: function(value) {
      this.$emit('update', {'value': value, 'field': this.fieldname});
    }
  }
}
</script>
like image 5
jensmtg Avatar answered Nov 19 '22 15:11

jensmtg