Thomas.Yu
Thomas.Yu

Reputation: 185

Vue.js - How to disable the button when data array is empty

I write a simple shopping cart app with Vue.js:

var app = new Vue({
    el: "#app",
    data: {
        items: [
            { id: 1, name: "Item 00", spec: "spec 00", price: 400, quantity: 1, unit: "unit 00" },
            { id: 2, name: "Item 01", spec: "spec 01", price: 416, quantity: 1, unit: "unit 01" },
        ]
    },
    methods: {
        isEmpty: function () {
            return this.items.length > 0;
        },
        handleReduce: function (index) {
            if (this.items[index].quantity === 1) {
                return;
            }

            this.items[index].quantity--;
        },
        handleAdd: function (index) {
            this.items[index].quantity++;
        },
        handleRemove: function (index) {
            this.items.splice(index, 1);
        },
        isDisabled: function (index) {
            return this.items[index].quantity === 1;
        }
    },
    computed: {
        total: function () {
            var total = 0;

            for (var i = 0; i < this.items.length; i++) {
                total += this.items[i].quantity * this.items[i].price;
            }

            return total;
        },
        disabled: function (value) {
            return this.items.length < 1;
        }
    },
    filters: {
        numberFormat: function (value) {
            return value.toString().replace(/\B(?=(\d{3})+$)/g, ',');
        }
    }
});

And my HTML is:

<template v-if="isEmpty()">
    <tr v-for="(item, index) in items">
        <td>{{ index+1 }}.</td>
        <td>{{ item.name }}</td>
        <td>{{ item.spec }}</td>
        <td class="text-right">{{ item.price | numberFormat }}</td>
        <td>
        <button class="btn btn-sm btn-secondary" @click="handleReduce(index)" :disabled="isDisabled(index)">-</button>
        {{ item.quantity }}
        <button class="btn btn-sm btn-secondary" @click="handleAdd(index)">+</button>
        </td>
        <td>{{ item.unit }}</td>
        <td class="text-right">{{ (item.quantity * item.price) | numberFormat }}</td>
        <td class="text-right"><button class="btn btn-sm btn-danger" @click="handleRemove(index)">Remove</button></td>
    </tr>
</template>

<template v-else>ereNo Items h</template>

<h5 class="text-right mt-5">Total:{{ total | numberFormat }}</h5>
<button class="btn btn-primary" :disabled="disabled">Confirm</button>

I want to disable the "Confirm Button" when items array is empty, and I have bind the disabled attribute on the button. But It does not work when I empty the items array.

How do I correctly disable the button ? Any help is appreciated. Thanks.

Upvotes: 0

Views: 1837

Answers (1)

Phil
Phil

Reputation: 164731

The button logic looks fine to me but your isEmpty() method logic is back-to-front for its name. It would only make sense if you called it isNotEmpty.

I would use the same computed property to determine both since using a method in a v-if is highly inefficient.

computed: {
  isEmpty: ({ items }) => items.length === 0
}

For example (and with a few other improvements)

new Vue({
  el: "#app",
  data: () => ({
    items: [{"id":1,"name":"Item 00","spec":"spec 00","price":400,"quantity":1,"unit":"unit 00"},{"id":2,"name":"Item 01","spec":"spec 01","price":416,"quantity":1,"unit":"unit 01"}]
  }),
  methods: {
    handleReduce (item) {
      item.quantity = Math.max(1, item.quantity - 1)
    },
    handleAdd (item) {
      item.quantity++;
    },
    handleRemove (index) {
      this.items.splice(index, 1);
    }
  },
  computed: {
    total: ({ items }) => items.reduce((total, { quantity, price }) =>
        total + quantity * price, 0),
    isEmpty: ({ items }) => items.length === 0
  },
  filters: {
    numberFormat: function(value) {
      return value.toString().replace(/\B(?=(\d{3})+$)/g, ',');
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<table id="app">
  <tbody>
  <template v-if="!isEmpty">
    <tr v-for="(item, index) in items" :key="item.id">
      <td>{{ index+1 }}.</td>
      <td>{{ item.name }}</td>
      <td>{{ item.spec }}</td>
      <td class="text-right">{{ item.price | numberFormat }}</td>
      <td>
      <button class="btn btn-sm btn-secondary" @click="handleReduce(item)" :disabled="item.quantity === 1">-</button>
      {{ item.quantity }}
      <button class="btn btn-sm btn-secondary" @click="handleAdd(item)">+</button>
      </td>
      <td>{{ item.unit }}</td>
      <td class="text-right">{{ (item.quantity * item.price) | numberFormat }}</td>
      <td class="text-right"><button class="btn btn-sm btn-danger" @click="handleRemove(index)">Remove</button></td>
    </tr>
  </template>

  <template v-else><tr><td>ereNo Items h</td></tr></template>
  </tbody>
  <tfoot>
  <tr><td colspan="8">
  <h5 class="text-right mt-5">Total:{{ total | numberFormat }}</h5>
  </td></tr>
  <tr><td colspan="8">
  <button class="btn btn-primary" :disabled="isEmpty">Confirm</button>
  </td></tr>
</table>

Upvotes: 2

Related Questions