Search code examples
vue.jsbootstrap-vue

Vue and Bootstrap Vue - dynamically use slots


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>

Solution

  • 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>