Right now, I\'m trying to make a website that shows recent news posts which is supplied my NodeJS API.
I\'ve tried the following:
HTML
You can have multiple root elements (or components) using render functions
A simple example is having a component which renders multiple <li> elements:
<template>
<li>Item</li>
<li>Item2</li>
... etc
</template>
However the above will throw an error. To solve this error the above template can be converted to:
export default {
functional: true,
render(createElement) {
return [
createElement('li', 'Item'),
createElement('li', 'Item2'),
]
}
}
But again as you probably noticed this can get very tedious if for example you want to display 50 li items. So, eventually, to dynamically display elements you can do:
export default {
functional: true,
props: ['listItems'], //this is an array of `<li>` names (e.g. ['Item', 'Item2'])
render(createElement, { props }) {
return props.listItems.map(name => {
return createElement('li', name)
})
}
}
INFO in those examples i have used the property functional: true but it is not required of course to use "render functions". Please consider learning more about functional componentshere
Multiple root elements are not supported by Vue (which caused by your v-for directive, beacause it may render more than 1 elements). And is also very simple to solve, just wrap your HTML into another Element will do.
For example:
<div id="app">
<!-- your HTML code -->
</div>
and the js:
var app = new Vue({
el: '#app', // it must be a single root!
// ...
})
Vue requires that there be a single root node. However, try changing your html to this:
<div id="news" >
<div class="media" v-for="item in posts">
<h4 class="media-heading">{{item.title}}</h4>
<p>{{item.msg}}</p>
</div>
</div>
This change allows for a single root node id="news" and yet still allows for rendering the lists of recent posts.
The simplest way I've found of adding multiple root elements is to add a single <div> wrapper element and make it disappear with some CSS magic for the purposes of rendering.
For this we can use the "display: contents" CSS property. The effect is that it makes the container disappear, making the child elements children of the element the next level up in the DOM.
Therefore, in your Vue component template you can have something like this:
<template>
<div style="display: contents"> <!-- my wrapper div is rendered invisible -->
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</div>
</template>
I can now use my component without the browser messing up formatting because the wrapping <div> root element will be ignored by the browser for display purposes:
<table>
<my-component></my-component> <!-- the wrapping div will be ignored -->
</table>
Note however, that although this should work in most browsers, you may want to check here to make sure it can handle your target browser.
Define a custom directive:
Vue.directive('fragments', {
inserted: function(el) {
const children = Array.from(el.children)
const parent = el.parentElement
children.forEach((item) => { parent.appendChild(item) })
parent.removeChild(el)
}
});
then you can use it in root element of a component
<div v-fragments>
<tr v-for="post in posts">...</tr>
</div>
The root element will not be rendered in DOM, which is especially effective when rendering table.