5

I'm using Vue 2.6.9 with the new v-slot syntax. I want to access interact with v-model inside slot. The problem is that showing data inside slot works, but using v-model does not. Here is my code:

Vue.component('base-test', {
  template: `
  <div>
    <slot :foo="foo" :foo2="foo2"></slot>
  </div>
  `,
  data(){
    return{
      foo: 'Bar',
      foo2: 'Bar 2'
    }
  }
});


// Mount
new Vue({
  el: '#app'
});

<div id="app">
  <base-test v-slot="sp">
    <div>foo2 is {{ sp.foo2 }}</div>
    <input type="text" v-model="sp.foo">
    <div>foo is {{ sp.foo }}</div>
  </base-test>
</div>

Codepen

My question is how to interact with the component data from within slot.

Chris Panayotoff
  • 1,744
  • 21
  • 24

2 Answers2

5

Regarding this issue, Vue core member says that you should not modify the data you pass to a slot.

You should pass a method to change the value. If you agree with this, then follow this answer.


However, there is a tricky way to do it by taking advantage of Javascript reference values

Instead of passing a primitive value (which will not have reactivity), you pass a reactive object which will keeps its reactivity (eg Observer, reactiveGetter, reactiveSetter).

Child component

<template>
  <div class="child">
    <slot :model="model"></slot>
  </div>
</template>

<script>
export default {
  data: () => ({
    model: {
      value: "Initial value",
    },
  }),
};
</script>

Parent component

<template>
  <div id="app">
    <Child v-slot="{ model }">
      <input type="text" v-model="model.value" />
    </Child>
  </div>
</template>

<script>
import Child from "./components/Child";

export default {
  components: {
    Child,
  },
};
</script>

See it live on codesandbox.

Roland
  • 24,554
  • 4
  • 99
  • 97
2

Ok, it seems that one cannot change the data directly. The way to do it is to pass as slot prop method and basically redo v-model:

<div id="app">
  <base-test v-slot="sp">
    <div>foo2 is {{ sp.foo2 }}</div>
    <input type="text" 
          :value="sp.foo2" @input="event => sp.onInput(event, 'foo2')">
    <div>foo is {{ sp.foo }}</div>
  </base-test>
</div>

Vue.component('base-test', {
  template: `
  <div>
    <slot :foo="foo" :foo2="foo2" :onInput="onInput"></slot>
  </div>
  `,
  data(){
    return{
      foo: 'Bar',
      foo2: 'Bar 2'
    }
  },
  methods:{
    onInput(event, prop){
      this[prop] = event.target.value;
    }
  }
});


// Mount
new Vue({
  el: '#app'
});

Codepen demo

Chris Panayotoff
  • 1,744
  • 21
  • 24