Vue js error: component template must contain exactly one root element

I do not know what the error is, so far I am testing through the console log to check the changes after selecting the file (for download).

When I run $ npm run watch , I get the following error:

"Webpack browsing files ...

95% radiation

ERROR Failed to compile with 1 error
19:42:29

error. / resources / assets / js / components / File.vue

(The emitted value instead of the Error instance) Vue template syntax Error:

A component template must contain exactly one root element. if you use v-if on multiple elements, use v-else-if to link them instead.

@. / resources / assets / js / components / AvatarUpload.vue 5: 2-181 @. /resources/assets/js/app.js @ multi. / resources / assets / js / app.js. /resources/assets/sass/app.scss "

My file.vue

 <template> <div class="form-group"> <label for="avatar" class="control-label">Avatar</label> <input type="file" v-on:change="fileChange" id="avatar"> <div class="help-block"> Help block here updated 4 🍸 ... </div> </div> <div class="col-md-6"> <input type="hidden" name="avatar_id"> <img class="avatar" title="Current avatar"> </div> </template> <script> export default{ methods: { fileChange(){ console.log('Test of file input change') } } } </script> 

Any ideas on how to solve this? What is the actual error?

+33
source share
6 answers

You have two root elements in your template.

 <div class="form-group"> ... </div> <div class="col-md-6"> ... </div> 

And you need one.

 <div> <div class="form-group"> ... </div> <div class="col-md-6"> ... </div> </div> 

Essentially, in Vue, you should only have one root element in your templates .

+85
source

You need to wrap all html in one element.

 <template> <div> <div class="form-group"> <label for="avatar" class="control-label">Avatar</label> <input type="file" v-on:change="fileChange" id="avatar"> <div class="help-block"> Help block here updated 4 🍸 ... </div> </div> <div class="col-md-6"> <input type="hidden" name="avatar_id"> <img class="avatar" title="Current avatar"> </div> </div> </template> <script> export default{ methods: { fileChange(){ console.log('Test of file input change') } } } </script> 
+13
source

if for some reason you do not want to add a wrapper (in my first case it was for <tr/> components), you can use a functional component.

Instead of having one components/MyCompo.vue you will have several files in the components/MyCompo :

  • components/MyCompo/index.js
  • components/MyCompo/File.vue
  • components/MyCompo/Avatar.vue

With this structure, the way you name your component will not change.

components/MyCompo/index.js the components/MyCompo/index.js :

 import File from './File'; import Avatar from './Avatar'; const commonSort=(a,b)=>ba; export default { functional: true, name: 'MyCompo', props: [ 'someProp', 'plopProp' ], render(createElement, context) { return [ createElement( File, { props: Object.assign({light: true, sort: commonSort},context.props) } ), createElement( Avatar, { props: Object.assign({light: false, sort: commonSort},context.props) } ) ]; } }; 

And if you have any function or data used in both templates, they are passed as properties and what it is!

I will allow myself to introduce a list of components and so many functions with this template.

+6
source

For a more complete answer: http://www.compulsivecoders.com/tech/vuejs-component-template-should-contain-exactly-one-root-element/

But basically:

  • Currently, a VueJS template can contain only one root element (due to a rendering problem).
  • In those cases when you really need to have two root elements, because the HTML structure does not allow you to create a parent element for transfer, you can use a vue fragment .

To install it:

 npm install vue-fragment 

To use this:

 import Fragment from 'vue-fragment'; Vue.use(Fragment.Plugin); // or import { Plugin } from 'vue-fragment'; Vue.use(Plugin); 

Then in your component:

 <template> <fragment> <tr class="hola"> ... </tr> <tr class="hello"> ... </tr> </fragment> </template> 
+3
source

The template component must contain exactly one root element. If you use v-if for multiple elements, use v-else-if instead.

The right approach

 <template> <div> <!-- The root --> <p></p> <p></p> </div> </template> 

Wrong approach

 <template> <!-- No root Element --> <p></p> <p></p> </template> 

Multi-root components

The way to solve this problem is to use functional components, which are components in which you should not transmit any reactive data, which means that the component will not monitor any changes in the data, nor will it update itself when something changes in the parent component.

Since this is a workaround, it comes with a price, no lifecycle hooks are passed to the functional components, they are smaller than the instance, and you can no longer reference this , and everything is transferred with context.

Here's how you can create a simple functional component.

 Vue.component('my-component', { // you must set functional as true functional: true, // Props are optional props: { // ... }, // To compensate for the lack of an instance, // we are now provided a 2nd context argument. render: function (createElement, context) { // ... } }) 

Now that we have examined functional components in detail, let's look at how to create multi-root components, for this I will give a general example.

 <template> <ul> <NavBarRoutes :routes="persistentNavRoutes"/> <NavBarRoutes v-if="loggedIn" :routes="loggedInNavRoutes" /> <NavBarRoutes v-else :routes="loggedOutNavRoutes" /> </ul> </template> 

Now, if we look at the NavBarRoutes template

 <template> <li v-for="route in routes" :key="route.name" > <router-link :to="route"> {{ route.title }} </router-link> </li> </template> 

We cannot do something like this, we will violate the restriction of one root component

Solution Make this component functional and use a render

 { functional: true, render(h, { props }) { return props.routes.map(route => <li key={route.name}> <router-link to={route}> {route.title} </router-link> </li> ) } 

Here you have it you created a multi-root component, happy coding

Link for more information visit: https://blog.carbonteq.com/vuejs-create-multi-root-components/

0
source

I was baffled because I knew that VueJS should contain only 1 root element, and yet I still get the same "template syntax error. The component template must contain exactly one root element ..." on an extremely simple component . Turns out I just incorrectly entered </template> as </tempate>, and this gave me the same error in several files that I copied and pasted. So check your syntax for errors in your component.

0
source

Source: https://habr.com/ru/post/1269656/


All Articles