Search code examples
typescriptvue.jsvue-cli

How to two-way bind v-model object in vue class style component with typescript


I would like to create a custom component in vue cli where I can use the v-model for passing a value (or object) to my component. As I understand, when I use v-model for binding I can update the passed value in the parent. Either you can tick the checkbox or click the button to set the value to true.

In app code:

 <test v-model="content"></test>
    <br />
    selected: {{content}}

Test component:

<template>
  <div>
    <v-text-field label="Regular" v-model="checkval" disabled></v-text-field>
    <input
      type="checkbox"
      v-bind:checked="checkval"
      v-on:change="$emit('change', $event.target.checked)"
    />
    <v-btn @click="$emit('change', true)">Make true</v-btn>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Model, Prop } from "vue-property-decorator";
@Component({
  model: {
    prop: "checkval",
    event: "change"
  },
  props: {
    checkval: Boolean
  }
})
export default class test extends Vue {}
</script>

Now I would like to go the next step and implement my component as "class style" and two-way bind an object. I tried the following, but that didn't work (the previous code with Boolean worked fine):

export class myobject {
    checkval!: boolean;
    test!: String;
}

@Component
export default class test extends Vue {
    @Prop() checkval: Boolean = false;
    @Model() model: myobject = {
        checkval: true,
        test: "checkval"
    };
}

Now my questions:

  1. How would I do this when binding an object?
  2. Is there a way I don't have to use the Emit and just set the variable like checkval = true or model.checkval = true ?
  3. When I have to use the Emit, how would the correct code look for the button, like <v-btn @click="$emit('change', {...this.model, checkval: true})"> ?

Solution

  • I was running into the same issue and finally found the answer on the vue-property-decorator github:

    @Model(event?: string, options: (PropOptions | Constructor[] | Constructor) = {}) decorator

    import { Vue, Component, Model } from 'vue-property-decorator'
    
    @Component
    export default class YourComponent extends Vue {
      @Model('change', { type: Boolean }) readonly checked!: boolean
    }
    

    is equivalent to

    export default {
      model: {
        prop: 'checked',
        event: 'change'
      },
      props: {
        checked: {
          type: Boolean
        }
      }
    }
    

    @Model property can also set type property from its type definition via reflect-metadata .