Checking if something exists in json in Vue - vue.js

I've got a json API that I'm using like this:
[{
"name": "Thing",
"id": 1234,
"total": 1,
"stock": [
{
"size": "Small",
"id": 1,
"count": 10
},{
"size": "Medium",
"id": 2,
"count": 5
},{
"size": "Large",
"id": 3,
"count": 5
}
]
}]
I'm looping over these in Vue, but want to check if anything exists in the 'stock' element outside of the v-for loop.
I can use v-if to check if the overall json exists, but can't seem to narrow it down to checking if the stock element contains anything.
Any pointers?

What about a v-if & v-else condition on the length of the stocks array? If the length is greater than zero we have stocks, so display them, else, display a message. Something like this.
Vue.component('your-component', {
template:
`
<div v-for="(item, i) in items" :key="i">
<p>{{ item.name }}<p>
<p>{{ item.id }}<p>
<div v-if="item.stock && item.stock.length > 0">
<p v-for="(stock, j) in item.stock" :key="j">
There'are {{ stock.count }} of size {{ stock.size }}.
<p>
</div>
<div v-else>
Ops... stocks not available.
</div>
</div>
`,
data () {
return {
items: []
}
},
created () {
fetch('your-api')
.then((res) => res.json())
.then((res) => { this.items = res })
}
})

Related

Nesting in VueDraggable is not not working

here's my problem :
I'm using the VueDraggable library in order to drag and drop elements between a DragBoard.vue and a DropBoard.vue, and a specific type of element should allow to be nested when it is in the DropBoard.
I'm going to take this element as an example :
"Grouped Items"
To do that I've followed this example : https://github.com/SortableJS/vue.draggable.next/blob/master/example/components/nested-example.vue
And this is what I get when I drop "Grouped Items" into the DropBoard.vue :
IMG
As you can see, the DropBoard appears a second time inside Grouped items for whatever reason. I've supposed that the nested-draggable tag also loop what is out of the draggable tag and I've no idea how to resolve that...
📄 dragItems.JSON (used in DragBoard.vue) :
1st object is a common element
2nd object is a nestable element
[
{
"type": "Simple list",
"title": "Simple list",
"id": 1,
"properties": "this is an item property"
},
...
{
"type": "Grouped items",
"title": "Grouped items",
"id": 10,
"properties": "this is an item property",
"tasks": []
},
...
]
🚩 DropBoard.vue template:
<template>
<div class="board">
<div class="head">Mock</div>
<div class="dd-container">
<draggable
:list="tasks"
v-model="dropItems"
item-key="title"
:group="{ name: 'items', put: true }"
#change="log"
>
<template #item="{ element }">
<div
class="item"
:key="element"
>
<div>
{{ element.title }}
</div>
<nested-draggable
v-if="element.tasks"
:tasks="element.tasks"
class="group-container"
/>
<div class="trashico" :key="index">
<i class="fas fa-trash" #click="deleteItem(index)"></i>
</div>
</div>
</template>
</draggable>
</div>
</div>
</template>
🚩 DropBoard.vue script
<script>
import draggable from "vuedraggable";
export default {
name: "nested-draggable",
components: {
draggable,
},
props: {
dropItems: {
type: Array,
required: true,
},
tasks: {
required: true,
type: Array,
},
},
data() {
return {
dropItems: [],
};
},
methods: {
deleteItem(id) {
this.dropItems.splice(id, 1);
},
},
};
</script>
Here is what I found while using the Vue DevTools, it's quit explicit about the problem.
See image: IMG

How to change input value for individual object in an array using v-for in Vue?

