javascriptvue.jsiconsvuetify.jsvue-render-function

How to create Vuetity badge and icon using createElement in render function


In my Vue app, I use a v-data-table, and the column values are rendered using a render function inside a functional component like so:

render(createElement) {
    if (this.$props.format) {
      return this.$props.format(this.item, this.index, createElement);
    }
    return createElement('div', this.getText());
  },

and then in my format function (which is part of an object in a separate file), you can use createElement to create an hTML element and return it. Here's an example from another part of the app:

format: (template, index, createElement) => {
    const captureType = template.captureType === 'passphrase' ? 'voice' : template.captureType;
    return createElement('div', captureType);
  },

So with all that, I'm trying to do something fairly complex, which is a Vuetify icon with a badge. Here's the code from the Vuetify docs.

<v-badge left>
  <template v-slot:badge>
    <span>6</span>
  </template>
  <v-icon
    large
    color="grey lighten-1"
  >
    shopping_cart
  </v-icon>
</v-badge>

As a starting point, I can create the basic badge HTML just fine

    format: (item, index, createElement) => {
      const propsObj = {
        attrs: {
          color: 'blue',
        },
        props: {
          overlap: true,
          left: true,
        },
        slots: {
          badge: 'dummy',
        },
      };
      return createElement('v-badge', propsObj, [createElement('v-icon', { attrs: { color: 'success', large: true } }, 'account_circle')]);
    },

That gets me almost there, in that it shows my icon, and it's wrapped with the badge element, although no badge content is displayed:

<span class="v-badge v-badge--left v-badge--overlap">
  <i aria ....>account_circle></a>
</span>

My issue is getting the display value to the badge slot. What am I missing to do that?


Solution

  • With help from a buddy, I got it working. Here's the final code:

    format: (item, index, createElement) => {
          const propsObj = {
            props: {
              overlap: true,
              left: true,
              color: 'success',
            },
          };
          const icon = createElement('v-icon', { props: { color: 'success', large: true } }, 'account_circle');
          const span = createElement('span', { slot: 'badge' }, '5');
          return createElement('v-badge', propsObj, [span, icon]);
        },
    

    The idea is that I break it down into smaller chunks that mimic the structure I'm trying to create. In this case, it's basically a v-badge that contains two children: the badge slot and the v-icon element. I pass the appropriate config options to each child element, and then pass the two rendered elements to createElement for the parent v-badge.