Vuetify - custom rule on v-text-field returns first element as undefined - vue.js

I used this rule to calculate the minimum purchase quantity and as long as this is not reached the form cannot be sent. The calculation itself works, but the first element is always "undefined".
Because the first element is "undefined", the number in the function getSizesQuantity is not correct if the value of the input field is 0.
What could be the reason for this?
product.json
{
"sku": "12345",
"name": "Product Name",
"variants": [
{
"color": "White",
"sku": "246420009",
"colorimage": "path/to/image",
"sizes": [
{
"size": "XS",
"sku": "246420002"
},
{
"size": "S",
"sku": "246420003"
},
{
"size": "M",
"sku": "246420004"
},
{
"size": "L",
"sku": "246420005"
},
{
"size": "XL",
"sku": "246420006"
},
{
"size": "2XL",
"sku": "246420007"
},
{
"size": "3XL",
"sku": "246420008"
},
{
"size": "4XL",
"sku": "246420009"
}
],
"images": [
{
"look": "front",
"packshot": "path/to/image"
}
]
}
]
}
<v-form
ref="form"
v-model="isValid"
lazy-validation
#submit.prevent="onSubmit">
<v-form ref="sizeform">
<div class="grid-row sizes-col">
<template v-for="(size, index) in variant.selected.sizes">
<v-text-field
ref="sizeInputs"
:key="size.sku"
v-model.number="variantSize[index]"
:rules="sizeRules"
:label="size.size"
type="number"
min="0"
#change="(value) => setVariantSize(value, size, index)"
required />
</template>
</div>
</v-form>
<div class="small muted">
* Mindestabnahme Menge 25 Stück / {{ getSizesQuantity }}
</div>
</v-form>
data() {
return {
variant: this.activeVariant,
variantSize: [],
minimumSizesQuantity: 25,
sizeQuantity: 0,
sizeRules: [ (v) => {
let totalQuantity = 0;
console.log(this.$refs.sizeInputs && this.$refs.sizeInputs.length);
if (this.$refs.sizeInputs && this.$refs.sizeInputs.length > 0) {
this.$refs.sizeInputs.forEach((input) => {
if (input.value) {
totalQuantity += parseInt(input.value, 10);
this.sizeQuantity = totalQuantity;
}
});
}
return totalQuantity >= this.minimumSizesQuantity;
}
],
};
},
computed: {
getSizesQuantity() {
return this.minimumSizesQuantity - this.sizeQuantity;
},
},
this is the output of console.log(this.$refs.sizeInputs && this.$refs.sizeInputs.length);
undefined
1
2
3
4
5
6
7

Related

Vue3 Chart not updating after sending data into Data series in Apex Chart