I'm making a shopping cart. I want to show the price of each product based on their quantity.
I made the buttons to add or subtract the quantity of products. However the quantity changes in all products because they all share the same data. How can I do to change quantity for the specific product?
<div v-for="(cartProduct,index) in cartProducts" :key="index" class="px-3 py-2">
<div id="cartProducts">
<p>{{cartProduct.description}}</p>
<button #click="subtract" >-</button> <p>{{quantity}}</p> <button #click="add">+</button>
<p>$ {{cartProduct.price*quantity}}</p>
</div>
</div>
export default {
data(){
return{
quantity:1
}
},
methods:{
add(){
this.quantity++;
},
subtract(){
this.quantity--;
},
}
You have to do is, build an object for all products having quantity field, just like this
<template>
<div>
<div
v-for="(cartProduct, index) in cartProducts"
:key="index"
class="px-3 py-2"
>
<div id="cartProducts">
<p>{{ cartProduct.description }}</p>
<button #click="subtractProduct(index)">-</button>
<p>{{ cartProduct.quantity }}</p>
<button #click="addProduct(index)">+</button>
<p>$ {{ cartProduct.price * cartProduct.quantity }}</p>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
cartProducts: [
{
description: "product 1",
price: 100,
quantity: 0,
},
{
description: "product 2",
price: 100,
quantity: 0,
},
{
description: "product 3",
price: 100,
quantity: 0,
},
],
};
},
methods: {
addProduct(index) {
this.cartProducts[index].quantity++;
},
subtractProduct(index) {
if (this.cartProducts[index].quantity !== 0)
this.cartProducts[index].quantity--;
},
},
};
</script>

How to read deep JSON data using Vuejs and Axios

How would I read deep JSON data nested deep inside a file? I've tried different methods and can't seem to get this to work.
<template>
<div>
<div v-for="edu in info" :key="edu">
<div>{{ edu.section.title }}</div> // this is what im trying to get to work
</div>
<div class="card container">
{{ info }}
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
info: null
}
},
mounted() {
axios
.get('./calculus.json') // Data Below
.then(response => (this.info = response.data.edu))
.catch(error => console.log(error))
}
}
</script>
My JSON looks like this:
{
"edu": {
"1": {
"title": "Title One",
"subtitle": "Subtitle One",
"description": "Description One",
"section": {
"1": {
"title": "Section One Title",
"content": "Section One Content"
}
}
},
"2": {
"title": "Title Two",
"subtitle": "Subtitle Two",
"description": "Description Two",
"section": {
"1": {
"title": "Section One Title",
"content": "Section One Content"
}
}
}
}
}
How can I use vue-for and get the data inside the section to get it to display under the title? For example: title, section>title, section>subtitle, etc.
Given each section is also an object with weird numeric keys, you can iterate them in the same way you do info.
I would also advise you to use identifiable values instead of the entire edu object in your :key bindings.
<div v-for="(edu, eduId) in info" :key="eduId">
<div v-for="(section, sectionId) in edu.section" :key="sectionId">
{{ section.title }}
</div>
</div>
If possible, I would alter the format of your JSON data to use actual arrays instead of objects with numeric keys.
One way to browse your object deeply is to cumulate v-for on your object (and children) entries.
ie:
<div v-for="([category, books], catkey) in Object.entries(info)" :key="`category-${catkey}`">
<div>{{ category }} :</div>
<div v-for="([num, book], numkey) in Object.entries(books)" :key=`book-${catkey}-${numkey}`>
<div v-for="([field, value], valkey) in Object.entries(book)" :key=`field-${catkey}-${numkey}-${valkey}`>
{{ field }} : {{ value }}
</div>
</div>
</div>
If you find it too verbose, you may try to flatten your computed data to have the following structure:
[
{
"category": "edu",
"id": "1",
"title": "Title One",
"subtitle": "Subtitle One",
"description": "Description One",
"section": {
"1": {
"title": "Section One Title",
"content": "Section One Content"
}
}
}
]

How to loop through nested objects using v-for loop

