0
votes

I have child component, that has some internal data, that should not be changed from outside. But when I update prop from parent component, this internal data is reset.

Basically in example below, when we change title from outside, value is set back to empty ''. How can I make value persistent with Child component props update?

Child.vue

<template>
  <div class="child">
    <h2>{{title}}</h2>
    <input type="text" :value="value" v-on:change="$emit('change', $event.target.value)">
  </div>
</template>

<script>
  export default {
    props: {
      title: {
        default: 'Just title'
      }
    },
    data() {
      return {
        value: ''
      }
    }
  }
</script>

Parent.vue

<template>
  <div class="parent">
    <Child :title="title" v-on:change="processTitle($event)"></Child>
  </div>
</template>

<script>
  import Child from './Child';

  export default {
    data() {
      return {
        title: 'Title from parent'
      }
    },
    methods: {
      processTitle(value) {
        this.title = value.reverse();
      }
    }
  }
</script>
1

1 Answers

1
votes

You are not setting the value data attribute, :value=value means that "if value changes, the input value should pick up that change". But value doesn't change. Use v-model instead if you want to keep it simple.

Vue.component("Child", {
  props: {
    title: {
      default: 'Just title'
    }
  },
  data() {
    return {
      value: ''
    }
  },
  template: `
    <div class="child">
      <h2>{{title}}</h2>
      <input type="text" v-model="value" v-on:change="$emit('change', $event.target.value)">
    </div>
  `
})

new Vue({
  el: "#app",
  data() {
    return {
      title: 'Title from parent'
    }
  },
  methods: {
    processTitle(value) {
      this.title = value.split("").reverse().join("");
    }
  },
  template: `
    <div class="parent">
      <child :title="title" v-on:change="processTitle($event)"></child>
    </div>
  `
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

EDIT

Also, if you want a continuous effect, don't use @change - use @input instead:

Vue.component("Child", {
  props: {
    title: {
      default: 'Just title'
    }
  },
  data() {
    return {
      value: ''
    }
  },
  template: `
    <div class="child">
      <h2>{{title}}</h2>
      <input type="text" v-model="value" v-on:input="$emit('change', $event.target.value)">
    </div>
  `
})

new Vue({
  el: "#app",
  data() {
    return {
      title: 'Title from parent'
    }
  },
  methods: {
    processTitle(value) {
      this.title = value.split("").reverse().join("");
    }
  },
  template: `
    <div class="parent">
      <child :title="title" v-on:change="processTitle($event)"></child>
    </div>
  `
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>