[Vuejs]-V-model and scoped slots not working?

1👍

What you are seeing is actually the parent’s default <input>. So you understand what I mean, add some text to both, like:

<slot name="test" :name="name">
    Default: <input type="text" v-model="name">
</slot>
<div slot="test" slot-scope="props">
    Actual: <input type="text" v-model="props.name">
</div>

You’ll see that what appears is the default.

Now, that happens because, it seems like a bug, when the slot prop has the same name as the parent’s, the slot does not work.

Workaround: rename the slot prop.

In the example below, I renamed it from name to namex. Notice the v-model in the default remains the same name because anything in the template refers to the props of that template (in other words, slot props, e.g. namex, will never be available in the parent default slot).

<slot name="test" :namex="name">
    Default: <input type="text" v-model="name">
</slot>
<div slot="test" slot-scope="props">
    Actual: <input type="text" v-model="props.namex">
</div>

1👍

to use v-model in scoped slots, the value of v-model must be one level deeper:

Vue.component('render-props', {
  data: () => ({message: 'hello', obj: {msg: 'obj_msg'}}),
  template: `<div>
    <slot name="a" :message="message">
      default: {{message}}
      <input v-model="message"/>
    </slot>
    <slot name="b" :obj="obj">
      default: {{obj.msg}}
      <input v-model="obj.msg"/>
    </slot>
  </div>`
});
new Vue({
  el: "#root",
  template: `<div>
    <render-props>
      <template v-slot:a="props">
        actual: {{props.message}}
        <input v-model="props.message"/>
      </template>
      <template v-slot:b="props">
        actual: {{props.obj.msg}}
        <input v-model="props.obj.msg"/>
      </template>
    </render-props>
    <cus_2 />
  </div>`
});

Another easier case:

var Sub = Vue.extend({
  props: ['a', 'b'],
  template: `<div>
    <div>a : <input v-model="a" /></div>
    <div>b.txt : <input v-model="b.txt" /></div>
  </div>`
});

var Main = Vue.extend({
  components: { Sub },
  data() {
    return {
      a: 'aaa',
      b: { txt: 'bbb' },
      c: 'ccc',
    };
  },
  template: `<div>
    <Sub :a="a" :b="b" />
    <div>c : <input v-model="c" /></div>
    <ul>
      <li>a: {{a}}</li>
      <li>b.txt: {{b.txt}}</li>
      <li>c: {{c}}</li>
    </ul>
  </div>`
});
new Main().$mount("#app");

a won’t change, b.txt and c is ok.

0👍

you are not supposed to modify the data you pass to a slot, pretty
much like a prop. You should pass a method instead to change tha
value. You can always pass an object and modify a property (like a
prop) but it’s also not recommended

-from https://github.com/vuejs/vue/issues/9726

So I imagine something like

<template>
   <slot v-bind:value="value"></slot>
</template>
<script>
export default {
  name: 'FooBar',
  data() {
    value: '',
  },
  methods: {
    updateValue(e) {
      this.value = e.target.value;
    }
  },
};
</script>

Then when using the component <FooBar> instead of using v-model, you can use the passed scoped slot props, the method (updateValue), and actual prop that will be updated, value.

<FooBar v-slot="slotProps">
  <input type="text" :value="slotProps.value" @input="slotProps.updateValue" />
</Foobar>

Leave a comment