Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a method in Vue.js slot scope

Tags:

vue.js

I'm using a slot scope in vuejs. It's working great. I can pass anything I want into the slot like this:

<slot :item1="item1">    
</slot>

The problem is that when I pass a function as a prop, it is undefined in the parent template. So this doesn't work:

<slot :my-method="myMethod">    
</slot>

In this example, myMethod is a method defined on the child vue component. (I am using typescript, so it is a method on the component class)

Any ideas on how to pass a function defined on the child component back through the slot props to the parent so that it can be called from within the slot code in the parent?

like image 409
user3413723 Avatar asked May 11 '18 18:05

user3413723


People also ask

How do you pass a Vue slot?

Scoped slots To pass a property in Vue, you would define the data in the parent component and assign a value to the data. Then, you'd pass the value of the property to the child component so the data becomes a property in the child component.

What is scoped slot Vue?

In our previous adventure, we looked at Vue's basic slots. Scoped slots allow us to expose a piece of data, through the scope, to the parent that is using it.

Can you pass a function as a prop Vue?

While you can pass a function as a prop, this is almost always a bad idea. Instead, there is probably a feature of Vue that is designed exactly to solve your problem. If you keep reading you'll see what I mean. Join 11,067 other Vue devs and get exclusive tips and insights delivered straight to your inbox, every week.

How do you make a Vue slot?

You add a colon ( : ) after v-slot and then write the name of the slot you want the content to be passed to. Note that v-slot is new to Vue 2.6, so if you're using an older version, you'll need to read the docs about the deprecated slot syntax.


2 Answers

Reading this article I have discovered that if you need to call a method programmatically (not from the template), you can actually pass a method from the parent component to the scoped-slot, but then you have to pass the same method to a child component through a prop: in this way you have access to the method, and can call it from the code.

This is how I used it:

Usage (in html, blade or other vue component)

<template>
    <cart-validation>
        <template v-slot:trigger="{ myMethod }">
            <!-- here you pass the method as a prop -->
            <cart :my-method="myMethod">
            </cart>
        </template>
    </cart-validation>
</template>

Parent component (CartValidation.vue)

<template>
    <div>
        <slot name="trigger" :my-method="myMethod" />
    </div>
</template>
<script>
    export default {
        name: 'CartValidation',
        methods: {
            myMethod() {
                // here you define your method
                console.log('hello!');
            }
        },
    };
</script>

Child component (Cart.vue)

<script>
    export default {
        name: 'Cart',
        props: ['myMethod'],
        mounted() {
            // here you call the method
            this.myMethod();
        }
    };
</script>

In other parts of my code I used other elements inside the slot, but in each child component I could call this.myMethod(). I hope this helps other people :)

like image 162
Giorgio Tempesta Avatar answered Sep 22 '22 06:09

Giorgio Tempesta


UPDATE

This answer was written for the older pre v2.6 syntax. Since then, this syntax has been marked for deprecation. The core functionality stays the same, the functions(methods) work the same way as the properties that are being bound upwards (from child to parent), however the definition uses v-slot:default now.

as per updated documentation (https://vuejs.org/v2/guide/components-slots.html#Scoped-Slots),

<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

Attributes bound to a element are called slot props. Now, in the parent scope, we can use v-slot with a value to define a name for the slot props we’ve been provided:

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

Here is a more complicated example, as you will notice, the function and the scoped slots are passed using slotProps
Edit Vue Template


Original answer with pre v2.6 syntax. Example of how to pass the slot-scope

parent:

<template>
  <div slot="item" slot-scope="{ myLink, myMethod }">
    <button @click="myMethod(myLink.title)">
      Bookmark
    </button>
  </div>
</template>

child:

<template>
  <li v-for="myLink in links">
    <slot name="myLink" :myLink="myLink" :myMethod="myMethod"></slot>
  </li>
</template>

<script>
export default {
  methods: {
    myMethod(link) {
      link.bookmarked = true
    }
  }
}
</script>
like image 30
Daniel Avatar answered Sep 20 '22 06:09

Daniel