12

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>
acdcjunior
  • 132,397
  • 37
  • 331
  • 304
MarioC
  • 2,934
  • 15
  • 59
  • 111

1 Answers1

23

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>
tony19
  • 125,647
  • 18
  • 229
  • 307
acdcjunior
  • 132,397
  • 37
  • 331
  • 304
  • 1
    You can also use string interpolation (when using Single File Components, which don't have the same restrictions as in DOM templates): ` – Troy Morehouse Sep 29 '19 at 18:31
  • Thanks @acdcjunior this kind of dynamic slot names function works perfectly! – MarioC Sep 30 '19 at 08:25
  • 4
    Please note that Troy's example works but the backticks don't show up correctly in the comment. This may help: ``` – inki Jan 15 '20 at 19:20
  • 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. – Jumi Nov 24 '20 at 10:12
  • 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. – acdcjunior Nov 24 '20 at 23:53