When I send data into the apex chart array that I took from my json file with axios, the chart does not automatically renew itself in Vue3
With Axios, I fetch all the apexcharts in the json file and add them to the elementCustomize array. Then I push the data in the elementDataseries array into elementCustomize[i].options.series one by one, the data goes into the series of the related apexchart successfully, but I can't see the change in the chart in the page. I can see the data whenever I write a text in the page and save it.
Can you help me?
That is my json file
"elementCustomize": [
{
"id": "2023024145531",
"customizeId": 0,
"elementId": 2023024145531,
"pageId": 1,
"zone": "zone1",
"options": {
"series": [ {
"elementId" : 2023024145531,
"dataId" : 123453576978982,
"name" : "Data 1",
"data" : [-44,55,187,11,61,22,63,45,3]
}],
"chart": {
"type": "bar",
"height": 280,
"toolbar": {
"show": true,
"tools": {
"download": true,
"selection": true,
"zoom": true,
"zoomin": true,
"zoomout": true,
"pan": true,
"reset": true
}
}
},
"plotOptions": {
"bar": {
"horizontal": false,
"columnWidth": "55%",
"endingShape": "rounded"
}
},
"colors": [
"#0150581244",
"#2196F3",
"#4CAF50",
"#9C27B0"
],
"dataLabels": {
"enabled": false
},
"stroke": {
"show": true,
"width": 2,
"colors": [
"transparent"
]
},
"xaxis": {
"categories": [
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct"
]
},
"yaxis": {
"title": {
"text": "$ (thousands)"
}
},
"fill": {
"opacity": 1
},
"legend": {
"position": "top",
"horizontalAlign": "center"
},
"title": {
"text": "Multiple Bars",
"align": "left"
},
"tooltip": {
"y": {}
}
}
},
{
"id": "2023025111221",
"customizeId": 0,
"elementId": "2023025111221",
"pageId": 1,
"zone": "zone3",
"options": {
"series": [],
"chart": {
"type": "bar",
"height": 280,
"toolbar": {
"show": true,
"tools": {
"download": true,
"selection": true,
"zoom": true,
"zoomin": true,
"zoomout": true,
"pan": true,
"reset": true
}
}
},
"plotOptions": {
"bar": {
"horizontal": false,
"columnWidth": "55%",
"endingShape": "rounded"
}
},
"colors": [
"#0150581244",
"#2196F3",
"#4CAF50",
"#9C27B0"
],
"dataLabels": {
"enabled": false
},
"stroke": {
"show": true,
"width": 2,
"colors": [
"transparent"
]
},
"xaxis": {
"categories": [
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct"
]
},
"yaxis": {
"title": {
"text": "$ (thousands)"
}
},
"fill": {
"opacity": 1
},
"legend": {
"position": "top",
"horizontalAlign": "center"
},
"title": {
"text": "Multiple Bars",
"align": "left"
},
"tooltip": {
"y": {}
}
}
}
]
The process where I pull this data from the json and sync it into the array
onBeforeMount(async () => {
await api.get(jsonServerUrl+"elementCustomize?pageId="+pageID).then(response=>{
elementCustomize = response.data
})
}
That is my apex chart code
<div v-for="item in filteredCustomize('zone1')" :key="item.id" class="drag-item s-card">
<ApexChart
id="apex-chart-1 chart"
:height="item.options.chart.height"
:type="item.options.chart.type"
:series="item.options.series"
:options="item.options"
>
</ApexChart>
{{item.options.series}}
<div class="elementHeadBar hover" align="start">
<VButton icon="feather:edit-2" color="info" :loading="loading" raised #click="updateSeries(item)"> test push series </VButton>
</div>
</div>
filteredCustomize for filtering areas, because i have 3 column in page. zone1, zone2, zone3 etc.
const filteredCustomize=(e)=>{
return elementCustomize.filter(item => item.zone === e)
}
I am posting fake datas with updateseries function.
const updateSeries = (item)=> {
let matchingData = elementDataSeries.filter(e => e.elementId == item.id)
if (matchingData){
for(let i = 0; i < elementCustomize.length; i++) {
for(let j = 0; j < elementDataSeries.length; j++) {
if(elementCustomize[i].elementId === elementDataSeries[j].elementId) {
elementCustomize[i].options.series.push(elementDataSeries[j]);
}
}
}
}else{
console.log("no")
}
console.log(elementCustomize)
}
i tried watch but it doesn't work. i read something in forums. when post data into apexchart series, it have to re render automatically.

How render attributes in component Vue 3

I have products two types: simple and configurable:
"products" : [
{
"type": "simple",
"id": 1,
"sku": "s1",
"title": "Product 1",
"regular_price": {
"currency": "USD",
"value": 27.12
},
"image": "/images/1.png",
"brand": 9
},
{
"type": "configurable",
"id": 2,
"sku": "c1",
"title": "Product 2",
"regular_price": {
"currency": "USD",
"value": 54.21
},
"image": "/images/conf/default.png",
"configurable_options": [
{
"attribute_id": 93,
"attribute_code": "color",
"label": "Color",
"values": [
{
"label": "Red",
"value_index": 931,
"value": "#ff0000"
},
{
"label": "Blue",
"value_index": 932,
"value": "#0000ff"
},
{
"label": "Black",
"value_index": 933,
"value": "#000"
}
]
},
{
"attribute_code": "size",
"attribute_id": 144,
"position": 0,
"id": 2,
"label": "Size",
"values": [
{
"label": "M",
"value_index": 1441,
"value": 1
},
{
"label": "L",
"value_index": 1442,
"value": 2
}
]
}
],
"variants": [
{
"attributes": [
{
"code": "color",
"value_index": 931
},
{
"code": "size",
"value_index": 1441
}
],
"product": {
"id": 2001,
"sku": "c1-red-m",
"image": "/image/conf/red.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 931
},
{
"code": "size",
"value_index": 1442
}
],
"product": {
"id": 2002,
"sku": "c1-red-l",
"image": "/image/conf/red.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 932
},
{
"code": "size",
"value_index": 1441
}
],
"product": {
"id": 2003,
"sku": "c1-blue-m",
"image": "/image/conf/blue.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 933
},
{
"code": "size",
"value_index": 1442
}
],
"product": {
"id": 2004,
"sku": "c1-black-l",
"image": "/image/conf/black.png"
}
}
],
"brand": 1
}
]
The above data I get with actions (Vuex)
GET_PRODUCTS_FROM_API({ commit }) {
return axios('http://localhost:8080/products', {
method: 'GET',
})
.then((products) => {
commit('SET_PRODUCTS_TO_STATE', products.data);
return products;
})
.catch((e) => {
console.log(e);
return e;
});
}
then I mutate the data:
SET_PRODUCTS_TO_STATE: (state, products) => {
state.products = products
}
and get from in getters
PRODUCTS(state) {
return state.products = state.products.map((product) => {
const brand = state.brands.find((b) => b.id === product.brand)
return {...product, brandName: brand?.title || 'no brand'}
})
}
after which i get the data in the component
At the moment I'm stuck on how to render the color and size attributes of a configurable product. Tell me how to do it right? Do I need to write logic in vuex or parent component?
I tried to push data from parent component to child. But it stopped there again.
I also tried to separate the color and size attributes separately using getters.
For Vuex, the syntax is the following
<template>
<div>
<div v-for="product in products" :key="product.id">
<span>type: {{ product.type }}</span>
<span>type: {{ product.title }}</span>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['products']),
...mapGetters('fancyNamespace', ['products']), // if namespaced
},
}
</script>
As of where to call it, directly into the component I guess. Otherwise, as explained here it may not be relevant to use Vuex at all.
PS: you can even rename on the fly if you want.
Solved this issue by Computed Properties and transfer props to child components
computed: {
getAttributeColors() {
let attributes_colors = []
this.product_data.configurable_options.map((item) => {
if(item.label === 'Color') {
attributes_colors.push(item.values)
}
})
return attributes_colors
},
getAttributeSize() {
let attributes_size = []
this.product_data.configurable_options.map((item) => {
if(item.label === 'Size') {
attributes_size.push(item.values)
}
})
return attributes_size
}
}

