13

I'm trying to make in a bootstrap-vue table a slot to render any boolean value with a custom component.

So I have a simple table

<b-table :items="items" :fields="columns" >

</b-table>

Now if i want to render a single column in a particular way i have to use a slot

<template v-slot:cell(active)="data" >
    <my-component :item="data.item" />
</template>

And it works, because I know that active is a boolean.

I would like to generalize this behavior but i cannot use v-for in templates and cannot use v-slot:cell(active) if not on template... The idea was to create an array with all my boolean fields and iterate on it... but it does not work..

Something like this

<template v-slot:cell(b)="data" v-for="b in booleanFields">
    <my-component :item="data.item[b]" />
</template>

1 Answer 1

24

Because Vue supports Dynamic Slot Names, you can use variables to set the slot names using the v-bind:[attributeName]="value" syntax.

This way you could do something like:

<template v-slot:['cell(' + b + ')']="data" v-for="b in booleanFields">

But using the quotes there is not possible due to the dynamic argument expression constraints. So you'll have to create a helper method to do that concatenation. So:

<template v-slot:[gomycell(b)]="data" v-for="b in booleanFields">

plus

methods: {
  gomycell(key) {
    return `cell(${key})`; // simple string interpolation
  }

Naturally, you could just name the method gomycell as cell and use it like v-slot:[cell(b)]="data" (notice the []s), but I left the name gomycell just so in this texample it is clearer what is the name of the method and what is not.


Demo:

Here's a small demo showcasing the dynamic slot names usage, it's not b-table but I think it is good enough to show it is possible:

Vue.component('my-table', {
  template: '#my-table',
})

new Vue({
  el: '#app',
  data: {
    booleanFields: [true, false]
  },
  methods: {
    gomycell(key) {
      return `cell(${key})`;
    }
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <my-table>
    <template v-slot:[gomycell(b)]="data" v-for="b in booleanFields">
      <h3>who? {{ data.is }}</h3>
    </template>
  </my-table>
</div>

<template id="my-table">
  <div>
    <div style="color:green"><slot name="cell(true)" v-bind="{is: 'true!'}"></slot></div>
    <div style="color:red"><slot name="cell(false)" v-bind="{is: 'false!'}"></slot></div>
  </div>
</template>

Sign up to request clarification or add additional context in comments.

5 Comments

You can also use string interpolation (when using Single File Components, which don't have the same restrictions as in DOM templates): <template v-slot:[cell(${b})]="data" v-for="b in booleanFields"> Note you cannot have spaces in the attribute name (anything before the =). This will also work: <template v-slot:['cell('+b+')']="data" v-for="b in booleanFields"> (note the lack of spaces in the expression)
Thanks @acdcjunior this kind of dynamic slot names function works perfectly!
Please note that Troy's example works but the backticks don't show up correctly in the comment. This may help: <template v-slot:[`cell(${b})`]="data" v-for="b in booleanFields">
This is part of why i would never recommend templates over render functions. You have to make all these pointless workarounds. If you use render functions, you only have to know javascript. To be honest this is part of why i would never recommend vue over react. The community is built around the pointless template system.
You see, not everything is so cut and dried. Many people find templates easier to reason with in the general case, and may build whole apps without ever having to use slots, let alone dynamic slot names.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.