0
votes

The use of v-model creates a two-way bind between the view and data model WITHIN a component. And a view interaction can emit an event to a parent component.

It is possible, though, to have a data model change in a child component emit an event to a parent component?

Because as long as the user is the one clicking the checkbox, things are fine in both the parent and the child (the data model updates AND the event is emitted). But if I pull up the Vue dev tools and toggle the checkbox within the child component's data, the two-way bind from the v-model will make the appropriate updates within the CHILD component, but nothing ever makes it over to the parent component (I suspect because an event is not emitted).

How can I make sure the parent component "knows" about the data change in the child component? I assume this must be possible in some way... If not emitting from the child, perhaps there's some way to have the parent component "watch" the child component's data?

Thank you for any help or guidance! I'll keep reading and looking for an answer in the meantime!

child component

<template>
  <div class="list-item" v-on:click="doSomething">
    <input type="checkbox" v-model="checked">
    <label v-bind:class="{ checked: checked }">{{ name }}</label>
  </div>
  ...
</template>

<script>
  ...
  data: function() {
    return {
      checked: false,
    }
  },
  methods: {
    doSomething() {
      ...
      this.$emit('doSomething', this)
    }
  }
</script>

parent component

<template>
  <ChildComponent v-on:doSomething="getItDone"></ChildComponent>
  ...
</template>

<script>
  ...
  methods: {
    getItDone(target) {
      ...
    }
  }
</script>  

UPDATE: After playing around a bit more with @IVO GELOV's solution, the issue I'm running into now is that, when multiple Child components are involved, since the Parent's one singular value of myBooleanVar drives the whole thing, checking the box of one child component causes all child components to be checked.

So it's definitely progress in that both view and data manipulations make it over to the parent, but I'm still trying to figure out how to "isolate" the situation so that just the one Child component that was acted upon gets dragged into the party...

2

2 Answers

1
votes

You can keep the data in the parent, provide it to the child as a prop, make the child watch the prop and update its internal state, and finally emit an event to the parent when the internal state of the child has been changed.

parent

<template>
  <ChildComponent v-model="myBooleanVar" />
  ...
</template>

<script>
  data()
  {
    return {
      myBooleanVar: false,
    }
  },
  watch:
  {
    myBooleanVar(newValue, oldValue)
    {
      if (newValue !== oldValue) this.getItDone(newValue);
    }
  },
  methods: 
  {
    getItDone(value) 
    {
      ...
    }
  }
</script>  

child

<template>
  <div class="list-item">
    <input type="checkbox" v-model="checked">
    <label :class="{ checked: checked }">{{ name }}</label>
  </div>
  ...
</template>

<script>
  props:
  {
    value:
    {
      type: Boolean,
      default: false
    }
  }
  data() 
  {
    return {
      checked: this.value,
    }
  },
  watch:
  {
    value(newVal, oldVal)
    {
      // this check is mandatory to prevent endless cycle
      if(newVal !== oldVal) this.checked = newVal;
    },
    checked(newVal, oldVal)
    {
      // this check is mandatory to prevent endless cycle
      if(newVal !== oldVal) this.$emit('input', newVal);
    }
  },
</script>
1
votes

Maybe you can directly bind the checkbox attribut to the parent attribut using v-bind="$attrs"

Take a look at this answer: https://stackoverflow.com/a/56226236/10514369