Remove From 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.
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.
Adding More Mixin Logic
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!