If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeThe 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.
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.
Hey @atournayre!
Hmmm. Are you getting this directly from the downloaded course code? Or trying things on a fresh project with newer dependencies? That line - 56 - from ItemNormalizer
might be getting triggered via the individual product
being denormalized. I see that we're sending id: 1
in the JSON. If you remove that before making the AJAX call, does that make things all better?
On a high level, that IS the part that looks odd. We're sending a product
set to an object with @id
AND individual fields. Usually, you do one or the other: set product
to an IRI string to tell AI Platform to use that existing product or set it to an object of data without an @id
, which indicates that a new product should be created. Iirc, in the tutorial, we set product
to its @id
string - you can see that in this code block - https://symfonycasts.com/screencast/vue2/add-to-cart#codeblock-a668af6a6e - notice we're passing this.product['@id']
.
Let me know if that helps :).
Cheers!
my phpstorm keeps doing stuff like this for auto importing. how do i fix it so that it will use the @ for home directory and add space around curly braces?
import {addItemToCart} from "../services/cart-service";
Hey Robin,
Probably take a look at Preferences in your PhpStorm, I don't know if that may be configured, but if it may be - it should be in preferences then. On mac, you can press "Commad" + "," shortcut, or go to PhpStorm menu -> Preferences.
I hope this helps.
Cheers!
// 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
}
}
Hi,
Currently adding item to cart cause an issue.
I don't understand why, Cart seems well configured in ApiPlatform.