I have an indefinite number of selects. For each select, I need to track the change in their values. So I used v-model:
<!-- Options -->
<div class="size-box" v-for="(values, optionName) in product.values" :key="optionName">
<h4>{{ optionName }}</h4>
<div class="d-flex align-items-center">
<div class="size-select language">
<select v-model="selectedValues[optionName]">
<option v-for="value in values" :key="value.id" :value="value.id">
{{ value.name }}
</option>
</select>
</div>
</div>
</div>
<!-- Add to Cart -->
<div class="shop-details-top-cart-box-btn">
<button
class="btn--primary style2"
type="button"
@click="addToCart"
>
Add to Cart
</button>
</div>
The photo shows the structure of the received data.
Here is my script section:
<script>
import { getProduct } from "@/services/productService";
export default {
name: "Show",
data() {
return {
product: null,
currentSku: null,
selectedValues: {},
isProductReady: false,
};
},
async created() {
await this.fetchProduct();
},
methods: {
async fetchProduct() {
try {
const id = this.$route.params.id;
this.product = await getProduct(id);
console.log(this.product);
if (this.product && this.product.values) {
Object.keys(this.product.values).forEach((optionName) => {
const firstValue = this.product.values[optionName][0];
if (firstValue) {
this.selectedValues[optionName] = firstValue.id;
}
});
this.updateSku();
console.log(this.currentSku);
}
this.$nextTick(() => {
this.isProductReady = true;
this.triggerLocalChange();
});
} catch (error) {
console.error("Failed to load product:", error);
}
},
updateSku() {
if (!this.product || !this.product.skus) return;
const matchingSku = this.product.skus.find((sku) => {
return sku.values.every(
(value) => this.selectedValues[value.option_name] === value.value_id
);
});
this.currentSku = matchingSku || null;
},
addToCart() {
if (this.currentSku) {
console.log(
"Added to cart",
this.selectedValues,
);
} else {
console.log("Please select valid options first.");
}
},
triggerLocalChange() {
if (this.isProductReady) {
$(document).trigger("change");
}
},
},
mounted() {
this.$nextTick(() => {
if (!this.isProductReady) {
console.log("DOM updated but product data is not fully loaded yet.");
}
});
},
};
</script>
Response from the backend:
{
"name": "Test Product",
"manufacturer": "Nike",
"values": {
"Color": {
"0": {
"id": 1,
"name": "Green"
},
"2": {
"id": 8,
"name": "White"
},
"4": {
"id": 10,
"name": "Brown"
}
},
"Clothes Size": [
{
"id": 15,
"name": "M"
},
{
"id": 16,
"name": "L"
}
]
}
}
I tried to do the following: when changing the value in at least one select, cause the currentSku value to change. However, I noticed that the values of selectedValues do not change as they should. Please help me understand the problem, I'm writing on Vue for the first time. Thank you all
selectedValues
is an array, it's possible to modify non-index properties, but they are not reactive.
It should be:
selectedValues: {}