Home > Back-end >  Two way binding of data between child and parent using emit vue3 typescript
Two way binding of data between child and parent using emit vue3 typescript

Time:02-23

I have a child component:

<template>
  <label :>
    <span><LocCtrl :page="pageName" :locKey="labelLoc" /></span>
    <input
      type="text"
      :placeholder="getLoc(placeHolderLoc)"
      :value="text"
    />
  </label>
</template>

<script lang="ts">
import { ref, defineComponent} from "vue";
import { useModelWrapper } from '../utils/modelWrapper';
import LocCtrl from "../components/LocCtrl.vue";
import Locale from "@/services/Locale";

export default defineComponent({
  name: "Claims3View",
  components: {
    LocCtrl
  },
  setup(props, {emit}) {
    
    const data = ref({
      textValue: ""
    });

    return {
      text: useModelWrapper(props, emit, "modelValue")
    };
  },
  methods: {
    getLoc(locKey: string): string {
      return Locale.getItem(this.pageName, locKey);
    }
  },
  props: {
    labelLoc: {
      type: String,
      required: true,
    },
    modelValue: {
      type: String,
      required: true,
    },
    placeHolderLoc: {
      type: String,
      required: true,
    },
    pageName: {
      type: String,
      required: true,
    },
    className: {
      type: String,
      required: true,
    },
  },
});
</script>

The parent control:

<template>
   <textBox
      labelLoc="Symptoms"
      className="w4"
      data="claim.petCondition"
      :modelValue="claim.petCondition.symptoms"
      placeHolderLoc="saDC"
      pageName="claims3View"
   />
  </div>
</template>

<script lang="ts">
import { ref, defineComponent, inject } from "vue";
import type { Claim } from "../types/types";
import TextBox from "../components/TextBox.vue";

export default defineComponent({
  name: "Claims3View",
  components: {
    TextBox,
  },
  setup() {
    const claim = inject("ClaimData") as Claim;

    return {
      claim,
    };
  },
});
</script>

The code is working to put the value from Claim into the input field of the control, but the code doesn't update the data in the other direction when the user types in the textbox. I need something like this to work eventually when I have common methods of having validation for example. Part of the problem here is that is code from https://developpaper.com/vue-3-with-the-development-of-data-events-are-more-and-more-outstanding/ that I don't really grok yet.

Another part of the problem is that most of the examples I have found for Vue3 are not in typescript and do not work at all when I copy the javascript.

Edit: I forgot to enclude the helper class:

import { computed } from "vue";
export function useModelWrapper(
  props: { [x: string]: any },
  emit: (arg0: string, arg1: any) => void,
  name = "modelValue"
) {
  return computed({
    get: () => props[name],
    set: (value) => emit("update:${name}", value),
  });
}

CodePudding user response:

try this ?

<textBox
  labelLoc="Symptoms"
  className="w4"
  data="claim.petCondition"
  v-model="claim.petCondition.symptoms"
  placeHolderLoc="saDC"
  pageName="claims3View" />

CodePudding user response:

gengsong was partially correct.

You need to pass v-model on the child control .

But the helper function didn't convert to typescript properly as well. As I said before, the original example was javascript, so I had to convert it to typescript. This is what works:

import { computed } from "vue";
export function useModelWrapper(
  props: { [x: string]: any },
  emit: (arg0: string, arg1: any) => void,
  name = "modelValue"
) {
  return computed({
    get: () => {
      return props[name];
    },
    set: (value: string) => {
      return emit("update:"   name, value)
    }
  });
}
  • Related