How to add a specific product variant to the shopping cart

The task is to add a product with selection options to the cart. For example, take product with id:2, which has different color and size options. By clicking on the add product button, the product of the selected option should be added to the cart. Product options are predefined. You can see them in the products array below. At the moment, I have created a cart entity in the global store, where I can add a product without selection options and render it on the cart page.
"products" : [
{
"type": "simple",
"id": 1,
"sku": "s1",
"title": "Product 1",
"regular_price": {
"currency": "USD",
"value": 27.12
},
"image": "/images/1.png",
"brand": 9
},
{
"type": "configurable",
"id": 2,
"sku": "c1",
"title": "Product 2",
"regular_price": {
"currency": "USD",
"value": 54.21
},
"image": "/images/conf/default.png",
"configurable_options": [
{
"attribute_id": 93,
"attribute_code": "color",
"label": "Color",
"values": [
{
"label": "Red",
"value_index": 931,
"value": "#ff0000"
},
{
"label": "Blue",
"value_index": 932,
"value": "#0000ff"
},
{
"label": "Black",
"value_index": 933,
"value": "#000"
}
]
},
{
"attribute_code": "size",
"attribute_id": 144,
"position": 0,
"id": 2,
"label": "Size",
"values": [
{
"label": "M",
"value_index": 1441,
"value": 1
},
{
"label": "L",
"value_index": 1442,
"value": 2
}
]
}
],
"variants": [
{
"attributes": [
{
"code": "color",
"value_index": 931
},
{
"code": "size",
"value_index": 1441
}
],
"product": {
"id": 2001,
"sku": "c1-red-m",
"image": "/image/conf/red.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 931
},
{
"code": "size",
"value_index": 1442
}
],
"product": {
"id": 2002,
"sku": "c1-red-l",
"image": "/image/conf/red.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 932
},
{
"code": "size",
"value_index": 1441
}
],
"product": {
"id": 2003,
"sku": "c1-blue-m",
"image": "/image/conf/blue.png"
}
},
{
"attributes": [
{
"code": "color",
"value_index": 933
},
{
"code": "size",
"value_index": 1442
}
],
"product": {
"id": 2004,
"sku": "c1-black-l",
"image": "/image/conf/black.png"
}
}
],
"brand": 1
}]
My store:
import {createStore} from 'vuex'
import apiRequests from "#/store/actions/apiRequests";
import commonActions from './actions/actions'
import mutations from './mutations/mutations'
import getters from './getters/getters'
const actions = {...commonActions, ...apiRequests}
export default createStore({
state: {
products: [],
brands: [],
cart: []
},
mutations,
actions,
getters
})
actions:
export default {
ADD_TO_CART({commit}, product) {
commit('SET_CART', product)
},
INCREMENT_CART_ITEM({commit}, index) {
commit('INCREMENT', index)
},
DECREMENT_CART_ITEM({commit}, index) {
commit('DECREMENT', index)
},
DELETE_FROM_CART({commit}, index) {
commit('REMOVE_ITEM_FROM_CART', index)
}
}
mutations:
export default {
SET_PRODUCTS_TO_STATE: (state, products) => {
state.products = products
},
SET_BRANDS_TO_STATE: (state, brands) => {
const includesBrands = {}
for (const brand of brands) {
for (const product of state.products) {
if (product.brand === brand.id) {
includesBrands[brand.id] = brand
}
}
}
state.brands = Object.values(includesBrands)
state.brands.unshift({title: "All brands"})
},
SET_CART: (state, product) => {
if (state.cart.length) {
let isProductExists = false
state.cart.map((item) => {
if (item.id === product.id) {
isProductExists = true
item.quantity++
}
})
if (!isProductExists) {
state.cart.push({...product, quantity: 1})
}
} else {
state.cart.push({...product, quantity: 1})
}
},
REMOVE_ITEM_FROM_CART: (state, index) => {
state.cart.splice(index, 1)
},
INCREMENT: (state, index) => {
state.cart[index].quantity++
},
DECREMENT: (state, index) => {
if (state.cart[index].quantity > 1) {
state.cart[index].quantity--
}
}
}
and getters:
export default {
BRANDS(state) {
return state.brands
},
CART(state) {
return state.cart
},
PRODUCTS(state) {
return state.products = state.products.map((product) => {
const brand = state.brands.find((b) => b.id === product.brand)
return {...product, brandName: brand?.title || 'no brand'}
})
},
}
Now I am faced with the fact that I do not understand how I can add a certain product variant to the cart and draw it on the cart page.

