0
votes

I'm trying to make a re-usable custom Switch component, but my v-model is not working. Here's the situation:

  • My component correctly emits the tap event
  • My component updates its data correctly
  • However, the parent data doesn't get updated despite being hooked to the child with a v-model

Here are some snippets showing my setup:

// MY COMPONENT
<template>
  <Switch
    dock="right"
    backgroundColor="red"
    offBackgroundColor="yellow"
    v-model="model"
  />
</template>

<script>
export default {
  name: "SettingsSwitch",
  props: {
    value: {
      type: Boolean,
      required: true
    }
  },
  data() {
    return {
      model: this.value
    };
  },
  watch: {
    model: function(value) {
      this.$emit("tap", value);
    }
  }
};
</script>

In the example below, I have 2 Switches: - A normal one that works and whose data gets updated - The one linked to my child component and the data does not get updated

// My parent view
<template>
  <ViewWrapper viewTitle="Change your settings" pageColor="tertiary">
    <StackLayout class="content-wrapper">
      <StackLayout class="category-wrapper">
        <DockLayout class="field-wrapper" stretchLastChild="true">
          <Switch v-model="myCheck" dock="right" @tap="test" /> 
          <StackLayout>
            <Label text="Mon label" class="field-label" />
            <Label text="Ma valeur actuelle" class="field-value" />
          </StackLayout>
        </DockLayout>
        <DockLayout class="field-wrapper" stretchLastChild="true">
          <SettingsSwitch v-model="myCheck2" @tap="test2" />
          <StackLayout>
            <Label text="Mon label" class="field-label" />
            <Label text="Ma valeur actuelle" class="field-value" />
          </StackLayout>
        </DockLayout>

      </StackLayout>
    </StackLayout>
  </ViewWrapper>
</template>

<script>
import { ViewWrapper } from "@/components";
import SettingsSwitch from "./SettingsSwitch";
export default {
  name: "Settings",
  components: { ViewWrapper, SettingsSwitch },

  data() {

    return {
      myCheck: false,
      myCheck2: false
    };
  },
  methods: {
    test() {
      console.log(this.myCheck);
    },
    test2(v) {
      console.log("emit", v); // <--- Value changes each time
      console.log("model", this.myCheck2); // <--- Value never changes
    }
  }
};
</script>

I've tried playing around with different setups, like removing the watch and directly calling a method that does the $emit but it doesn't seem to fix the issue

Any thoughts?

1

1 Answers

0
votes

So I managed to fix my issue. My mistake was that I was emitting tap instead of input in my component. I feel stupid but I'm leaving this up instead someone struggles like I did

The bottom line is:

You can use v-model on any tag, but in order to update its value, it will need to receive an "input" event with some data. That's why my child component must perform this.$emit("input", value);