Search code examples
javascriptvue.jsvuetify.jssettimeout

setTimeout for v-alert after adding Item to an array basket


this is my rightTableMenu template

<template>
  <div>
    <h1 align="center">{{ title }}</h1>
    <v-alert type="info" icon="mdi-emoticon-sad" v-if="basketStatus">
      Empty Basket, please add some to basket
    </v-alert>
    <div v-if="changeAlertStatus()">
      <v-alert
        type="success"
        icon="mdi-emoticon-happy"
        :value="alert"
        transition="fade-transition"
      >
        thank you
      </v-alert>
      <v-simple-table>
        <template v-slot:default>
          <thead>
            <tr>
              <th class="text-left">Quantity</th>
              <th class="text-left">Name</th>
              <th class="text-left">Price</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="item in basket" :key="item.name">
              <td>
                <v-icon @click="increaseQuantity(item)">add_box</v-icon>
                <span>{{ item.quantity }}</span>
                <v-icon @click="decreaseQuantity(item)"
                  >indeterminate_check_box
                </v-icon>
              </td>
              <td>{{ item.name }}</td>
              <td>{{ (item.price * item.quantity).toFixed(2) }}</td>
            </tr>
          </tbody>
        </template>
      </v-simple-table>
      <v-divider color="black"></v-divider>
      <v-row id="basket_checkout" style="margin: 0">
        <v-col>
          <p>Subtotal:</p>
          <p>Delivery:</p>
          <p>Total amount:</p>
        </v-col>
        <v-col class="text-right">
          <p>${{ subTotalResult }}</p>
          <p>$10</p>
          <p class="font-weight-bold">${{ totalPriceResult }}</p>
        </v-col>
      </v-row>
      <v-row>
        <v-spacer></v-spacer>
        <v-btn depressed class="orange" v-on:click="submitOrder">
          <v-icon>shopping_basket</v-icon>
        </v-btn>
      </v-row>
    </div>
  </div>
</template>

as you see there are two alerts one is showing when there is not item inside the array basket by checking the following

basketStatus() {
  return this.$store.getters.basket.length === 0;
},

which is computed property my data property section is

  data() {
    return {
      title: "Current Basket",
      alert: false,
    };
  },

but for the second v-alert, I wanna to have the alert to be shown and disappear after few sec and so far I have done the following for it

  async changeAlertStatus() {
      if (this.$store.getters.basket.length !== 0) {
        this.alert = true;
        try {
          const response = await setTimeout(() => {
            this.alert = false;
          }, 100);
          console.log("this is the resonse " + response);
        } catch (err) {
          console.log("fetch failed", err);
        }
      } else {
        this.alert = false;
      }
    },

which is a method I am confused how to interject the function inside the div part without using v-if directive and my async changeAlertStatus gets in the infinite loop when I check it inside the console and the v-alert does not get disappear

enter image description here

any thoughts on that?

if there is more info needed , please let me know

thank you

just in case my leftTableMenu is follows

<template>
  <div>
    <div v-if="showError['situation']">
    <!-- 
basically, when you close the alert, the value of the alert goes to false
so you need to turn it to true when there is an error  :value="showError.situation" -->
      <app-alert :text="showError.message"  :value.sync="showError.situation"></app-alert>
    </div>
    <h1 align="center">{{ title }}</h1>
    <v-simple-table od="menu-table">
      <template v-slot:default>
        <thead>
          <tr>
            <th class="text-left">Name</th>
            <th class="text-left">Price</th>
            <th class="text-left">Add</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="item in menuItems" :key="item.name">
            <td>
              <span id="id_name">{{ item.name }}</span>
              <br />
              <span id="menu_item_description">{{ item.description }}</span>
            </td>
            <td>{{ item.price }}</td>
            <td>
              <v-btn text v-on:click="addToBasket(item)">
                <v-icon color="orange">1add_shopping_cart</v-icon>
                <span></span>
              </v-btn>
            </td>
          </tr>
        </tbody>
      </template>
    </v-simple-table>
  </div>
</template>
<script>
export default {
  name: 'LeftTableMenu',
  data() {
    return {
      title: "Menu Items", 
    };
  },
  methods: {
    addToBasket(item) {
      this.$store.dispatch("addToBasket", item);
    },
  },
  computed: {
    showError() {
      return this.$store.getters.showError;
    },
    menuItems() {
      return this.$store.getters.menuItems;
    },
  },
};

Solution

  • You can add a watcher on your computed property to see if it's changed.

    When it changes you can update your data to show or the "Success" alert and then set a timeout to hide it back again after some time.

    Here is an updated example with some changed param names for clarity.

    I changed the computed name to be emptyBasket

    computed: {
      emptyBasket() {
        return this.$store.getters.basket.length === 0;
      }
    },
    

    I added showSuccessAlert to data

    data() {
      return {
        showSuccessAlert: false
      };
    },
    

    And here it the watcher that updates the showSuccessAlert

    watch: {
      emptyBasket: {
        immediate: true,
        handler(newVal, oldVal) {
          this.showSuccessAlert = !newVal;
          setTimeout(() => {
            this.showSuccessAlert = oldVal;
          }, 5000);
        }
      }
    }
    

    The watcher will be triggered immediately (not sure you need it), newVal and oldVal are representing the new and old state of emptyBasket. So when newVal is false it means that the basket is not empty, hence the update of showSuccessAlert = !newVal

    I created a simple working sandbox with your code.

    Here is the link:

    https://codesandbox.io/s/smoosh-cherry-ngpqu?file=/src/App.vue