1

I have an application that uses a form contained within a child component. A prop (wizardData) is passed to the child from the parent. If the form is being used to enter a new set of data, the field values in that prop will be null; if the user is reviewing/editing stored data, the field values contain these stored data values.

My problem occurs in the latter scenario. Although the form's fields are populated with the stored values, when I click to edit any field (I've only shown two of several in the code below), all the values in the form disappear and the $emit call updates the parent with null values.

What am I doing wrong here?

Thanks, Tom

child Component

<template>
  <div>
      <form @input="submit" class="form">
      <v-card-text>
        <v-text-field       
            model='wizardData.product'
            type="text"
            label="Name"
            box
            max="100%"
            autofocus
        ></v-text-field>
        <v-text-field
            model='wizardData.source'
            type="text"
            label="Source"
            box
        ></v-text-field>
     </v-card-text>
    </div>
</template>

<script>
  export default {
    props: {
      wizardData: {
        type: Object,
        required: true
      }
    },
    data() {
      return {
        form: {
          product: null,
          source: null,
        }
      }
    },
      submit () {
        this.$emit('update', {
          data: {
            product: this.form.product,
            source: this.form.source,
          },
        })
      },
    }
  }
</script>

My prop is as follows:

wizardData

{
  "product": "Cucumber",
  "source": "D112",
}
  • 2
    Without knowing anything about the <v-text-field> component, it's hard to say much. But it is the case that your <form> and <v-card-text> elements have no closing tags. – Stephen Thomas Apr 15 at 23:30
  • You also have to let us know what's inside wizardData. – Andrei Gheorghiu Apr 15 at 23:46
  • FYI, your model attributes should be v-model – Phil Apr 16 at 0:37
1

Binding your input field models to the wizardData prop violates Vue's One-Way Data Flow.

You should initialise your component's local data as a copy of the prop and bind your field models to form. For example

// default form values in case they're missing from wizardData
const FORM_TEMPLATE = {
  product: null,
  source: null
}

export default {
  props: { wizardData: Object },
  data () {
    return {
      form: {...FORM_TEMPLATE, ...this.wizardData}
    }
  },
  methods: {
    submit() {
      this.$emit('update', { data: this.form })
    }
  }
}

and in your template

<v-text-field v-model="form.product" ... />

JSFiddle demo ~ https://jsfiddle.net/z04um7Lb/


If wizardData is altered externally to your component, you will need to set up a watcher to monitor changes in the prop, eg

watch: {
  wizardData (newData) {
    this.form = {...this.form, ...newData}
  }
}

Another (and possibly better) option would be to use conditional rendering to prevent the form component from displaying until the data is ready, eg

<form-component :wizard-data="wizardData" v-if="dataLoaded" />
  • Thanks for this. However, this solution - an approach I had tried - gives me another problem: the contents of the props are not being "given" to the form. As the prop example (that I've just added to my question) shows, both product and source have values, but those values do not show up in the form - the only way I could get them to show was to bind wizardData to the input fields (and then that gave rise to the problem outlined in my question). – TomBaine Apr 16 at 5:09
  • @TomBaine I've added a JSFiddle demo and my code works just fine – Phil Apr 16 at 5:21
  • @TomBaine the only thing I can think of is that the wizardData is not set when this component is created but is updated later. Your question does not mention this though – Phil Apr 16 at 5:23
  • That's @Phil for the time here. You are correct, I think, about the time issue. It seems that by the time the database call is made and returned, the initial values given to product and source (set to null in the parent's data() step) are sent to and consumed by the form in the child component. Once the database call is completed, the prop is updated, but because it's not bound to the form, the updated values are not used by the now existing form. I don't know how to avoid this issue, other than to have the whole form present in the parent and forget about child components. A pity. – TomBaine Apr 16 at 6:50
  • 1
    Yes, and I missed it 'cos I was looking at the Fiddle. It's late. Sorry. Thank you. The watch option didn't do the trick (a console.log indicated it wasn't fired), BUT the v-if option worked a treat. Wonderful. This has been a 5 day headache. My family thanks you too! Cheers, Tom. – TomBaine Apr 16 at 9:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.