Why is v-for can't show the value with computed

This is for select a city and area, It will filter the same data to show it. But I meet with a problem is that when I selected, the value doesn't appear.
I have been try and searched similar code but still doesn't find the solution.
This is the image when of HTML rendering :
Here is template :
<a href="#" class="list-group-item" v-for="(live , idx) of filterLivingNames" :key="idx">
<h3 class="text-center">{{live.Name}}</h3>
<p>Address:</p>
<p>Phone:</p>
</a>
Here is script
import LivingData from '#/assets/LivingData.json';
export default {
computed: {
livedata(){
return LivingData;
},
filterLivingNames(){
let livelength = this.livedata.length
for(let i = 0 ; i < livelength ; i++){
if(this.livedata[i].Region === this.city && this.livedata[i].Town === this.area){
console.log(this.livedata[i])
return this.livedata[i]
}
else{
continue
}
}
}
}
}
Update json file
[
{
"Id": "1",
"Name": "Hotel-1",
"Region": "Region-1",
"Town": "Town-1",
},
{
"Id": "2",
"Name": "Hotel-2",
"Region": "Region-2",
"Town": "Town-2",
},
{
"Id": "3",
"Name": "Hotel-3",
"Region": "Region-2",
"Town": "Town-1",
},
{
"Id": "4",
"Name": "Hotel-4",
"Region": "Region-1",
"Town": "Town-2",
},
]
As you are filtering out the livedata based on Region and Town. You can simply use the Array.filter() method and this will resolve the issue you are facing as it will return the array.
Live Demo :
new Vue({
el: '#app',
data: {
livedata: [
{
"Id": "1",
"Name": "Hotel-1",
"Region": "Region-1",
"Town": "Town-1",
},
{
"Id": "2",
"Name": "Hotel-2",
"Region": "Region-2",
"Town": "Town-2",
},
{
"Id": "3",
"Name": "Hotel-3",
"Region": "Region-2",
"Town": "Town-1",
},
{
"Id": "4",
"Name": "Hotel-4",
"Region": "Region-1",
"Town": "Town-2",
}
],
city: 'Region-1',
area: 'Town-1'
},
computed: {
filterLivingNames() {
return this.livedata.filter(obj => obj.Region === this.city && obj.Town === this.area)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<a href="#" class="list-group-item" v-for="(livingData, index) of filterLivingNames" :key="index">
<h3 class="text-center">{{ livingData.Name }}</h3>
<p>Address:</p>
<p>Phone:</p>
</a>
</div>

How to fill object with the selected value of dropdown in Vue

I have a dropdown as you see in the picture:
The value of this dropdown is coming from the fetched data:
"data": {
"type": "products",
"id": "2021-01-04.1.1",
"attributes": {
"name": "product 1",
"descriptions": "some description",
"image": null,
"date": "2021-01-04",
"valid_from": null,
"valig_untill": null,
"xparc_paid_product_id": 1,
"xparc_unpaid_product_id": 1,
"xparc_access_id": 1,
"stock": null,
"variations": [
{
"id": 1,
"product_template_id": "1",
"name": "child ticket",
"description": "Only for children!",
"price_excl_vat": 1,
"created_at": "2021-09-15T13:16:00.000000Z",
"updated_at": "2021-09-15T13:16:00.000000Z"
},
{
"id": 2,
"product_template_id": "1",
"name": "Adults",
"description": "Not for children!",
"price_excl_vat": 2,
"created_at": "2021-09-15T13:16:10.000000Z",
"updated_at": "2021-09-15T13:16:10.000000Z"
},
{
"id": 3,
"product_template_id": "1",
"name": "Test",
"description": "Test",
"price_excl_vat": 10,
"created_at": "2021-09-30T11:29:44.000000Z",
"updated_at": "2021-09-30T11:29:44.000000Z"
}
]
},
As you see I am displaying variations of this object into my dropdown. What I am trying to achieve is according to the selected value I want to put some info into object (for example this
info: {
"id": 1,
"product_template_id": "1",
"name": "child ticket",
"description": "Only for children!",
"price_excl_vat": 1,
"created_at": "2021-09-15T13:16:00.000000Z",
"updated_at": "2021-09-15T13:16:00.000000Z"
},
)
For this I have a `dropdown component:
<template>
<div class="custom-select" :tabindex="tabindex" #blur="open = false">
<div class="selected" :class="{ open: open }" #click="open = !open">
{{ selected.name }}
</div>
<div class="items" :class="{ selectHide: !open }">
<div
v-for="(option, i) of options"
:key="i"
#click="
selected = option;
open = false;
$emit('input', option);
"
>
{{ option.name }}
</div>
</div>
</div>
</template>
<script>
export default {
props: {
options: {
type: Array,
required: true,
},
default: {
type: String,
required: false,
default: null,
},
tabindex: {
type: Number,
required: false,
default: 0,
},
},
data() {
return {
selected: this.default
? this.default
: this.options.length > 0
? this.options[0]
: null,
open: false,
sel: '',
};
},
mounted() {
this.$emit("input", this.selected);
},
computed: {
variations() {
return this.data.attributes.variations
}
},
methods: {
getSelected(opt) {
this.sel = opt.description
}
}
};
</script>
And a parent of this component, I am trying to fill the object:
<Dropdown
:options="getVariations"
:default="'Choose an option'"
class="select"
#input="getSelected"
/>
<script>
data() {
return {
selectedObject: "",
};
},
computed: {
getVariations() {
return this.product.attributes.variations;
},
getSelected(opt) {
this.selectedObject= opt;
}
},
</script>
But unfortunately, I am not getting anything from selectedObject. Could you please have a look?
Thanks...
You emit selected item data from dropdown component, so set your object in method:
getSelected(opt) {
this.selectedObject = opt
Vue.component('Dropdown', {
template: `
<div class="custom-select" :tabindex="tabindex" #blur="open = false">
<div class="selected" :class="{ open: open }" #click="open = !open">
{{ selected.name }}
</div>
<p>Description child :{{ selected.description }}</p>
<div class="items" :class="{ selectHide: !open }">
<div
v-for="(option, i) of options"
:key="i"
#click="
selected = option;
open = false;
$emit('input', option);
"
>
{{ option.name }}
</div>
</div>
</div>
`,
props: {
options: {
type: Array,
required: true,
},
default: {
type: String,
required: false,
default: null,
},
tabindex: {
type: Number,
required: false,
default: 0,
},
},
data() {
return {
selected: this.default
? this.default
: this.options.length > 0
? this.options[0]
: null,
open: false,
};
},
mounted() {
this.$emit("input", this.selected);
},
})
new Vue({
el: '#demo',
data(){
return {
"data":
{
"type": "products",
"id": "2021-01-04.1.1",
"attributes": {
"name": "product 1",
"descriptions": "some description",
"image": null,
"date": "2021-01-04",
"valid_from": null,
"valig_untill": null,
"xparc_paid_product_id": 1,
"xparc_unpaid_product_id": 1,
"xparc_access_id": 1,
"stock": null,
"variations": [
{
"id": 1,
"product_template_id": "1",
"name": "child ticket",
"description": "Only for children!",
"price_excl_vat": 1,
"created_at": "2021-09-15T13:16:00.000000Z",
"updated_at": "2021-09-15T13:16:00.000000Z"
},
{
"id": 2,
"product_template_id": "1",
"name": "Adults",
"description": "Not for children!",
"price_excl_vat": 2,
"created_at": "2021-09-15T13:16:10.000000Z",
"updated_at": "2021-09-15T13:16:10.000000Z"
},
{
"id": 3,
"product_template_id": "1",
"name": "Test",
"description": "Test",
"price_excl_vat": 10,
"created_at": "2021-09-30T11:29:44.000000Z",
"updated_at": "2021-09-30T11:29:44.000000Z"
}
]
},
},
sel: '',
selectedObject: null
}
},
computed: {
variations() {
return this.data.attributes.variations
}
},
methods: {
getSelected(opt) {
this.selectedObject = opt
this.sel = opt.description
}
}
})
Vue.config.productionTip = false
Vue.config.devtools = false
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<h3>selected object</h3>
<p>{{ selectedObject }}</p>
<Dropdown
:options="variations"
:default="'Choose an option'"
class="select"
#input="getSelected"
/>
</div>