I have two components TheCollapsible
and TheBuyProduct
. The first should be a structural component, making it possible to pass some children and a slot
and render multiple collapsible itens (parents), that can expand and show its children. The second (which uses the first), should be a reactive screen to make it possible for the user to add items of some product. The problem here is the quantity of the product is not updated when the add
or subtract
functions are called.
Notice I have made two trials on reactivity: the first was to add a new property to the prop passed for my second component, this property is my quantity, but it doesn't work; the second trial was to create an array, where the index is the product id
and the value is the quantity (which starts at zero). Both fail to be reactive.
I wander if this is because of the way my slot
works. In my TheCollapsible
component, I need a list of objects that has a property which is a new list (parent has property containing children). But as I said this is merely structural, each children HTML
is passed as a slot
and every prop I need in the slot
I get through the v-slot
.
TheCollapsible.vue
<template>
<div class="ui-collapsible">
<div
class="ui-collapsible__parent"
:key="parent_index"
v-for="(parent, parent_index) in parents"
>
<div>
<p>{{ parent.title }}</p>
<button @click="openChildren(parent_index)">
<img
alt="Abrir"
:id="`collapsible-icon-${parent_index}`"
src="/img/icons/chevrons-up-down.svg"
/>
</button>
</div>
<ul
class="ui-collapsible__children"
:id="`collapsible-child-${parent_index}`"
>
<li :key="index" v-for="(child, index) in parent[child_key]">
<slot
:child="child"
:child_index="index"
:parent_index="parent_index"
/>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: ["child_key", "parents"],
methods: {
openChildren(index) {
this.changeIconForOpenOrClosed(index);
const open_child = document.getElementsByClassName(
"ui-collapsible__children--active"
)[0];
if (open_child) {
open_child.classList?.remove("ui-collapsible__children--active");
open_child.classList.add("ui-collapsible__children");
}
const child = document.getElementById(`collapsible-child-${index}`);
if (open_child?.id != child.id) {
child.classList.remove("ui-collapsible__children");
child.classList.add("ui-collapsible__children--active");
}
},
changeIconForOpenOrClosed(index) {
const opened_button = document.querySelector(
'[src$="chevrons-down-up.svg"]'
);
if (opened_button?.src) {
opened_button.src = "/img/icons/chevrons-up-down.svg";
}
const click_button = document.querySelector(`#collapsible-icon-${index}`);
if (click_button?.id != opened_button?.id) {
click_button.src = "/img/icons/chevrons-down-up.svg";
}
},
},
};
</script>
TheBuyProduct.vue
<template>
<div class="row">
<div class="col-6">
<img :alt="product.title" class="product__image" :src="product.image" />
<h1>{{ product.title }}</h1>
<div class="product__lead" v-html="product.lead"></div>
</div>
<div class="col-6">
<h1>Acompanhamentos</h1>
<the-collapsible
child_key="items"
:parents="product.accompaniment_categories"
v-slot="{ child, child_index, parent_index }"
>
<div class="row product__accompaniment">
<img :alt="child.title" class="col-2" :src="child.image" />
<span class="col-4">{{ child.title }}</span>
<div class="col-4 product__quantity">
<button @click="subtract(child_index, parent_index, child.id)">
<i class="fa fa-minus"></i>
</button>
<span>
{{
product.accompaniment_categories[parent_index].items[
child_index
].quantity
}}
-
{{ accompaniments[child.id] }}
</span>
<button @click="add(child_index, parent_index, child.id)">
<i class="fa fa-plus"></i>
</button>
</div>
<span class="col-2">R${{ child.price }}</span>
</div>
</the-collapsible>
<button class="ui-button product__button">Enviar pedido</button>
</div>
</div>
</template>
<script>
export default {
props: ["product"],
data() {
return {
accompaniments: [],
};
},
created() {
this.addPropToAccompaniments();
},
methods: {
addPropToAccompaniments() {
for (let i = 0; i < this.product.accompaniment_categories.length; i++) {
const category_items = this.product.accompaniment_categories[i].items;
for (let j = 0; j < category_items.length; j++) {
category_items[j].quantity = 0;
this.accompaniments[category_items[j].id] = 0;
}
}
},
add(i, j, id) {
this.product.accompaniment_categories[i].items[j].quantity += 1;
console.log("add:", this.accompaniments[id]);
this.accompaniments[id] += 1;
},
subtract(i, j, id) {
this.product.accompaniment_categories[i].items[j].quantity -= 1;
console.log("sub:", this.accompaniments[id]);
this.accompaniments[id] -= 1;
},
},
};
</script>