Add To Cart

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

The cart data is being loaded via AJAX... and we need that data before we can add a new item to the cart. It should all load pretty quickly, but to be safe, let's prevent the user from clicking the "Add to cart" button until that AJAX call is done.

Head up to find that button. This is delightfully simply: add :disabled set to cart === null.

<template>
<div>
... lines 3 - 8
<div
... lines 10 - 12
>
... lines 14 - 30
<div class="col-8 p-3">
... lines 32 - 33
<div class="row mt-4 align-items-center">
... lines 35 - 38
<div class="col-8 p-3">
<div class="d-flex align-items-center justify-content-center">
... lines 41 - 50
<button
class="btn btn-info btn-sm"
:disabled="cart === null"
>
Add to Cart
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
... lines 64 - 132

If we don't have a cart, no clicky the button! It's disabled.

On Click, Add to Cart

Now let's hook up the real functionality: @click="" and call a new addToCart() method:

<template>
<div>
... lines 3 - 8
<div
... lines 10 - 12
>
... lines 14 - 30
<div class="col-8 p-3">
... lines 32 - 33
<div class="row mt-4 align-items-center">
... lines 35 - 38
<div class="col-8 p-3">
<div class="d-flex align-items-center justify-content-center">
... lines 41 - 50
<button
class="btn btn-info btn-sm"
:disabled="cart === null"
@click="addToCart"
>
Add to Cart
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
... lines 65 - 142

Head down to the component, add methods: {}, then addToCart(). This won't need any arguments.

... lines 1 - 65
<script>
... lines 67 - 73
export default {
name: 'ProductShow',
... lines 76 - 113
methods: {
addToCart() {
... lines 116 - 120
},
},
};
</script>
... lines 125 - 142

Inside, we can use an addItemToCart method from cart-service. I'll type addItemToCart() and hit tab to auto-complete... because that little trick gets PhpStorm to add the import for me.

Ok, the first argument is the cart object - so this.cart. In practice, we know that it's safe to reference this.cart because our addToCart method can't be called until after the cart AJAX call has finished. Until then, the button is disabled.

... lines 1 - 65
<script>
import { fetchCart, addItemToCart } from '@/services/cart-service.js';
... lines 68 - 73
export default {
name: 'ProductShow',
... lines 76 - 113
methods: {
addToCart() {
addItemToCart(this.cart, {
... lines 117 - 119
});
},
},
};
</script>
... lines 125 - 142

The second argument is the item to add. This is an object with three things: product - set to the product IRI, so this.product['@id'] - color - which for right now, I'm going to set to null - and quantity set to 1.

... lines 1 - 65
<script>
import { fetchCart, addItemToCart } from '@/services/cart-service.js';
... lines 68 - 73
export default {
name: 'ProductShow',
... lines 76 - 113
methods: {
addToCart() {
addItemToCart(this.cart, {
product: this.product['@id'],
color: null,
quantity: 1,
});
},
},
};
</script>
... lines 125 - 142

If... you're thinking:

How did Ryan magically know what keys to pass here?

That's... a fair question. This is just how the API is designed. If you go back to the API docs... and open the put endpoint, the example shows the keys we're using. Both of those strings are IRI strings.

Anyways... I think it's testing time! I'll refresh to be sure... hit "Add to Cart" and... I think it worked? I don't see any errors... but I can see the successful AJAX call to /api/carts. It's a POST request because this is creating a new cart.

Let's see if the cart data updated inside Vue. Hmm, it did not! This is a quirk that is completely unrelated to Vue... but I wanted to show in case it happens to you. If we look at the HTML source, we can see that window.cartIri is still null. The problem is that I use localhost:8000 for tons of projects, which means I already have some session cookies from those other projects. And since I'm using http instead of https this time, my browser is refusing to override my old secure cookie with an insecure one.

The fix is to go to Application and clear the storage to get rid of any cookies from other projects.

Let's try this again. Refresh... go back to the Vue dev tools and click "Add to Cart". This time when I refresh... yea! Look at the header! It says: "Shopping cart (1)". And if we look at the Vue tools... yes! The cart contains 1 item with quantity 1.

To prove we can increase the quantity, hit "Add to Cart" 2 more times. Notice that the header does not instantly update. That's no surprise, but we will fix that. Refresh to see the new value and... yes! It says 3! Our cart still only has one item, but with quantity 3.

So.. yay! We can add things to our cart! Next, let's make this whole process fancier with some animations and hook up the quantity input.

Leave a comment!

This course is also built to work with Vue 3!

What JavaScript libraries does this tutorial use?

// package.json
{
    "devDependencies": {
        "@fortawesome/fontawesome-free": "^5.15.1", // 5.15.1
        "@symfony/webpack-encore": "^0.30.0", // 0.30.2
        "axios": "^0.19.2", // 0.19.2
        "bootstrap": "^4.4.1", // 4.5.3
        "core-js": "^3.0.0", // 3.6.5
        "eslint": "^6.7.2", // 6.8.0
        "eslint-config-airbnb-base": "^14.0.0", // 14.2.0
        "eslint-plugin-import": "^2.19.1", // 2.22.1
        "eslint-plugin-vue": "^6.0.1", // 6.2.2
        "regenerator-runtime": "^0.13.2", // 0.13.7
        "sass": "^1.29.0", // 1.29.0
        "sass-loader": "^8.0.0", // 8.0.2
        "vue": "^2.6.11", // 2.6.12
        "vue-loader": "^15.9.1", // 15.9.4
        "vue-template-compiler": "^2.6.11", // 2.6.12
        "webpack-notifier": "^1.6.0" // 1.8.0
    }
}