4

I'm making a site that uses NuxtJS, Bootstrap Vue and vue-i18n.

I have a table (<b-table>) that shows areas in square meters, and the header should display: sq m in english, and m2 (m<sup>2</sup>) in a translation.

So the header field label is drawn from the i18n locale JSON to the single file component's table header label. The string is drawn correctly, but the HTML part is not rendered, unfortunately, so what I see on the page is m<sup>2</sup>.

Here's how I tried to solve it (examples are simplified - parts are deleted from them):

hu.json (translation locale file)

{
  "in_numbers": {
    "space": "m<sup>2</sup>"
  }
}

tableComponentFile.vue (single file component)

<template>
  <b-container fluid>
    <b-row>
      <b-col cols="12">
        <b-table
          :items="floors"
          :fields="tableHeader"
        />
          <template slot="HEAD_space" slot-scope="data">
            <span v-html="data.label"></span>
          </template>
        </b-table>
      </b-col>
    </b-row>
  </b-container>
</template>

<script>
export default {
  computed: {
    floors() {
      return [
        { space: 552.96 },
        { space: 796.27 }
      ]
    }
  },
  data() {
    return {
      tableHeader: [
        {
          key: 'space',
          label: this.$t('in_numbers.space'),
          sortable: false
        }
      ]
    }
  }
}
</script>

So, everything works fine, except that I cannot render the HTML from the locale json in the table header - so the table renders with the data in it, and in other components this <span v-html="$t('in_numbers.space')"></span> technique works just fine.

It doesn't work if I try (&sup2;) or anything.

The problem is that <template slot> doesn't seem to react to anything (actually I'm not sure it works) - but it should, as the documentation says (https://bootstrap-vue.js.org/docs/components/table#custom-data-rendering)

Anybody see a way to render HTML in bootstrap-vue's table header?

muka.gergely
  • 8,063
  • 2
  • 17
  • 34

2 Answers2

7

Updated answer (June 2020)

Both VueJS and bootstrap-vue has changed since the question and the accepted answer was posted. It still not very clear in the bootstrap-vue docs, but you can accomplish the same result with:

<template>
  <b-container fluid>
    <b-row>
      <b-col cols="12">
        <b-table
          :items="floors"
          :fields="tableHeader">
          <template v-slot:head(space)="data"> // This has changed
            <span v-html="data.field.label"></span> // Now you access data.field.label
          </template>
        </b-table>
      </b-col>
    </b-row>
  </b-container>
</template>

<script>
export default {
  computed: {
    floors() {
      return [
        { space: 552.96 },
        { space: 796.27 }
      ]
    }
  },
  data() {
    return {
      tableHeader: [
        {
          key: 'space',
          label: this.$t('in_numbers.space'),
          sortable: false
        }
      ]
    }
  }
}
</script>
Fouyer
  • 115
  • 1
  • 8
  • 1
    thanks, this should be the accepted answer! The docs actually do mention this but I only found this after seeing your post. https://bootstrap-vue.org/docs/components/table#header-and-footer-custom-rendering-via-scoped-slots – kurdemol94 Jul 19 '21 at 09:26
1

OK, I solved it - there was an unnecessary / in the code - originally <b-table> was a self closing tag, and after I added a slot I missed to modify it.

I corrected the error, and the bootstrap-vue HEAD_ slot started working, and everything is displayed correctly now.

So, the solution looks like this:

hu.json

{
  "in_numbers": {
    "space": "m<sup>2</sup>"
  }
}

tableComponentFile.vue

<template>
  <b-container fluid>
    <b-row>
      <b-col cols="12">
        <b-table
          :items="floors"
          :fields="tableHeader"
        >
          <template slot="HEAD_space" slot-scope="data">
            <span v-html="data.label"></span>
          </template>
        </b-table>
      </b-col>
    </b-row>
  </b-container>
</template>

<script>
export default {
  computed: {
    floors() {
      return [
        { space: 552.96 },
        { space: 796.27 }
      ]
    }
  },
  data() {
    return {
      tableHeader: [
        {
          key: 'space',
          label: this.$t('in_numbers.space'),
          sortable: false
        }
      ]
    }
  }
}
</script>
muka.gergely
  • 8,063
  • 2
  • 17
  • 34
  • Would you be able to expand a little what you've done here? It would be greatly useful :) – Adriano Mar 05 '20 at 02:30
  • @Adriano what are you interested in? **VueJS** and **bootstrap-vue** has changed a lot since I posted my original problem, so the answer here might not be correct anymore. – muka.gergely Mar 05 '20 at 06:44
  • 1
    I'm having the same problem: in a `b-table` element I need to programmatically inject some dynamic data in the `th` of each column. Injecting data in the `HEAD_space` slot doesn't work for me. – Adriano Mar 06 '20 at 00:07
  • If you post your problem here on StackOverflow with some code you tried, you can reference link that here in a comment - maybe I can look at it. – muka.gergely Mar 06 '20 at 16:47
  • This solution worked for me, but as Adriano said, unfortunately, I find hardcoding the keys after "HEAD_" far from ideal. – rubebop Nov 22 '21 at 12:52
  • Here is an alternative for people looking for a more dynamical solution using a `v-for` (i.e. looping through all the fields without having to explicitely write/hard-code a given one): https://stackoverflow.com/a/66360753/7894940 – rubebop Jul 26 '22 at 11:11