Vue: (Feature) Enable multiple parent nodes in component

Created on 1 Feb 2017  Â·  3Comments  Â·  Source: vuejs/vue

I'm currently facing a framework shortage with Vue that would be a nice to have. I know it's complex but it would be good to have it appointed maybe for a future.

The idea is to enable to iterate through a list if items and within those items iterate through a list of subitems, but when rendering all of them, put them all at the same level.

Here's an example:

<table>
  <!-- item -->
  <tr></tr>

  <-- subitems -->
  <tr></tr>
  <tr></tr>
  <tr></tr> 
</table>

And the js data would be something like:

items: [
    {key1: 'val1', subitems: [ {subkey1: 'subval1' }]},
    {key1: 'val1', subitems: [ {subkey1: 'subval1' }]},
    {key1: 'val1', subitems: [ {subkey1: 'subval1' }]}
]

So there are multiple options to address this issue, some of them without changing Vue.

Without changing Vue:
1) Use <div> and a grid layout to create a table look and feel.
Not possible by requirement. We need to use <tr>

2) Add all items and its subitems sequentially in an array and access it via a computed property. Something like "flattening" the list.
Little dirty as it would require some v-if conditioning in the layout in case the subitems have different keys than the items.

Changing Vue:
1) Allow multiple parent nodes for components so that when rendering. This way I can define a component as:
<item-row></item-row>

and the template would look like:

<tr class="item-row">...</tr>
<tr v-for="subitem in item.subitems>...</tr>

Of course the item would be passed as a prop of the component.

Here's a fiddle with the problematic:
https://jsfiddle.net/ehjmmoat/

Most helpful comment

Also note, that you can use template tag (but this example will only work with single file components, due to html parsing caveats):

<table>
  <template v-for="item in list">
    <tr>{{ item.title }}</tr>
    <tr v-for="subitem in item.subitems">{{ subitem.title }}</tr>
  </template>
</table>

All 3 comments

Allow multiple parent nodes for components

This won't happen anytime in the forseeable future. The requirement for a root node is deeply rooted (no pun intended) in the way the virtual DOM and component system works. Changing this would practically require a rewrite of a major part of the framework.

Therefore, I will close this issue.

About your problem: The best approach would probably be to use a computed property. The "nasty v-if's" could prevented by normalizing the id names and mayber add a "type" property to tell top items from sub items.

Alternatively, you could consider to wrap this in a functional component, which can return multiple root nodes (because, beingg a functional component, it has no component instance)

If you need further help, please post on our forum: forum.vuejs.org

Also note, that you can use template tag (but this example will only work with single file components, due to html parsing caveats):

<table>
  <template v-for="item in list">
    <tr>{{ item.title }}</tr>
    <tr v-for="subitem in item.subitems">{{ subitem.title }}</tr>
  </template>
</table>

Alternatively, you could consider to wrap this in a functional component, which can return multiple root nodes (because, being a functional component, it has no component instance)

@LinusBorg Should this also work in single files components ?

I'm getting an error (Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.) with:

<template functional>
    <div class="form-field">
    </div>
    <div class="form-field">
    </div>
</template>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

fergaldoyle picture fergaldoyle  Â·  3Comments

loki0609 picture loki0609  Â·  3Comments

lmnsg picture lmnsg  Â·  3Comments

paceband picture paceband  Â·  3Comments

seemsindie picture seemsindie  Â·  3Comments