Vue: Interpolating a dynamic number of props? - vue.js

I am trying to make a dynamic component that the parent can pass in data to shape it. I am stuck on how to interpolate the index as part of passed in prop. I assume it's possible but I think I'm just interpolating it incorrectly.
// Parent
<div>
<BoxComponent
:numberOfBoxes=3
boxTitle0="Hi"
boxTitle1="Foo"
boxTitle2="Test"
>
</BoxComponent>
</div>
//BoxComponent
<div v-for="(box,index) in numberOfBoxes">
<div class="title">
{{boxTitle + ${index}}} <-----
</div>
</div>

Like #yuriy636 also proposed, I would suggest you pass an array of objects named "boxes".
If you assume boxes looks like this:
[
{title: "Hi"},
{title: "Foo"},
{title: "Test"}
]
You can simply do this:
// Parent
<div>
<box-component :boxes="boxes"/>
</div>
//BoxComponent
<div v-for="box in boxes">
<div class="title">
{{ box.title }}
</div>
</div>

Related

Has anyone came across this problem? [vue/no-multiple-template-root] The template root disallows 'v-for' directives.eslint-plugin-vue

It is actually a three problems in one:
[vue/no-multiple-template-root]
The template root disallows 'v-for' directives.eslint-plugin-vue
[vue/no-parsing-error]
Parsing error: Expected to be an alias, but got empty.eslint-plugin-vue
[vue/valid-v-for]
Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive.eslint-plugin-vue
Can anyone help me please I am so fed with searching online for it everywhere
enter code
<template>
<div class="post" v-for="post" in posts >
<div><strong>Title</strong>{{post.title}}</div>
<div><strong>Desctiption</strong>{{post.body}}</div>
</div>
</template>
<script>
export default{
data(){
return{
posts:[
{ id: 1, title: 'javascript', body: "the desctiption"},
{ id: 2, title: 'javascript2', body: "the desctiption"},
{ id: 3, title: 'javascript3', body: "the desctiption"},
]
}
}
}
Vue.js must have a single element at the root of the template. If you have av-for directive, when the DOM is populated there will be multiple <div> elements at the root, which Vue does not allow.
So you just need to add another <div> element to surround your v-for div.
Then, move the in posts within your quotes and add a :key
<template>
<div>
<div class="post" v-for="post in posts" :key="post.id">
<div><strong>Title</strong>{{post.title}}</div>
<div><strong>Desctiption</strong>{{post.body}}</div>
</div>
</div>
</template>
In vue two you should one root element, using v-for loop will render multiple elements in the template like :
<div class="post" >
...
</div>
<div class="post" >
...
</div>
to avoid this add an extra div and bind key to the post id :key="post.id":
<template>
<div class="posts">
<div class="post" v-for="post in posts" :key="post.id">
<div><strong>Title</strong>{{post.title}}</div>
<div><strong>Desctiption</strong>{{post.body}}</div>
</div>
</div>
</template>

Vue - passing v-for index from parent to child component

I've done the research but can't find a good answer. My parent and child component code is below. How do I pass the index for the v-for loop in the parent to the child component for use there? I want to hide any of the gauges past #4 for mobile screens, but show all of them on a desktop.
Parent:
<div class="col-md-8 col-xs-6">
<div class="row flex-nowrap">
<data-block
v-for="(gauge, index) in device.gauges"
:metric="gauge.metric"
:value="gauge.value"
:unit="gauge.unit"
:alarm="gauge.alarm"
:idx="index">
</data-block>
</div>
</div>
Child:
app.component('data-block', {
props: ['alarm', 'metric','value','unit','idx'],
template: `<div v-bind:class="'col card px-0 text-center border' + ((alarm) ? ' border-danger':' border-success') + ((idx > 3) ? ' d-none d-md-block':'')">\
<div class="card-header p-1">{{metric}}</div>\
<div class="card-body p-1 align-middle">\
<h1 class=" text-center display-1 font-weight-normal text-nowrap">{{value}}</h1>\
</div>\
<div class="card-footer p-1">{{unit}}</div>\
</div>`,
created: ()=> console.log(this.idx) //yields "undefined"
})
You're passing the idx prop correctly, but Instead of checking its value inside created hook, try displaying it in the template instead, to make sure it's not an issue with timing (it might not be defined when the child component is created):
<div>{{idx}}</div>
Also, to make the code easier to read and write, I would suggest you to move the static classes to class attribute and the dynamic classes to v-bind:class attribute, and also make it multiline:
template: `
<div
class="col card px-0 text-center border"
:class="{
'd-none d-md-block': idx > 3,
'border-danger': alarm,
'border-success': !alarm
}"
>
...
`

How to have a scoped toggle variable in VueJS

I'm coming from an AngularJS background where the ng-repeat has a scoped variables and I'm trying to figure out how to achieve a similar result without the need to create a new component which seems overkill for a lot of situations.
For example:
<div class="item" v-for="item in items">
<div class="title">{{item.title}}</div>
<a #click="showMore = !showMore">Show more</a>
<div class="more" v-if="showMore">
More stuff here
</div>
</div>
In AngularJS that code would work great, but in VueJS if you click on show more it causes the variable to update for every item in the items list, is there anyway to create a local scoped variable inside of the v-for without the need to make a new component?
I was able to get it to work by having the showMore variable be something like #click="showMore = item.id" and then v-if="showMore.id = item.id" but that also seems like too much extra complexity for something that should be much simpler? The other problem with that approach is you can only get one item to show more rather than allow for multiple items to be toggled shown at once.
I also tried changing the items model to include item.showMore but once again that adds more complexity and it causes a problem if you need to update an individual item since the model is changed.
Are there any simpler approaches to this?
What do you think about this: CODEPEN
<template>
<div>
<h1>Items</h1>
<div v-for="item in items"
:key="item.id"
class="item"
>
{{item.name}}
<button #click="show=item.id">
Show More
</button>
<div v-if="item.id == show">
{{item.desc}}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{id:1, name:"One", desc: "Details of One"},
{id:2, name:"Two", desc: "Details of Two"},
{id:3, name:"Three", desc: "Details of Three"}
],
show: null
};
}
};
</script>
<style>
.item{
padding: 5px;
}
</style>

How to make iterations using v-for directive on nested array (array in array)

I am new to Vue and I came upon a situation that I would like to have some advice on.
In my js file I have some arrays that contain some data that I would like to insert in a table:
const d1=[{col1:"aaa1",col2:"bbb1",col3:"ccc1",col4:"ddd1",col5:"eee1"},
{col1:"aaa2",col2:"bbb2",col3:"ccc2",col4:"ddd2",col5:"eee2"}]
const d2=[{col1:"fff1",col2:"ggg1",col3:"hhh1",col4:"iii1",col5:"jjj1"},
{col1:"aaa2",col2:"bbb2",col3:"ccc2",col4:"ddd2",col5:"eee2"}]
then I saved the two arrays in another variable called availableData
const availableData=[d1,d2];
my vue instance as follows:
new Vue({
el: '#c1',
data: {
availableData,
}
});
In my HTML I am trying to add a for loop(v-for) in my row div so the row can display each of data in my availableData variable, but I am having some problems trying to pass d1 to the first row and d2 to the second,
<div id="c1" class="columns">
// ...some code
<div class="row" v-for="data in availableData">
<div class="cell">
{{data.col1}}
</div>
<div class="cell">
{{data.col2}}
</div>
<div class="cell">
{{data.col3}}
</div>
<div class="cell">
{{data.col4}}
</div>
<div class="cell">
{{data.col5}}
</div>
</div>
</div>
Of course, the v-for statement is not correct since I am trying to iterate through the availableData array, if I were to write
v-for="data in availableData[i]"
then is there a way to pass a varaible like i to achieve iteration, or is this method not a plausible way to conduct?
You have several solutions to do what you want.
Solution # 1 :
You can alter the availableData to display all data like you want. You have just to flat you array like this : const availableData=[...d1, ...d2];
With such a code your availableData variable will have :
const availableData = [{col1:"aaa1",col2:"bbb1",col3:"ccc1",col4:"ddd1",col5:"eee1"},
{col1:"aaa2",col2:"bbb2",col3:"ccc2",col4:"ddd2",col5:"eee2"},
{col1:"fff1",col2:"ggg1",col3:"hhh1",col4:"iii1",col5:"jjj1"},
{col1:"aaa2",col2:"bbb2",col3:"ccc2",col4:"ddd2",col5:"eee2"}]
Solution # 2
You can make a double iteration in your template :
<div class="data" v-for="data in availableData">
<div class="row" v-for="row in data">
<div class="cell">
{{row.col1}}
</div>
<div class="cell">
{{row.col2}}
</div>
<div class="cell">
{{row.col3}}
</div>
<div class="cell">
{{row.col4}}
</div>
<div class="cell">
{{row.col5}}
</div>
</div>
</div>

Render HTML properly for JSON text in Vue component

I am iterating through a list of props that consists of simple HTML markup
<div class="columns medium-4 large-4" v-for="keyOffer in keyOffers">
<p>{{ keyOffer.head }}</p>
<p>{{ keyOffer.sub }}</p>
</div>
and one of the props looks like this
keyOffers: [
{
id: 'offerSecond',
head: '4G network',
sub: 'Dedicated to bringing you the <span class="u_underline">best mobile service</span>
},
]
but in the output the <span> gets printed and not applied.
Any help?
Use v-html directive:
<div class="columns medium-4 large-4" v-for="keyOffer in keyOffers">
<p>{{ keyOffer.head }}</p>
<p v-html="keyOffer.sub"></p>
</div>
Ref: RawHTML