manidos
manidos

Reputation: 3464

Vues - How to use v-for and scoped slots in render function

I have a component that renders navigation links. It's based on scopedSlots feature. The component is working fine, but I'd like to improve it. This is how it's currently used:

<horizontal-navigation :items="items" #default="{ item }">
  <navigation-item :item="item"></navigation-item>
</horizontal-navigation>

Array of items looks like this:

[
  { path: '/about', title: 'About' },
  { path: '/', title: 'Home' }
]

Here's HorizontalNavigation component template:

<template>
    <div class="horizontal-navigation">
      <slot v-for="(item, index) in items" :key="index" :item="item"></slot>
    </div>
</template> -->

Here's NavigationItem component template

<template>
    <router-link class="navigation-item" :path="item.path">{{ item.title }}</router-link>
</template>

I'm trying to replace HorizontalNavigation component's template with a render function, because I want to make this component to render links with a default styling when no slot content is provided.

Here's where I'm stuck:

  render () {
    const options = {
      class: 'horizontal-navigation'
    }
    let children = []
    if (this.$slots.default) {
      children = this.$slots.default({ items: this.items }) // NEED TO ITERATE ITEMS TO CREATE INSTANCES OF A COMPONENT PASSED TO DEFAULT SLOT
    }
    return h('div', options, children)
  }

The closest thing I found in the docs is this:

render() {
  if (this.items.length) {
    return Vue.h('ul', this.items.map((item) => {
      return Vue.h('li', item.name)
    }))
  } else {
    return Vue.h('p', 'No items found.')
  }
}

Any advice?

Upvotes: 1

Views: 1455

Answers (1)

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

In the template try to use conditional rendering to render the slot or the fallback content :

 <div class="horizontal-navigation">
   <template  v-for="(item, index) in items" >
       <template v-if="$slots.default">
           <slot  :item="item"></slot>
       </template>
       <template v-else>
          <router-link class="navigation-item" :path="item.path">{{ item.title }}</router-link>
       </template>         
   </template>
</div>    

Upvotes: 1

Related Questions