I have a code like
<template>
<div v-for="(item, i) in items" :key="i">
<div v-for="(subitem, index) in subitems" :key="index" v-
if="item.id==subitem.item_id">
{{count(subitem)}}
</div>
</div>
</template>
<script>
data() {
return {
items: [],
subitems: [],
}
}
watch: {
items : async function() {
const itm = await('get','/item')
this.items = itm
},
subitems : async function() {
const subitm = await('get','/sub_items')
this.subitems = subitm
},
},
</script>
The items and subitems array get the values of array from the api fetch in watch property. There is item id in each subitems values, Now I want count or length of for each v if output of subitem which is equal to item id. How to do that?
Thank you
You can't put v-for and v-if on the same element can you please provide more about your array structure so i can give you the best way but from what i have you can create do this function after getting item and subitem
items.foreach((element)=>{
element.subitemCount=0;
subitem.foreach(item=>{
if(element.id==item.item_id){
element.subitemCount++;}}
And for your vuejs you can write this
<div v-for="(item, i) in items" :key="i"> {{item.subitemCount}} </div>
Related
I want to display the designated data that is found for a particular code match. I have a data set that will come in model. I want if the data-set, subject property has the first 2-3 characters found in it, to display the corresponding name. Based on the first 3 characters begins with LA_, which is found in the first index, only the first set of content should appear (Name: Library Arts Department: ACSF-LA Identifier: 6774). I know i would need to slice the character off, with string slice, but what if sometimes the name has like LAX_ (SO I want to be sure to check if the subjects have any that match--). So basically to check everything before the first "_"
new Vue({
el: "#app",
data: {
Name:"LA_123_cc",
todos: [{"Name":"Library Arts","Identifier":"6774","Code":"AACSF-LA","Subjects":["LA_","AEL","APC","GAP","FAC","GLM","GS","MPT","PRO","WNM"]},
{"Name":"Violin Dance","Identifier":"6169","Code":"Avvv-VA","Subjects":["VA","VL","VPC","AAP","YAC","XLM","GXS","XPT","IRO","CNM"]}
]
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Name: {{Name}}</h2>
<ol>
<li v-for="todo in todos">
Name: {{todo.Name}} <br>
Department: {{todo.Code}}<br>
Identifier: {{todo.Identifier}}
</li>
</ol>
</div>
Create a computed property that uses Array.prototype.filter on the todos[]. The callback to filter() receives each array item, and returns true if the item should be in the result. In this callback, you can check if each item contains the leading characters (before the underscore) in the search string (LA in your example):
export default {
computed: {
computedTodos() {
const searchLetters = this.Name.split('_')[0].split('') /* get characters of first part of string before underscore */
.filter(x => /\w/.test(x)) /* keep only letters */
return this.todos.filter(item => {
/* check if each letter appears in order within the item's name */
let i = 0
return searchLetters.every(letter => {
i = item.Name.indexOf(letter, i)
return i > -1
})
})
}
}
}
Then update the template to use the computed prop instead of todos[]:
<!-- <li v-for="todo in todos"> -->
<li v-for="todo in computedTodos">
new Vue({
el: "#app",
data: {
Name:"LA_123_cc",
todos: [{"Name":"Library Arts","Identifier":"6774","Code":"AACSF-LA","Subjects":["LA_","AEL","APC","GAP","FAC","GLM","GS","MPT","PRO","WNM"]},
{"Name":"Violin Dance","Identifier":"6169","Code":"Avvv-VA","Subjects":["VA","VL","VPC","AAP","YAC","XLM","GXS","XPT","IRO","CNM"]}
]
},
computed: {
computedTodos() {
const searchLetters = this.Name.split('_')[0].split('').filter(x => /\w/.test(x))
return this.todos.filter(item => {
let i = 0
return searchLetters.every(letter => {
i = item.Name.indexOf(letter, i)
return i > -1
})
})
}
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input v-model="Name">
<h2>Name: {{Name}}</h2>
<ol>
<li v-for="todo in computedTodos">
Name: {{todo.Name}} <br>
Department: {{todo.Code}}<br>
Identifier: {{todo.Identifier}}
</li>
</ol>
</div>
Is it possible from the items array to create a variable item.id (in props)?
props: {
items: {
type: Array,
default: () => []
}
},
And layout, just in case
<div class = 'bestsellers-item' v-for = '(item, index) in items': key = 'index'>
<div class = 'bestsellers-item__sticker'>
<img: src = 'item.img'>
</div>
<span> {{item.id}}
</div>
Based on the comments and also Michal Levý's comment, I think what you are looking for is this:
<div class = 'bestsellers-item' v-for = '(item, index) in items': key = 'index'>
<div class = 'bestsellers-item__sticker'>
<img: src = 'item.img'>
</div>
<button #click="addCartItem(item.id)">Add to cart</button>
</div>
And then, your function:
addCartItem(itemId) {
console.log("Do something with item " + itemId);
}
I have a loop with products, each with a product card.
I want to be able to toggle the button when clicked from Add to cart to Remove from cart.
The problem is all of the products buttons toggle at the same time, and I wan't ONLY the individual product card buttons to be toggled referencing each individual product.
In my HTML
<div v-for="product of products" :key="product.id">
<span class="btn btn-primary mt-5 modal-toggle-btn" #click="addGift(product, text, 'index')" v-show="!isAdded">Añadir a la box</span>
<span class="btn btn-primary mt-5 modal-toggle-btn" #click="removeGift(product, 'index')" v-show="isAdded">Quitar de la box</span>
</div>
Vue data
isAdded: false
My Vue methods
addGift(product, index){
this.campaign.selectedproducts.push({name: product.name });
this.isAdded = true
},
removeGift(product, index){
this. campaign.selectedproducts.splice(index, 1)
this.isAdded = false
},
My suggestion is to:
Divide the product buttons as an individual component.
Use addedIds as an array to store added product ids instead of isAdded boolean.
Communicate parent and child click events with Vue event handling.
Store clicked product id in to the addedProductId on click events.
Check against addedProductId to make sure a product was added or
not in child component.
Example:
ProductButtons.vue (child component)
<template>
<div>
<span class="btn btn-primary mt-5 modal-toggle-btn" #click="addGift" v-show="!isAdded">Añadir a la box</span>
<span class="btn btn-primary mt-5 modal-toggle-btn" #click="removeGift" v-show="isAdded">Quitar de la box</span>
</div>
</template>
<script>
export default {
name: "ProductButtons",
props: {
product: { type: Object, required: true },
addedIds: { type: Array, required: true },
},
computed: {
isAdded() {
return this.addedIds.indexOf(this.product.id) > -1;
},
},
methods: {
addGift(){
this.$emit('addGift', this.product);
},
removeGift(product){
this.$emit('addGift', this.product);
},
}
}
</script>
In Your HTML
<template v-for="product of products" :key="product.id">
<product-buttons :product="product" :addedIds="addedIds" #addGift="addGift" #removeGift="removeGift"></product-buttons>
</template>
Vue data
addedIds: []
Your Vue methods
addGift(product){
this.campaign.selectedproducts.push({name: product.name });
// save product id as an added id
const index = this.addedIds.indexOf(product.id);
if (index === -1) {
this.addedIds.push(product.id);
}
},
removeGift(product){
this.campaign.selectedproducts.splice(index, 1);
// remove product id
const index = this.addedIds.indexOf(product.id);
if (index > -1) {
this.addedIds.splice(index, 1);
}
},
I have several input fields like so:
<input type=text" v-model="InputVModel1">
<input type=text" v-model="InputVModel2">
and I want to place these v-model values inside an array of objects, like so:
array = [{id:1,value:InputVModel1},{id:2,value:InputVModel2},..]
What's the best way to achieve this?
Is it to use $set in a computed value to 'push' these into the array like:
computed: {
computed_array: function(){
object= {"id":1,"value":InputVModel1}
this.$set(this.array, object) //push them with a for loop
[..]
}
}
Or is there a more elegant way to do this?
Background: I want to use the final array for 'vuedraggable' to change the order of the objects while maintaining other important meta infos for each value.
new Vue({
el: '#app',
data: {
list: [
{ id: 1, value: 'foo' },
{ id: 2, value: 'bar' },
{ id: 3, value: 'baz' }
]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div
v-for="(record, i) in list"
:key="i"
>
{{ record.id }}
<input v-model="record.value"/>
{{ record.value }} <!-- To check if value key is updating in the list -->
</div>
</div>
PS: Use list (final array) with for vue-draggable.
I have an object with this structure
object: {
"prop1": [],
"prop2": [],
"prop3": [],
}
In my template I want to loop over it and display data in prop's but if there is no data in any of them I want to show something like this
<div>No data</div>
but only once and not for each prop
So far I have this
<div v-for="(props, index) in object" :key="index">
<div v-if="!props.length">
No data
</div>
</div>
But it shows message 3 times, for each prop.
I'm not sure how to solve it. Any help will be much appreciated.
To solve this in a nice way, you should use a computed property.
A computed property is basically a piece of code that give meaningless caclulations meaningful names.
export default {
data() {
return {
object: {
"prop1": [],
"prop2": [],
"prop3": [],
},
};
},
computed: {
areAllEmpty() {
return Object.values(this.object).map(e => e.length).reduce((a, b) => a + b, 0) === 0;
},
}
};
This can then be used in your template as the following:
<template>
<template v-if="areAllEmpty">
<div>No data</div>
</template>
<template v-else>
<div v-for="(props, index) in object" :key="index">
I'm index {{ index }} with length {{ props.length }}
</div>
</template>
</template>