@100R

Как определить, был ли товар помещён в корзину?

Есть компонент каталога, модуль товара и что-то отдалённо напоминающие корзину покупок. Модуль товара — хранит список всех товаров, а модуль заказа — Id купленного товара и количество. Как определить, что кнопка "Купить" конкретного товара была нажата, вывести об этом сообщение и сделать кнопку недействительной (disabled)?

Catalog.vue

<template>
    <b-row>
        <b-col sm="6" lg="4" xl="3" v-for="product in products" :key="product.id">
            <div class="image" v-lazy:background-image="product.image">
                Видно если нажали "Купить".
            </div>
            <div class="d-flex justify-content-between">
                <div>
                    <p class="mb-0">{{product.name}}</p>
                    <p class="mb-0">{{product.price}} грн.</p>
                </div>
                <b-button class="align-self-center" variant="outline-dark" @click="buyProduct(product.id)">Купить</b-button>
            </div>
        </b-col>
    </b-row>
</template>

<script lang="javascript">
    import { BRow, BCol, BButton } from 'bootstrap-vue'
    import { mapState, mapActions } from 'vuex'

    export default {
        components: {
            BRow,
            BCol,
            BButton
        },
        computed: mapState({
            products: state => state.product.all
        }),
        methods: {
            ...mapActions('order', ['buyProduct'])
        }
    }
</script>

product.js

import axios from 'axios'

export default {
    namespaced: true,
    strict: true,

    state: {
        page: 1,
        all: []
    },

    mutations: {
        incrementPage: (state) => {
            state.page++
        },
        addToAllProducts: (state, products) => {
            state.all.push(...products)
        }
    },

    actions: {
        getFourProducts: (context, $state) => {
            axios.get('http://api.local/api/products', {
                params: {
                    page: context.state.page
                },
            }).then(({ data }) => {
                if (data.data.length) {
                    context.commit('incrementPage')
                    context.commit('addToAllProducts', data.data)
                    $state.loaded()
                } else {
                    $state.complete()
                }
            })
        }
    }
}

order.js

export default {
    namespaced: true,
    strict: true,

    state: {
        all: []
    },

    mutations: {
        addToOrder(state, id) {
            state.all.push({
                id,
                quantity: 1
            })
        }
    },

    actions: {
        buyProduct(context, id) {
            context.commit('addToOrder', id)
        }
    }
}
  • Вопрос задан
  • 293 просмотра
Решения вопроса 1
0xD34F
@0xD34F Куратор тега Vue.js
Добавим элементам products свойство, которое будет указывать, присутствует ли товар в корзине. Для этого перепишем его следующим образом:

computed: mapState({
  products: state => state.product.all.map(n => ({
    ...n,
    isOrdered: state.order.all.some(m => m.id === n.id),
  })),
}),

Всё, можно блокировать кнопку: <b-button :disabled="product.isOrdered".
И показывать уведомление о покупке: <div v-if="product.isOrdered".

Если же не хотите изменять уже существующее вычисляемое свойство, можно сделать ещё одно:

computed: {
  isOrdered() {
    return Object.fromEntries(this.$store.state.order.all.map(n => [ n.id, true ]));
  },
},

В шаблоне, вместо product.isOrdered из предыдущего варианта, будет isOrdered[product.id].

UPD. Вот вам демо. Код немного отличается от вашего и от того, что выше в ответе, плюс добавлен роутер, но, полагаю, разберётесь, что к чему.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
IgorPI
@IgorPI
<template>
  <b-row>
    <b-col sm="6" lg="4" xl="3" v-for="product in products" :key="product.id">
      <div class="image" v-lazy:background-image="product.image">
        Видно если нажали "Купить".
      </div>
      <div class="d-flex justify-content-between">
        <div>
          <p class="mb-0">{{product.name}}</p>
          <p class="mb-0">{{product.price}} грн.</p>
        </div>
        <b-button class="align-self-center" variant="outline-dark" @click="buyProduct(product)">Купить</b-button>
      </div>
    </b-col>
  </b-row>
</template>

<script lang="javascript">
  import { BRow, BCol, BButton } from 'bootstrap-vue'
  import { mapState, mapActions } from 'vuex'

  export default {
    components: {
      BRow,
      BCol,
      BButton
    },
    computed: mapState({
      products: state => state.product.all
    }),
    methods: {
      buyProduct(product){
        console.log(product)
      }
    }
  }
</script>


По поводу кнопки можно так
<b-button class="align-self-center" variant="outline-dark" @click.once="buyProduct(product.id)">Купить</b-button>
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы