-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
enable <template>
as component root element when it contains only one logical node
#5758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@caikan For the second case, you can change the code as below.
Because your code may cause two div element in template which is not allowed in vue. |
I'm curious, why can't the template contain multiple nodes and just become |
@larryu Thanks. But sometimes I want to use the wrapper elements as few as posiblle. |
This would technically require much more complex analyzing of the template structure and I'm not sure if it's worth it when you can achieve the equivalent with this: <div v-if="!conditionA"></div>
<div v-else-if="conditionC"></div>
<div v-else-if="conditionD"></div>
<div v-else></div> |
If the implementation process is complex, can we temporarily use a warning instead of a compilation error and allow its first child node as the root element? BTW: OK, I think I may use |
+1, feature request. had to make <!-- some-table.vue -->
<table>
<tr>
<copy-first :arr="arr">
<template slot="elem" slot-scope="s">
<td>{{s.index}}</td>
</template>
</copy-first>
</tr>
</table>
<style>
tr th:nth-child(1), tr th:nth-child(2),
tr td:nth-child(1), tr td:nth-child(2) {
/* hack of fixed column */
}
</style> <!-- copy-first.vue -->
<template>
<slot v-if="arr[0]" name="elem" :index="0" :elem="arr[0]"></slot>
<slot v-for="(elem, i) in arr" :key="i" name="elem" :index="i" :elem="elem"></slot>
</template>
<script>
export default {
name: 'copy-first',
props: { arr: Array }
}
</script> |
+1 When it comes to generating tables it simplifies things |
+1 Perhaps something as simple as allowing |
React has a nice implementation of this in the current version: https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html |
How about add fragment for root like a Web Component with shadow root. |
Another use for this is that am refactoring a component in order to make it easier to maintain. It's a form and various parts of it fall on a CSS grid. The extra wrapper required when I group several related elements in the same component is causing the grid to treat that whole component as one grid-item. I'm sure I can work around that, but hope we end up with a fragment syntax like react's (if we don't already have such a thing?) |
My primary need for this is to maintain valid HTML. I have a component that generates table rows with different rendering depending on different logic, and I can't give the <tr>'s a div parent without violating HTML rules. Accessibility is a priority of this table, so good HTML structure and semantics are important. I'm fairly certain I can satisfy my need with render(), but it's a bummer that I have to sacrifice a clean declarative implementation. |
@njleonzhang For what it's worth, though I haven't tried it yet, I recently learned about portal-vue feel a workaround may be possible and relatively easy with it for many cases where the component structure Vue needs is different to the DOM structure we want to actually end up with (https://github.com/LinusBorg/portal-vue). I'm looking forward to playing with it. I will post a demo if I get time to create a clean example, but wanted to go ahead and share the library anyway so others can maybe check it out. |
@markbrouch currently I make all grid items in one component and provide a |
This comment has been minimized.
This comment has been minimized.
The whole issue could be irrelevant if fragments were supported instead. What's the reason why it's disallowed really? The patching algorithm already works on arrays, it's just the fact that it starts from node to iterate on it's children, instead of starting iterating on array to visit all nodes in this array. I had similar issue with vuelidate once, where I ported simplified version of DOM patching into validation tree to find differences in "virtual validation tree". It was required to support multiple nodes on each level, as there were no guarantees about data shapes. It turned out it was pretty easy to just turn the algorithm upside down to treat the array as entry point. |
This is a very important technology.
thats will be very good way to create multi root-element in template. We do not need to add an extra element to wrap it. Actually, this issue has been referred to by more than one issue. Can solve it as soon as possible. Finally, in any case Thanks for vue community.👍 |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
+1 Rendering tables is the most common practical scenario where this would be useful, and I strongly agree with this request. Is this still under consideration? Or is there a workaround I don't know about yet? |
Another possible solution would be for vue to have a switch statement for the contents like
|
@RPainter8West If I understand your need correctly, I think this is already possible with Vue's built-in dynamic component feature: https://vuejs.org/v2/guide/components.html#Dynamic-Components, though maybe docs don't explore the potential of this enough. I've used this pattern in the past:
Where So for the use case where a person wants to render only one of a group of components, with no extra wrapper element, I think it's already covered. |
Totally agree with @maxnorth . I am trying to implement a simple table with data coming from Algolia Vue InstantSearch and the |
the same problem here with tr that is wrapped with a div |
The requirement of wrapping with a div, or some other element, breaks content flow all the time.... There has got to be a way around this? |
All I honestly want from a Parent:
Child:
All in order to get this beauty:
If I use a work-around like such then it breaks my CSS:
because I get this instead:
😢 |
Did someone find a solution for this table problem ? |
As a (temporary) solution, you can use <template>
<fragment>
Your content here
</fragment>
</template> Output: <!--fragment#1690ec9267a#head-->
Your content here
<!--fragment#1690ec9267a#tail--> |
The good news is that Fragments are included in Vue 3 so we'll have multiple root elements in a template! https://vueschool.io/articles/vuejs-tutorials/exciting-new-features-in-vue-3/ |
Until Vue 3 version comes out I would strongly recommend using a method proposed by @FedericoBiccheddu. If for any reason, you don't want to use the third party lib, you can use this hack: <template v-if="true">
<p>Sibling 1</p>
<p>Sibling 2</p>
</template> Unfortunately, this solution is limiting (same as in conditional rendering), so you can't return a component that has 2 siblings without root element. This won't work: <template>
<template v-if="true">
<p>Sibling 1</p>
<p>Sibling 2</p>
</template>
</template> This will: <template>
<div>
<template v-if="true">
<p>Sibling 1</p>
<p>Sibling 2</p>
</template>
</div>
</template> |
This deserves a lot more upvotes! |
Duplicate of #7088 Here are the current alternatives: #7088 (comment) |
What problem does this feature solve?
From compiling template error message:
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.
But
Cannot use
as component root element because it may contain multiple nodes.
So I can't use
<template>
as component root element even if it contains only one node.What does the proposed API look like?
Allow the following code as component root.
Do not allow the following code as component root.
The text was updated successfully, but these errors were encountered: