v-for with index on iterable collection vue js not recongnisable - vue.js

I'm currently iterating from results of array of key value
data: {
return {
results: [
[{id: 1, name: 'A1'}, {id: 2, name: 'B1'}, {id: 3, name: 'C1'}],
[{id: 4, name: 'A2'}, {id: 5, name: 'B2'}, {id: 6, name: 'C2'}],
[{id: 7, name: 'A3'}, {id: 8, name: 'B3'}, {id: 9, name: 'C3'}],
[{id: 10, name: 'A4'}, {id: 11, name: 'B4'}],
]
}
}
And I'm rending it using this
<div v-for="(items, index) in results" :key="index">
<div v-for="item in items" :key="item.id">
<v-card>
<v-card-title>{{item.name}}</v-card-title>
</v-card>
</div>
</div>
Is there a way I can exclude the rendering of parent div?

Another option: If the outer parent <div> is not needed and is only used for iteration, v-for on <template> can be used to generate a block of multiple elements inside it (only renders dom elems inside it iteratively).
When both iterative divs are not required
<template v-for="(items, index) in results">
<template v-for="item in items">
<v-card>
<v-card-title>{{item.name}}</v-card-title>
</v-card>
</template>
</template>
When the div parent immediate to v-card is not required:
<div v-for="(items, index) in results" :key="index">
<template v-for="item in items">
<v-card>
<v-card-title>{{item.name}}</v-card-title>
</v-card>
</template>
</div>
++UPDATE++
key binding can't be put on template for listing (iterating) because the way it is used to track and diff between acutal DOM elements nodes.Vue itself gives a nice warning for that in console.

You have an array in array
so look at this, I am using v-for in v-for.
I changed both section.
data: {
return {
results: [
[{id: 1, name: 'A1'}, {id: 2, name: 'B1'}, {id: 3, name: 'C1'}],
[{id: 4, name: 'A2'}, {id: 5, name: 'B2'}, {id: 6, name: 'C2'}],
[{id: 7, name: 'A3'}, {id: 8, name: 'B3'}, {id: 9, name: 'C3'}],
[{id: 10, name: 'A4'}, {id: 11, name: 'B4'}]
]
}
}
-
<div v-for="(items, idx) in results" :key="items[0].id">
<v-card v-for="(item) in items" :key="item.id">
<v-card-title>{{item.name}}</v-card-title>
</v-card>
</div>

data should be a method that return object with values just like below
data () {
return {
results: [
[{id: 1, name: 'A1'}, {id: 2, name: 'B1'}, {id: 3, name: 'C1'}],
[{id: 4, name: 'A2'}, {id: 5, name: 'B2'}, {id: 6, name: 'C2'}],
[{id: 7, name: 'A3'}, {id: 8, name: 'B3'}, {id: 9, name: 'C3'}],
[{id: 10, name: 'A4'}, {id: 11, name: 'B4'}],
]
}
}

Related

Something is not working in vue js, I can't see the info of props

