Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vuejs v-for on inline elements trims whitespace

When looping over an array (or object) with v-for on an inline element, vuejs does not render whitespace around said element.

For example, I have this html:

<div id="app">
    Vue Rendering<br>
    <a v-for="fruit in fruits" v-bind:href="fruit.url" v-html="fruit.label"></a>

    </div>
    <div>
    Navite rendering<br>
    <a href="apple.html">Apple</a>
    <a href="banana.html">Banana</a>
    <a href="peach.html">Peach</a>
</div>

and this javascript:

var fruits = [
    {
        label: 'Apple',
        url: 'apple.html'
    },
    {
        label: 'Banana',
        url: 'banana.html'
    },
    {
        label: 'Peach',
        url: 'peach.html'
    }
];

var app = new Vue({
    el: '#app',
    data: {
        fruits: fruits
    }
});

When Vue renders this, it deletes the spaces between the links. See this jsfiddle.

How can I counter this behaviour ?

like image 413
G2N Avatar asked Jan 24 '18 14:01

G2N


2 Answers

From the Docs on List Rendering > v-for on a <template>

Similar to template v-if, you can also use a <template> tag with v-for to render a block of multiple elements. For example:

<ul>
 <template v-for="item in items">
   <li>{{ item.msg }}</li>
   <li class="divider" role="presentation"></li>
 </template>
</ul>

So in order to get sibling elements (and yeah, a breaking space character &#32; would count as one), you'll have to add the loop to a parent <template> container and then include any elements / spacing you want in the looped contents like this:

<template v-for="fruit in fruits" >
  <span>{{fruit}}</span>&#32;
</template>

As of Vue 2.x+, templates trim any breaking space characters, even if they are escaped.

Instead, you can add a slot or text interpolation like this:

<template v-for="fruit in fruits" >
  <span>{{fruit}}</span><slot> </slot>
</template>
<template v-for="fruit in fruits" >
  <span>{{fruit}}</span>{{ ' ' }}
</template>

If you only want spaces in-between elements, you can output the space conditionally:

<template v-for="(fruit, i) in fruits" >
  <span>{{fruit}}</span>{{ i < fruits.length -1 ? ', ': '' }}
</template>

Demo in Stack Snippets

var app = new Vue({
    el: '#app',
    data: {
        fruits: ["apple", "banana", "carrot"]
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.0/vue.js"></script>

<div id="app">
    <template v-for="(fruit, i) in fruits" >
      <span>{{fruit}}</span>{{ i < fruits.length -1 ? ', ': '' }}
    </template>
</div>

Further Reading:
Issue #1841 - Suggestion: v-glue / v-for element joins

like image 53
KyleMit Avatar answered Oct 07 '22 02:10

KyleMit


I had a case where I needed to wrap each character (including spaces) of a string in a <span> and solved it this way.

<template v-for="(letter, i) in 'My text with spaces'">
    <span v-if="letter !== ' '">{{ letter }}</span>
    <span v-else>&nbsp;</span>
</template>
like image 2
Leopold Kristjansson Avatar answered Oct 07 '22 03:10

Leopold Kristjansson