I'm working on some practice code that deals with card information, in which you can display the chosen card's detailed information by clicking one of the cards on the screen.
As demonstrated in the screenshots, if you choose one of the yellow cards, it displays more detailed information of the chosen card with green and blue background color.
I implemented this by using v-for loop, but the problem is that the detailed card information is a JSON object that contains multiple JSON objects inside, and I haven't been successful in displaying all of the members in non-JSON form.
I found some pages (like the link below) where some ways to loop through nested objects were discussed, but it was plain JavaScript code and I couldn't use the same strategy for v-for loop.
How to loop through a plain JavaScript object with the objects as members?
I understand the idea that you should just continue the loop in case the member is another object, not a primitive data type, but I don't know how to implement the same logic in v-for loop.
Could anyone tell me how to do it?
Here is my code.
(v-for loop part)
<div v-for="(obtainedCardInfo, index) in obtainedCardsInfo">
<span v-if="cardBtnChosen && card.id == selectedCard && obtainedCardInfo.id == selectedCard">
<span class="cardInfo">DETAILED CARD INFO:</span>
<div class="cardInfoDisplay">
<div v-for="(detailedInfo,index) in obtainedCardInfo" :key="index">
<p v-if="obtainedCardInfo[index]"> {{index}} : {{obtainedCardInfo[index]}} </p>
<p v-else> {{index}} : NULL </p>
</div>
</div> <br>
</span>
</div>
and the output for my current code.
DETAILED CARD INFO:
accountId : 3917674
id : 3918534
customerId : 998774
cardRole : MAIN
cardStatus : CARD_OK
truncatedCardNumber : 524804______9042
cardTemplate : MC_CARD
cardAddress : NULL
usageLimits : [ { "code": "WEEKLY", "values": null }, { "code": "DAILY", "values": [ { "code": "ATM", "singleAmount": 200, "count": 3, "sumAmount": 300 } ] }, { "code": "MONTHLY", "values": [ { "code": "ATM", "singleAmount": null, "count": 1000, "sumAmount": 1000000 } ] } ]
expiration : { "year": 2022, "month": 6 }
pinAddress : NULL
regionAndEcommBlocking : { "ecomm": false, "africa": false, "asia": false, "europe": false, "home": false, "northAmerica": false, "oceania": false, "southAmerica": false }
The v-for simply iterate through the array or the object keys.
v-for iterates through each element in the array
v-for also iterates through the keys in the object
You should also move your logic to a computed method
<template>
<p v-for:"item, index in arr" />
{{ item }}
{{ index }}
<p v-for:"item, key in obj" />
{{ item }}
{{ key }}
<br />
</template>
<script>
export default {
data() {
return {
arr:[1,2,3,4,5],
obj: { 1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e' }
}
},
computed: {
// do computation here
doSomething() {
}
}
}
</script>

How to filter an array in Vue.js with multiple select buttons?

I try to filter an object of array in Vue.js. have products collection in this vue component. I would like to filter this collection with select buttons. These products are food products and as default I would like to show all products but if I select the lactosefree button the I would like to show only products are lactosefree. In my database these options true or false. so for example if I have a cheese that lactose free then in the database I have a field lactosefree with value true.
I have tried to filter the array with computed property but I don't really know how to do it.
<div class="col-12 justify-content-between row filterbtn">
<label class="btn btn-primary">
<input v-model="selected" value="gluteinfree" type="checkbox" class="check2">GLUTEIN FREE
</label>
<label class="btn btn-primary">
<input v-model="selected" value="lactosefree" type="checkbox" class="check2">LAKTOZ FREE
</label>
</div>
<script>
export default{
data(){
return{
products: [
{ "id": 1, "productName": "Majomkenyérfa kivonat", "gluteinfree": true, "lactosefree": false, },
{ "id": 2, "productName": "Kókuszolaj", "gluteinfree": false, "lactosefree": true,},
{ "id": 3, "productName": "C-vitamin 80mg", "gluteinfree": true, "lactosefree": true, },
],
selected: [],
}
},
computed: {
//
},
}
</script>
As default I would like to show all the products. but when i click the gluteinfree select button I would like to show only the First and the last products where the gluteinfree is true.
Here is the code you can use for your computed. This will loop over all the products and compare each against a list of selected options
return this.products.filter(product => this.selected.every(selection => product[selection] === true));
note that it's using filter and every which for old browsers may require polyfills. You can can also convert to a more verbose for loop though.
Code:
new Vue({
el: '#app',
data() {
return {
products: [{
"id": 1,
"productName": "Majomkenyérfa kivonat",
"gluteinfree": true,
"lactosefree": false,
},
{
"id": 2,
"productName": "Kókuszolaj",
"gluteinfree": false,
"lactosefree": true,
},
{
"id": 3,
"productName": "C-vitamin 80mg",
"gluteinfree": true,
"lactosefree": true,
},
],
selected: [],
}
},
computed: {
zsir() {
return this.products.filter(prod => this.selected.every(sel => prod[sel] === true));
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="col-12 justify-content-between row filterbtn">
<label class="btn btn-primary">
<input v-model="selected" value="gluteinfree" type="checkbox" class="check2">GLUTEIN FREE</label>
<label class="btn btn-primary"><input v-model="selected" value="lactosefree" type="checkbox" class="check2">LAKTOZ FREE</label>
</div>
<ul>
<li v-for="prod in zsir" :key="prod.id">{{prod.productName}}</li>
</ul>
</div>