David
David

Reputation: 1237

Is there a better way to support label subscripts in dynamically generated b-form-groups with BootstrapVue?

I'm writing a Vue.js app using BootstrapVue. I'm dynamically generating a form based on a simple "field" data structure (see code and screenshot below). The label for each <b-form-group> comes from a label attribute in my field object. It worked fine until I needed a subscript in the label. I'm using the <sub> HTML tag, but v-bind-ing the label treats the HTML as plain text. See the first column of inputs:

enter image description here

Next I tried using <b-form-group>'s label slot instead, using mustache templates. As documented, this also interprets the value as plain text, so I get the same result -- see the second column.

Finally, I was able to achieve the result I wanted using v-html in a span inside the label slot. This works (see the third column), but it seems a bit convoluted, and it's not making the linter happy (yes, I can always turn it off).

Is there a better way to achieve this? I'm relatively new to Vue.js.

(Note that I've simplified the example for brevity, omitting id's, etc.)

<template>
  <div class="m-4">
    <b-container>
      <b-form-row class="round-border">
        <b-col
          cols="4"
        >
          <b-form class="mr-4">
            <b-form-group
              v-for="(field, index) in fields"
              :key="index"
              :label="field.label"
            >
              <b-form-input
                v-model.number="form[field.model]"
                v-bind="field.atts"
              />
            </b-form-group>
          </b-form>
        </b-col>

        <b-col
          cols="4"
        >
          <b-form class="mr-4">
            <b-form-group
              v-for="(field, index) in fields"
              :key="index"
            >
              <label>{{ field.label }}</label>
              <b-form-input
                v-model.number="form[field.model]"
                v-bind="field.atts"
              />
            </b-form-group>
          </b-form>
        </b-col>

        <b-col
          cols="4"
        >
          <b-form class="mr-4">
            <b-form-group
              v-for="(field, index) in fields"
              :key="index"
            >
              <label><span v-html="field.label" /></label>
              <b-form-input
                v-model.number="form[field.model]"
                v-bind="field.atts"
              />
            </b-form-group>
          </b-form>
        </b-col>
      </b-form-row>
    </b-container>
  </div>
</template>

<script>

export default {
  components: {},
  data () {
    return {
      form: {
        Length: 1,
        Width: 4,
        Height: 9
      },
      fields: [
        { label: 'Label<sub>1</sub>', model: 'Length', atts: { type: 'number', step: 1 } },
        { label: 'Label<sub>2</sub>', model: 'Width', atts: { type: 'number', step: 1 } },
        { label: 'Label<sub>3</sub>', model: 'Height', atts: { type: 'number', step: 1 } }
      ]
    };
  }
};

</script>

Upvotes: 1

Views: 649

Answers (2)

The.Bear
The.Bear

Reputation: 5855

As @Ian Cho says, if the content of field.label property is html as string, the only way to solve it in vue.js is using v-html.

If you are able to change the field item structure to something like {label: 'Label', sub: 1, ...}, you can use label slot as following:

<b-form-group v-for="(f, i) in fields">
    <template slot="label">{{f.label}} <sub>{{f.sub}}</sub></template>
    <!-- rest of your code -->
</b-form-group>

DEMO: https://jsfiddle.net/4xmr35p0/

Upvotes: 2

Ian Cho
Ian Cho

Reputation: 107

If you have to use HTML tags as parameter, v-html is the only way. If there's another way, please anyone let me know. ;)

Upvotes: 1

Related Questions