Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

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.

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

Our 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!

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

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
    }
}
userVoice