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 SubscribeOur cart page is nearly fully functional! Just one last task: bring the remove button to life!
Let's repeat the process we used for quantity. Start in cart-item
. Find the button so we can add an "on click". I'll break this onto multiple lines. @click=
then $emit
and call the event, how about, removeFromCart
, though remove-from-cart
would better follow the standard naming convention for events.
<template> | |
<div :class="[$style.component, 'row', 'p-3']"> | |
... lines 3 - 29 | |
<div class="col-3"> | |
<button | |
class="btn btn-info btn-sm" | |
@click="$emit('removeFromCart')" | |
> | |
Remove | |
</button> | |
</div> | |
</div> | |
</template> | |
... lines 40 - 88 |
Unlike quantity, this time, we do not need to include any data with the event: we're simply saying "remove from cart".
Next, in index.vue
, listen to this with @removeFromCart=""
. Do the same thing we did before: emit an event with the same name - removeFromCart
- and make sure to include productId
and colorId
so that our parent component knows which item to remove. I'll copy these from the emit above.
<template> | |
<div> | |
... lines 3 - 6 | |
<div v-if="items.length"> | |
... lines 8 - 20 | |
<shopping-cart-item | |
... lines 22 - 29 | |
@removeFromCart="$emit('removeFromCart', { | |
productId: item.product['@id'], | |
colorId: item.color ? item.color['@id'] : null, | |
})" | |
/> | |
... lines 35 - 38 | |
</div> | |
</div> | |
</template> | |
... lines 42 - 72 |
Finally, we can listen to the removeFromCart
event from the top level shopping-cart.vue
. Scroll up. Hey! I have an extra import I can remove - yay! Keep going to find the <shopping-cart-list
component. Add @removeFromCart=""
.
But this time, instead of calling a method on this component, let's immediately put a new method in the mixin to handle everything related to removing an item from the cart.
Over in get-shopping-cart.js
, add a new method called removeProductFromCart()
. We know this will need the productId
and colorId
to identify which item it is. Inside, we can call another function from cart-service
that we haven't used yet. It's called removeItemFromCart()
. Hit tab so that it adds the import for us. Pass this the cart: this.cart
, productId
and colorId
.
import { | |
... lines 2 - 4 | |
removeItemFromCart, | |
... line 6 | |
} from '@/services/cart-service'; | |
export default { | |
... lines 10 - 19 | |
methods: { | |
... lines 21 - 45 | |
async removeProductFromCart(productId, colorId) { | |
await removeItemFromCart(this.cart, productId, colorId); | |
... lines 48 - 49 | |
}, | |
... lines 51 - 55 | |
}, | |
}; |
Hold Command or Ctrl and click removeItemFromCart
to jump into that function. Just like with updateCartItemQuantity()
, this does two things: it modifies the cart object to remove the item and then makes an AJAX call to save that to the server.
... lines 1 - 89 | |
/** | |
* Removes an item from the shopping cart | |
* | |
* @param {CartCollection} cart | |
* @param {string} productId | |
* @param {string} colorId | |
* @return {Promise} | |
*/ | |
export async function removeItemFromCart(cart, productId, colorId) { | |
cart.items = cart.items.filter( | |
(item) => (!(item.product === productId && item.color === colorId)), | |
); | |
const response = await axios.put(getCartIri(), cart); | |
return { items: response.data.items }; | |
} | |
... lines 107 - 149 |
Back in the mixin, don't forget to update the header: this.updateCartHeaderTotal()
. Oh, but let's await
for the AJAX call to finish before doing this.
... lines 1 - 8 | |
export default { | |
... lines 10 - 19 | |
methods: { | |
... lines 21 - 45 | |
async removeProductFromCart(productId, colorId) { | |
await removeItemFromCart(this.cart, productId, colorId); | |
this.updateCartHeaderTotal(); | |
}, | |
... lines 51 - 55 | |
}, | |
}; |
Ok: let's put our new method to work! Back in shopping-cart.vue
, since we use that mixin, we can call the method directly: removeProductFromCart()
passing $event.productId
and $event.colorId
.
<template> | |
<div :class="[$style.component, 'container-fluid']"> | |
<div class="row"> | |
... lines 4 - 5 | |
<div class="col-xs-12 col-lg-9"> | |
... lines 7 - 8 | |
<div class="content p-3"> | |
... lines 10 - 11 | |
<shopping-cart-list | |
... lines 13 - 15 | |
@removeFromCart="removeProductFromCart( | |
$event.productId, | |
$event.colorId, | |
)" | |
/> | |
</div> | |
</div> | |
</div> | |
</div> | |
</template> | |
... lines 26 - 103 |
Testing time! Find your browser and do a full page refresh to be safe. Right now, we have 15 items. Remove the couch with quantity 3 and.... it worked! The header says 12, the item is gone, the total updated. We rock! And, when we refresh, the item is still gone.
Next: I have a challenge for us! To help sell, I mean, "share", more high quality merchandise with the world, the marketing department has asked us to add a "featured product" to the sidebar of the cart page with the ability to add that item to the cart directly from this page - including choosing the color.
To accomplish this, we're going need to reuse a lot of code between the sidebar and the cart show page. Let's do it!
"Houston: no signs of life"
Start the conversation!
// 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
}
}