Sander Plomp
Sander Plomp

Reputation: 261

Return an error message in the form of a toast message to component using Vuex

I have successfully created a shopping cart using Vuex, but there's one more thing I would like to implement, and that is an error message in the form of a toast message.

This will trigger when the user tries to exceed the limit of the product's stock.

Here is my code, take a look at the method inside of the component, Home.vue:

addToCart(product) {
    product.quantity = 1;
    this.$store.commit('addToCart', product)
    this.$store.commit('totalItems');
    this.$store.commit('totalPrice');
}

This works and everything, even uses an if statement to check if the user exceeds the limit, so far so good, but it's just the message I want to display.

As last, here is my store.js file:

import Vue from 'vue'
import Vuex from 'vuex'
 
Vue.use(Vuex)
 
export default new Vuex.Store({
    state: {
        products: [],
        cart: JSON.parse(localStorage.getItem('cart')) ? JSON.parse(localStorage.getItem('cart')) : [],
        totalItems: 0,
        totalPrice: 0,
        newCartItem: {}
    },
    actions: {    
    },
    mutations: {
        // getProducts(state, products) {
        //     state.products = products
        // },
        addToCart ( state, product ) {
            let findProduct = state.cart.find(o => o.id === product.id)
            if( findProduct ) {
                if ( product.quantity + findProduct.quantity > product.units ) {
                    findProduct.quantity = product.units
                    //show message
                } else {
                    findProduct.quantity += product.quantity;
                    findProduct.subtotal = findProduct.quantity * findProduct.price;
                }
            } else {
                state.newCartItem.id = product.id
                state.newCartItem.name = product.name;
                state.newCartItem.price = product.price;
                state.newCartItem.quantity = product.quantity;
                state.newCartItem.image = product.product_image[0].image;
                state.newCartItem.subtotal = product.price;
                state.newCartItem.units = product.units;
                state.cart.push(Object.assign({},state.newCartItem))
                state.newCartItem = {}
            }
            localStorage.setItem('cart', JSON.stringify(state.cart));
        },
        totalItems ( state ) {
            state.totalItems = parseInt(state.cart.reduce((total, item) => {
                return total + item.quantity;
            }, 0))           
        },
        totalPrice ( state ) {
            state.totalPrice = state.cart.reduce((total, item) => {
                return total + item.subtotal;
            }, 0);
        },
        removeFromCart ( state, product ) {
            let findProduct = state.cart.find(o => o.id === product.id)
            if ( findProduct ) {
                state.cart.pop( this.findProduct );
            }  
            localStorage.setItem('cart', JSON.stringify(state.cart));
        },
        changeQuantityItem ( state, product ) {
            let findProduct = state.cart.find(o => o.id === product.id)
            if (findProduct) {
                if ( product.quantity > product.units ) {
                    product.quantity = product.units
                } else {
                    findProduct.quantity = product.quantity;
                }
                findProduct.subtotal = product.quantity * findProduct.price;
            } 
            localStorage.setItem('cart', JSON.stringify(state.cart));
        }
    },
    getters: {
        cart: state => state.cart,
        totalItems: state => state.totalItems,
        totalPrice: state => state.totalPrice
    },
})

The location where I wrote down a comment (//show message), I would like to return a toast message, something like the user can't exceed the product's stock. How do I do this? I've read something like you should make use of an action, but maybe I am wrong and this could be executed much easier.

Any help would be appreciated, thanks in advance!

Upvotes: 0

Views: 1603

Answers (2)

Sander Plomp
Sander Plomp

Reputation: 261

Because I am using the PrimeVue component library, I wanted to also use it for these error messages. Here is what I've done to make it work:

  • I added a function to the computed error property like this inside my component:

      error: function() {
          if (this.$store.state.error !== null ) {
              this.$toast.add({severity:'warn', summary: 'Warn Message', detail:this.$store.state.error, life: 3000});
              this.$store.commit('clearError')
          }
          return this.$store.state.error
      }
    

And in my store.js, I've added the following code:

state.error = "You are trying to exceed the product's available stock."

And I just call a function to set the error property to null after the message has been displayed, like so:

clearError ( state ) {
    state.error = null
}

Upvotes: 0

Abhinav Kumar
Abhinav Kumar

Reputation: 3036

You are almost there. Yeah, making it an action only help when you want to listen it back to one component or other component and process something when this happen.

In that case go with Action approach.

But If you just want to show the message. You can use [buefy][1] component. That works even outside of the Vue instance. Its very simple to use.

import { ToastProgrammatic as Toast } from 'buefy'

use it like :

//show message
Toast.open('Item not available.')

You can import even one component if you are worried about the bundle size. [1]: https://buefy.org/documentation/toast

Upvotes: 1

Related Questions