How to control the v-for times dynamically? - vue.js

How to control the v-for times dynamically?
I have a case, I want to generate 1->10 divs:
<div v-for="item in 10" style="background-color: red" >{{ item }}</div>
and I want to control the counts dynamically, it maybe 1->3, 2->8, 5-6, how can I do that?

You can add v-if:
<div v-for="item in 10" v-if="item >=min && item <= max" style="background-color: red" >{{ item }}</div>
you can change the min and max dynamically.

You can pass a property of your component's data as the number:
<div v-for="number in count">{{ number }}</div>
If you want to start counting from a different number, you can use a property for that too:
<div v-for="number in count">{{ start - 1 + number }}</div>
See it here in action: https://codepen.io/JosephSilber/pen/vjKBRg

Related

How do I retrieve the value of my key button and row in v-for using Vue.js?

I am new to Vue.js and I trying to learn now to use it. I have 3X3 structure of buttons
I have the following sample code:
<template v-for="row in 3">
<div class="row" :key="row">
<button #click="nextPlayer(button, row)" v-for="button in 3" :key="indexByrow(button, row)" :value="squares[indexByrow(button, row)]" class="square" style="width:40px;height:40px;"></button>
</div>
</template>
When I click, I want to pass the button and row to nextPlayer(button, row), and the indexByrow(button, row) to use those values in the methods, but I don't seem to have any values. My main goal is to change the value name when I click on it.
You need to make the below changes
<template v-for="(row, indx) in 3">
<div class="row" :key="indx">
<button #click="nextPlayer(button, row)" v-for="(button, indexer) in 3" :key="indexer" :value="squares[indexByrow(button, row)]" class="square" style="width:40px;height:40px;"></button>
</div>
</template>
Not sure if indexByrow is a computed property or method.
You need to modify the logic in indexByrow as well based on the above changes

Vue2 generated select triggers event for every other selects

I have a Vue2 project with Buefy extension. Then I have an array of objects which is rendered in the template with one select component for each item. Everything works, but if I trigger #input event on one of the select elements it triggers input event for all selects in the list. I dont understand what is wrong with that.
<div v-for="(inv, index) in pendingInvitations" :key="index" class="columns is-desktop">
<div class="column is-4">{{inv.email}}</div>
<div class="column is-4">
<b-field class="mb-5">
<b-select v-if="invitationRoles"
:input="changeInvitationRole(index)"
v-model="pendingInvitations[index].role"
:placeholder="role">
<option v-for="(value, key) in invitationRoles"
:key="key"
:value="value">
{{ value }}
</option>
</b-select>
</b-field>
</div>
</div>
...
changeInvitationRole(index){
console.log(index);
},
If I change the role and there are three items in the list the console.log() writes 0, 1, 2 as indexes for all items. Why it happens to me? I expect only current itmes index in the log.
Try replacing input with change

How to update an ancestral element class in response to child input change with Vue.js?

I'm using Vue (v2.6.11) and I want to add/remove a class on an ancestor (grandparent) element of an input (checkbox) when it's value is changed. There are an unknown number of checkboxes so they are generated using v-for on the element that I want to add/remove the class. I have a function registered with my Vue instance methods when the checkbox value is changed.
In my code below, the <label> is the element to which I want to add/remove the class in response to the checkbox value changing. I'm trying to resist the urge to apply an :id attribute to the label and then do a lookup in my updateCounter method that will use the id of the checkbox to find the label and add/remove the class using pure JS. Is there a more Vue-esque way to do this?
<label class="item"
v-for="item in myItems"
v-bind:key="item.id"
:for="'item'+item.id">
<div>
<input type="checkbox"
:id="'item'+item.id"
v-model="item.isAccepted"
#change="updateCounter($event)" />
<span>{{ item.name }}</span>
<span>{{ item.status }}</span>
</div>
<div>{{ item.date }}</div>
</label>
just use a dynamic class like so: :class="item.applyClass ? 'item' : ' ' " so put a property on the item and then you can dynamically change that in your updatedCounter function
You can do
<label class="item"
v-for="item in myItems"
v-bind:key="item.id"
:for="'item'+item.id"
:class="{test: item.isAccepted === true}">
<div>
<input type="checkbox"
:id="'item'+item.id"
v-model="item.isAccepted"
#change="updateCounter($event)" />
<span>{{ item.name }}</span>
<span>{{ item.status }}</span>
</div>
<div>{{ item.date }}</div>
This would apply test class only when is Accepted is true for that particular checkbox.

Vue to render tr array recursively

I have to create collapsible tree with table data using bootstrap. This look the following way
<tr><td>Parent node1</td><td>...</td><td>...</td></tr>
<tr><td>Subparent node1.1</td><td>...</td><td>...</td></tr>
<tr><td>Subsupparent node1.1.1</td><td>...</td><td>...</td></tr>
<tr><td>Subsupparent node1.1.2</td><td>...</td><td>...</td></tr>
<tr><td>Subparent node1.2</td><td>...</td><td>...</td></tr>
<tr><td>Subsupparent node2.1.1</td><td>...</td><td>...</td></tr>
<tr><td>Subsupparent node2.1.2</td><td>...</td><td>...</td></tr>
I decided to create Vue component rendering on each level html with own data and collection of children via recursion:
<template id="tree-item">
<tr :key="currentNode.id">
<span #click="setExpanded(currentNode)">
<div style="display: inline-block;">
<span class="treegrid-indent" :style="{width: 15 * level + 'px'}"></span>
<span class="treegrid-expander fa" :class="currentNode.isExpanded ?'fa-chevron-down':'fa-chevron-right'">
</span>
</div>
{{level}} {{currentNode.id}}
</span>
</tr>
<tree-item v-for="item in currentNode.items" :currentNode="item" :level="level+1"> </tree-item>
</template>
But i get Vue error:Component template should contain exactly one root element.
Are there any ways to solve the task?
If you can relax your requirements to use a list instead of table then you can try something like this:
<div class="folder_container">
<ul class="no_list no_space">
<FolderTree :folder="folders" :level="0"/>
</ul>
</div>
And the FolderTree component's template looks like this:
<template>
<li>
<div>
<div class="folder_name">{{ folder.name }}</div>
</div>
<ul v-if="folder.child && folder.child.length > 0" class="no_list no_space">
<FolderTree
v-for="(fold,idx) in folder.child"
:key="fold.id"
:folder="fold"
:level="level + 1"
:last="1 + idx === folder.child.length"
/>
</ul>
</li>
</template>
If you need to use a table - then you will have to somehow transform your nested objects into a linear list/array of items. Otherwise you won't be able to overcome the limitation for only 1 root element in templates (unless you use render functions).

VueJS: read div content from its id

In my first example, I have in my component's template:
<div id="hello">hello world</div>
When console.log(this.$refs['hello']) is called in myMethod(), I get undefined in the console.
In my second example, I have:
<div v-for="item in data">
<div :id="'hello-'+item.id">hello {{ item.id }}</div>
</div>
When console.log(this.$refs['hello-1']) is called in myMethod(), I also get undefined in the console.
What's wrong in my code ?
You cannot get element with refs by giving that element id. You should bind ref to that element. Here is an example:
<div v-for="item in data" :key="item.id">
<div :id="'hello-'+item.id" :ref="'hello-'+item.id">hello {{ item.id }}</div>
</div>
And also don't forget to bind key to your iterating elements with v-for