javascript - Vue component renders only the first element in the template DOM - Stack Overflow

I have a Vue ponent inside a Vue loop on my website. Here's the JS file:Vueponent('fb-questio

I have a Vue ponent inside a Vue loop on my website. Here's the JS file:

Vueponent('fb-question-text', {
  props: ['question'],
  template:
    '<label>Prompt</label><input type="text" class="form-control" v-model="question.prompt"><a href="javascript:void" class="fb-remove">Remove</a>'
});

var questionList = new Vue({
  el: '#questions',
  data: {
    questions: [
      {
        type: 'text',
        id: 'question1',
        prompt: ''
      },
      {
        type: 'choice',
        id: 'question2',
        prompt: '',
        choices: ['', '']
      }
    ]
  }
});

This is what my HTML file looks like:

<ul id="questions">
    <li v-for="(question, index) in questions">
        <h4>Question {{ index + 1 }}</h4>
        <fb-question-text v-if="question.type === 'text'" :question="question"></fb-question-text>
    </li>
</ul>

As you can see, I am trying to render the fb-question-text ponent if the question.type is of type "text". While the <li> elements do render in the page, the ponent template does not render entirely. Only the first DOM element inside the template is rendered (in this case, the <label> element). The input box and <a> that are inside the ponent do not get rendered for some reason. When I remove the label, the input box gets rendered but nothing after it.

Can someone tell me what is going on?

I have a Vue ponent inside a Vue loop on my website. Here's the JS file:

Vue.ponent('fb-question-text', {
  props: ['question'],
  template:
    '<label>Prompt</label><input type="text" class="form-control" v-model="question.prompt"><a href="javascript:void" class="fb-remove">Remove</a>'
});

var questionList = new Vue({
  el: '#questions',
  data: {
    questions: [
      {
        type: 'text',
        id: 'question1',
        prompt: ''
      },
      {
        type: 'choice',
        id: 'question2',
        prompt: '',
        choices: ['', '']
      }
    ]
  }
});

This is what my HTML file looks like:

<ul id="questions">
    <li v-for="(question, index) in questions">
        <h4>Question {{ index + 1 }}</h4>
        <fb-question-text v-if="question.type === 'text'" :question="question"></fb-question-text>
    </li>
</ul>

As you can see, I am trying to render the fb-question-text ponent if the question.type is of type "text". While the <li> elements do render in the page, the ponent template does not render entirely. Only the first DOM element inside the template is rendered (in this case, the <label> element). The input box and <a> that are inside the ponent do not get rendered for some reason. When I remove the label, the input box gets rendered but nothing after it.

Can someone tell me what is going on?

Share Improve this question edited Dec 16, 2017 at 17:32 Abdennour TOUMI 93.8k42 gold badges268 silver badges269 bronze badges asked Dec 16, 2017 at 17:20 JackHJackH 4,7454 gold badges38 silver badges64 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 8

Templates must have a single root element.

<span>
  <label>Prompt</label>
  <input type="text" class="form-control" v-model="question.prompt">
  <a href="javascript:void" class="fb-remove">Remove</a>
</span>

Your fb-question-text is only allowed to have one root element. You need to wrap that in a div.

Add <div> around template html

Vue.ponent('fb-question-text', {
    props: ['question'],
    template: '<div><label>Prompt</label><input type="text" class="form-control" v-model="question.prompt"><a href="javascript:void" class="fb-remove">Remove</a></div>'
});

var questionList = new Vue({
    el: '#questions',
    data: {
        questions: [
            {
                type: 'text',
                id: 'question1',
                prompt: ''
            },
            {
                type: 'choice',
                id: 'question2',
                prompt: '',
                choices: [ '' , '' ]
            }
        ]
    }
});
<script src="https://cdnjs.cloudflare./ajax/libs/vue/2.5.11/vue.js"></script>
<ul id="questions">
    <li v-for="(question, index) in questions">
        <h4>Question {{ index + 1 }}</h4>
        <fb-question-text v-if="question.type === 'text'" :question="question"></fb-question-text>
    </li>
</ul>

For a similar question I purpose an other answer : Vue js error: Component template should contain exactly one root element

copy paste here :

if, for any reasons, you don't want to add a wrapper (in my first case it was for <tr/> ponents), you can use a functionnal ponent.

Instead of having a single ponents/MyCompo.vue you will have few files in a ponents/MyCompo folder :

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

With this structure, the way you call your ponent won't change.

ponents/MyCompo/index.js file content :

import File from './File';
import Avatar from './Avatar';   

const monSort=(a,b)=>b-a;

export default {
  functional: true,
  name: 'MyCompo',
  props: [ 'someProp', 'plopProp' ],
  render(createElement, context) {
    return [
        createElement( File, { props: Object.assign({light: true, sort: monSort},context.props) } ),
        createElement( Avatar, { props: Object.assign({light: false, sort: monSort},context.props) } )
    ]; 
  }
};

And if you have some function or data used in both templates, passed them as properties and that's it !

I let you imagine building list of ponents and so much features with this pattern.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744791179a4593923.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信