0
votes

I have the below child component. The props are updated from an input selector in the parent. Why does level: this.globalForm.level not update the child's level

Parent:

<template>
  <div>
    <div class="form-container">
      <select class="form-control" v-model="level">
        <option v-for="level in options" v-bind:key="level">{{ level }}</option>
      </select>
      <button @click="submit()">Create</button>
    </div>
    <child v-bind:globalForm="globalForm"/>
  </div>
</template>

    <script>
inputFiled;
export default {
  data() {
    return {
      level: "",
      globalForm: {
        level: ""
      },
      options: ["level1", "level2", "level3"]
    };
  },
  components: {
    child
  },
  methods: {
    submit() {
      this.globalForm.level = this.level;
    }
  },
  watch: {
    level() {
      this.globalForm.level = this.level;
    }
  }
};
</script>

Child:

<template>
  <div class="form-container">
      <option v-for="level in options" v-bind:key="level">{{ level }}</option>
  </div>
</template>

<script>
export default {
  props: { globalForm: Object },
  data() {
    return {
      options: ["level1","level2","level3",],
      level: this.globalForm.level //this does not update the child's level component
    };
  }
};
</script>
1
Where is the child component rendered in the parent one? i cant see something like <child :globalForm='globalForm'> </child> in the parentBill Souvas
sorry about that. I updated it thankslukechambers91

1 Answers

1
votes

TLDR

level should be a computed property on the child so that you can detect changes in the prop. You are setting level in the data function, so updates to the prop never make it to level.

Below you'll find a minimal example on what I think you want to achieve.

Vue.config.productionTip = false;
Vue.component('parent', {
  template: `
  <div class="parent">
    <b>PARENT</b>
    <div class="form-container">
      <select class="form-control" v-model="level">
        <option v-for="level in options" v-bind:key="level">{{ level }}</option>
      </select>
      <button @click="submit()">Create</button>
    </div>
    <child v-bind:globalForm="globalForm"/>
  </div>
  `,
  data: () => ({
    level: "",
    globalForm: {
      level: ""
    },
    options: ["level1", "level2", "level3"]
  }),
  methods: {
    submit() {
      this.globalForm.level = this.level;
    }
  }
});

Vue.component('child', {
  template: `
  <div class="form-container child">
      <p><b>Child</b></p>
      Level: {{ level }}
  </div>
  `,
  props: {
    globalForm: Object
  },
  computed: {
    level() {
      return  this.globalForm.level;
    }
  }
});

new Vue({
  el: "#app"
})
.parent {
  background-color: darkgray;
  padding: .5em;
  border: solid 1px black;
}
.child {
  background-color: lightgray;
  padding: .5em;
  border: solid 1px black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <parent></parent>
</div>

More Detailed explanation

There are couple of errors on your code that I'll go through.

In your child component

When initializing your component, this is not available inside the data function, so this.globalForm will be undefined. An error is thrown in the console when reproducing it.

data() {
    return {
      options: ["level1","level2","level3",], // this looks like duplicated code from the parent
      level: this.globalForm.level // throws error
    };
 }

To fix that error, you can get the vm context from the parameters of data But this is not the solution for your question.

data(vm) { // note vm
    return {
      level: vm.globalForm.level // note vm
    };
 }

The real problem is that level: this.globalForm.level runs only once, in your component initialization, so level is undefined. When the globalForm prop changes, level has already been initialized and it will not change (data returns a new object so the reference to the prop is lost).

You want convert level to be a computed property so that changes to the prop can be detected and the inner value returned. See code snippet above.