Travis Bear
Travis Bear

Reputation: 13869

Is it possible to use a v-model from inside a component template?

Can the v-model syntax be used from inside a Vue component template?

The following works as expected when included directly in an .html

<input type="text" v-model="selected_service_shortname">

Putting the following stuff into a component template does not work.

var service_details = {
    template: `
    ...
    <input type="text" v-model="selected_service_shortname"> 
    ...
`
};


vm = new Vue({
    el: "#app",
    components: {
        'service-details': service_details
    },

Results in vue.min.js:6 ReferenceError: selected_service_shortname is not defined

Changing the template syntax to

<input type="text" v-model="this.$parent.selected_service_shortname">

Seems to halfway work -- changes applied externally to selected_service_shortname appear in the input box as expected. But making changes to the input box directly results in Uncaught TypeError: Cannot convert undefined or null to object

Is what I'm trying to do a supported use case? If so, are there working examples somewhere?

Upvotes: 2

Views: 882

Answers (1)

Bert
Bert

Reputation: 82489

You can implement support for v-model in your component. This is covered in the documentation here.

Here is an example.

var service_details = {
  props: ["value"],
  template: `
          <input type="text" v-model="internalValue"> 
        `,
  computed: {
    internalValue: {
      get() {
        return this.value
      },
      set(v) {
        this.$emit("input", v)
      }
    }
  }
};

Basically, v-model, by default, is simply sugar for passing a value property and listening for the input event. So all you need to do is add a value property to your component, and emit an input event. This can also be customized as described in the documentation.

console.clear()

var service_details = {
  props: ["value"],
  template: `
          <input type="text" v-model="internalValue"> 
        `,
  computed: {
    internalValue: {
      get() {
        return this.value
      },
      set(v) {
        this.$emit("input", v)
      }
    }
  }
};

new Vue({
  el: "#app",
  data: {
    selected_service_shortname: "some service name"
  },
  components: {
    'service-details': service_details
  },
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>

<div id="app">
  <service-details v-model="selected_service_shortname"></service-details>
  <hr>
  Selected Service Shortname: {{selected_service_shortname}}
</div>

Used in the parent like this:

<service-details v-model="selected_service_shortname"></service-details>

Upvotes: 4

Related Questions