Jaye Renzo Montejo
Jaye Renzo Montejo

Reputation: 1862

When using conditional rendering, how do I prevent repeating the child components on each condition?

Scenario

I have a custom button component in Vue:

<custom-button type="link">Save</custom-button>

This is its template:

// custom-button.vue
<template>
  <a v-if="type === 'link'" :href="href">
    <span class="btn-label"><slot></slot></span>
  </a>
  <button v-else :type="type">
    <span class="btn-label"><slot></slot></span>
  </button>
</template>

You can see from the template that it has a type prop. If the type is link, instead of the <button> element, I am using <a>.

Question

You'll notice from the template that I repeated the child component, i.e. <span class="btn-label"><slot></slot></span> on both root components. How do I make it so that I won't have to repeat the child components?

In JSX, it's pretty straightforward. I just have to assign the child component to a variable:

const label = <span class="btn-label">{text}</span>

return (type === 'link') 
  ? <a href={href}>{label}</a>
  : <button type={type}>{label}</button>

Upvotes: 1

Views: 236

Answers (2)

Decade Moon
Decade Moon

Reputation: 34306

In this situation, I would probably opt to write the render function directly since the template is small (with or without JSX), but if you want to use a template then you can use the <component> component to dynamically choose what you want to render as that element, like this:

Vue.component('custom-button', {
  template: '#custom-button',
  props: [
    'type',
    'href',
  ],
  computed: {
    props() {
      return this.type === 'link'
        ? { is: 'a', href: this.href }
        : { is: 'button', type: this.type };
    },
  },
});

new Vue({
  el: '#app',
});
<script src="https://rawgit.com/vuejs/vue/dev/dist/vue.js"></script>

<div id="app">
  <custom-button type="button">Button</custom-button>
  <custom-button type="submit">Submit</custom-button>
  <custom-button type="link" href="http://www.google.com">Link</custom-button>
</div>

<template id="custom-button">
  <component v-bind="props">
    <span class="btn-label"><slot></slot></span>
  </component>
</template>

Upvotes: 2

bbsimonbb
bbsimonbb

Reputation: 29020

Well you could always create a locally registered component...

// in custom-button.vue
components : {
    'label' : {template : '<span class="btn-label"><slot></slot></span>'}
}

Upvotes: 2

Related Questions