I have this problem, I can't see the data of the father when I use it in the child
component.
This is the child component:
<template>
<div>
<h3>Lista de compras:</h3>
Carrito:
<div v-for="item in listaPlantas" :key="item">
{{item.productName}} : {{item.productQty}}
</div>
</div>
</template>
<script>
export default{
props: ["listaPlantas", "productName", "productQty", "productPrice", "productStock",
"productId"],
</script>
And this is the father:
<template>
<section>
<agregar-productos v-for="planta in listaPlantas" :key="planta.id"
:product-name="planta.name"
:product-id="planta.id"
:product-stock="planta.stock"
:product-qty="planta.qty"
:product-price="planta.price"></agregar-productos>
</section>
</template>
<script>
export default {
data() {
return{
listaPlantas:[
{id: 'flor', name: 'flores', qty: 0, stock: 5, price: 1000},
{id: 'cact', name: 'cactus', qty: 0, stock: 3, price: 2000},
{id: 'arbol', name: 'arboles', qty: 0, stock: 6, price: 7000},
]
};
},
methods: {
manejoProductos(id){
for(let flower of this.listaPlantas){
if(flower.name == id){
flower.qty +=1;
flower.stock -=1;
console.log(flower.name, flower.qty);
}
}
}
}
}
</script>
You're looping over the products in both the parent and the child. Try this:
<template>
<div>
<h3>Lista de compras:</h3>
Carrito:
<div v-for="item in listaPlantas" :key="item.id">
{{item.name}} : {{item.qty}}
</div>
</div>
</template>
<script>
export default{
props: ["listaPlantas"],
</script>
<template>
<section>
<agregar-productos :listaPlantas="listaPlantas" />
</section>
</template>
<script>
export default {
data() {
return{
listaPlantas:[
{id: 'flor', name: 'flores', qty: 0, stock: 5, price: 1000},
{id: 'cact', name: 'cactus', qty: 0, stock: 3, price: 2000},
{id: 'arbol', name: 'arboles', qty: 0, stock: 6, price: 7000},
]
};
},
methods: {
manejoProductos(id){
for(let flower of this.listaPlantas){
if(flower.name == id){
flower.qty +=1;
flower.stock -=1;
console.log(flower.name, flower.qty);
}
}
}
}
}
</script>

How do I reference an image path in an img src in Vue JS

I have an array of objects coming from a prop. Each object has a title and img key values. I'm using v-for to display the title and how the image from the img value.
<div v-for="item in products" :key="item.id">
<h1>{{item title}}</h1>
<img :src="item.img">
</div>
export default {
name: "home",
props: ["products"]
/*
here is the products
[{id: 1, title: "Moe", img: "../assets/images/stooges/moe.jpg"},
{id: 2, title: "Larry", img: "../assets/images/stooges/larry.jpg"},
{id: 3, title: "Curly", img: "#/assets/images/stooges/curly.jpg"}]
*/
};
On the last element, I'm trying the relative referencing. I've also tried something like this
<img :src="require(item.img)">
At least for the last element, I was hoping to see the image.
<div v-for="item in products" :key="item.id">
<h1>{{ item.title }}</h1>
<img :src="require(`#/assets/images/stooges/${item.img}.jpg`)" />
</div>
export default {
name: "home",
props: ["products"]
data() {
return {
products: [
[{id: 1, title: "Moe", img: "moe"},
{id: 2, title: "Larry", img: "larry"},
{id: 3, title: "Curly", img: "curly"}]
]
};
},
};

Binding model attribute to radio button with vuejs

I have a dataset that looks like this:
[
{id: 1, name: 'Foo', is_primary: false},
{id: 2, name: 'Bar', is_primary: true},
{id: 3, name: 'Baz', is_primary: false},
]
Only one of the entries is allowed to have is_primary = true. I'm displaying these items in a list, and I'm trying to display a radio button for each that the user can select to indicate that this is the primary one.
<tr v-for="item in items">
<td><input name="primary" type="radio" v-model="item.is_primary"></td>
</tr>
However, I don't think I'm understanding how this is supposed to work, because it's not working for me. Is this possible or am I supposed to handle this situation another way?
A set of radio inputs should v-model the same variable: a scalar that takes on the value associated with the selected radio.
To translate that back and forth into your item list, you can use a settable computed.
new Vue({
el: '#app',
data: {
items: [{
id: 1,
name: 'Foo',
is_primary: false
},
{
id: 2,
name: 'Bar',
is_primary: true
},
{
id: 3,
name: 'Baz',
is_primary: false
},
]
},
computed: {
primaryItem: {
get() {
return this.items.find((i) => i.is_primary);
},
set(pi) {
this.items.forEach((i) => i.is_primary = i === pi);
}
}
}
});
<script src="https://unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<div v-for="item in items">
<input name="primary" type="radio" :value="item" v-model="primaryItem">
</div>
<pre>{{JSON.stringify(items, null, 2)}}</pre>
</div>

in vueJS, how to bind the Id of selected option in v-select v2.5.1

It's been hours that I'm trying to get the id of the selected option in v-select, but it returns me the object not the id.
Is there any way to get only the Id (object Id) of the selected option?
I already checked the documentation site:
https://sagalbot.github.io/vue-select/docs/
I also checked the various examples in:
https://codepen.io/collection/nrkgxV/
But so far I have not found the concrete solution to my problem. What is missing or am I doing wrong?
My code:
<template>
<div>
<v-select
v-model="selectedId"
:options="items"
label="name"
></v-select>
</div>
</template>
<script>
export default {
data () {
return {
items: [
{id: 1, name: "User 1", creator_id: 3},
{id: 2, name: "User 2", creator_id: 1},
{id: 4, name: "User 3", creator_id: 3},
],
selectedId: '',
...
}
}
Instead of using v-model , you can listen the event on the select:
Vue.component("v-select", VueSelect.VueSelect);
new Vue({
el: "#app",
data () {
return {
items: [
{id: 1, name: "User 1", creator_id: 3},
{id: 2, name: "User 2", creator_id: 1},
{id: 4, name: "User 3", creator_id: 3},
],
selectedId: ''
}
},
methods: {
selectId(e) {
this.selectedId = e.id
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-select/2.5.1/vue-select.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<v-select
#input="selectId($event)"
:options="items"
label="name">
</v-select>
<p>Selected ID: {{ selectedId }}</p>
</div>
how about add a computed props id
<script>
export default {
data () {
return {
items: [
{id: 1, name: "User 1", creator_id: 3},
{id: 2, name: "User 2", creator_id: 1},
{id: 4, name: "User 3", creator_id: 3},
],
selectedId: {}
}
},
computed: {
id: function () {
return (this.selectedId && this.selectedId.id)?this.selectedId.id:'';
}
}
}
</script>
It took me quite a while to figure out but apparently you can use :reduce="item = item.id"
See: https://vue-select.org/guide/values.html#getting-and-setting
A real life saver since the "computed" approach wasn't gonna cut it in my case
Returning a single key with reduce
f you need to return a single key, or transform the selection before it is synced, vue-select provides a reduce callback that allows you to transform a selected option before it is passed to the #input event. Consider this data structure:
let options = [{code: 'CA', country: 'Canada'}];
If we want to display the country, but return the code to v-model, we can use the reduce prop to receive only the data that's required.
<v-select :options="options" :reduce="country => country.code" label="country" />
https://vue-select.org/guide/values.html#transforming-selections
In the v-select add these attributes
item-value="id" item-text="name"

I used v-for the router-link but it‘s not worked

<li v-for="item in navbars">
<router-link to="{path:item.router}">{{item.names}}</router-link>
</li>
but it does not work, the console is
vue-router.esm.js?f926:16 [vue-router] Duplicate named routes definition: { name: "auto", path: "/auto" }
export default {
data () {
return {
isShow: false,
navbars: [
{names: 'xx', router: '/xx'},
{names: 'xx', router: '/xx'},
{names: 'xx', router: '/xx'},
{names: 'xx', router: '/xx'},
{names: 'xx', router: '/xx'}
]
}
}
}
Instead of having to change into :to. A good practice would be to use :key="i" including v-for="(item, i) in navbars" due to performance reasons.
A note from someone else visiting this question and having :href in its code - you need to change :href into :to.
If you use router-link:
<li v-for="item in navbars" v-bind:key="item.id">
<router-link :to="{path:item.router}">{{item.names}}</router-link>
</li>
or if you use href:
<li v-for="item in navbars" v-bind:key="item.id">
<a :href="item.router">{{ item.title }}</a>
</li>
You can add id to navbars
export default {
data () {
return {
isShow: false,
navbars: [
{names: 'xx', router: '/xx', id: 1},
{names: 'xx', router: '/xx', id: 2},
{names: 'xx', router: '/xx', id: 3},
{names: 'xx', router: '/xx', id: 4},
{names: 'xx', router: '/xx', id: 5}
]
}
}
}
you should use v-bind when you use javascript expression:
<router-link :to="{path:item.router}">{{item.names}}</router-link>
vue router-link