12

I am trying to find good solution to execute custom javascript when product is successfully added to cart. Also this custom javascript need information about product that was added to cart (sku, qty, price, name, etc.)

Currently I come up with the following way to get information about products added to cart:

  1. Rewrite $.mage.catalogAddToCart.prototype.enableAddToCartButton (for products added to cart from catalog or product view page)
  2. Rewrite $.mage.dataPost.prototype.postData (for products added to cart from widgets)

To get necessary information I have to parse page (f.e. to get qty) and output additional infromation to page (f.e. to get sku having product id)

However my solution:

  • has two entry points
  • does not look nice
  • does not handle situation when validation is failed on backend
  • does not provide me all required information conveniently

Unfortunately I was not able to find any suitable extension point of checkout minicart to resolve my problem.

Any suggestions are much appreciated!

QuestionsQuestions
3091 gold badge2 silver badges14 bronze badges
asked Mar 18, 2016 at 10:31
3
  • I have a similar situation. I have reviewed Magento code and logic and does not find any solution. So, Magento does not support it and maybe, it makes sense because you can add product without Ajax request. But, I must have solution for my task and I wrote the following file (cart-update.js): require([ 'jquery', 'underscore', 'jquery/jquery-storageapi' ], function(,ドル _) { var storage = $.initNamespaceStorage('mage-cache-storage').localStorage; $(document).on('ajaxComplete', function (event, xhr, settings) { if (settings.url.match(/customer\/section\/load/i) && xhr.responseJSON && xhr.responseJ Commented Aug 16, 2017 at 20:54
  • Have you tried using mixins? alanstorm.com/the-curious-case-of-magento-2-mixins I personally use them often. Just like the php version of plugins. If you get stuck let me know and I can provide a solution. Commented Jul 25, 2018 at 17:21
  • @ChrisAnderson thanks, but actually my current ugly solution described in the question is implemented using mixins. Commented Jul 27, 2018 at 11:28

2 Answers 2

10

When something is added to the cart, the local storage information is updated and you can subscribe to a knockout observable in the cart section of the customer data to be notified when it's content changes.

Here is an example:

require(['Magento_Customer/js/customer-data'], function (customerData) {
 var cart = customerData.get('cart');
 var count = cart().summary_count;
 cart.subscribe(function () {
 if (cart().summary_count !== count) {
 count = cart().summary_count;
 // do something here
 console.log('Number of items in cart is now: ' + count);
 }
 });
});
answered Nov 5, 2019 at 12:12
5
  • Even with a "domReady!" in the require block, seems to run too early on as cart().summary_count always 'undefined' ? Commented May 11, 2020 at 14:27
  • That is why you subscribe to the cart Commented May 12, 2020 at 15:14
  • This worked for me on Magento 2.3.4. count variable updates after adding to the cart Commented Jun 3, 2020 at 10:14
  • Works like a charm in Magento 2.2.2 Commented Jun 4, 2020 at 15:28
  • This is good to get the items in the cart or detect a change in cart, but how to identify the affected item. For example, which item added to cart? Commented Feb 12, 2024 at 8:51
1

A solution is to write a mixin for the catalogAddToCart ajaxSubmit function. Usually the data you require would not be available here but this can be fixed by modifying the checkout/cart/add controller to return the data. Full solution below, currently it just javascript alerts the data you needed on add to cart success.

app/code/VendorName/ModuleName/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
 \Magento\Framework\Component\ComponentRegistrar::MODULE,
 'VendorName_ModuleName',
 __DIR__
);

app/code/VendorName/ModuleName/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
 <module name="VendorName_ModuleName" setup_version="1.0.0">
 <sequence>
 <module name="Magento_Catalog"/>
 <module name="Magento_Checkout"/>
 </sequence>
 </module>
</config>

app/code/VendorName/ModuleName/etc/frontend/di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
 <preference for="Magento\Checkout\Controller\Cart\Add" type="VendorName\ModuleName\Controller\Cart\Add"/>
</config>

app/code/VendorName/ModuleName/Controller/Cart/Add.php

<?php
namespace VendorName\ModuleName\Controller\Cart;
/**
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class Add extends \Magento\Checkout\Controller\Cart\Add
{
 /**
 * Add product to shopping cart action
 *
 * @return \Magento\Framework\Controller\Result\Redirect
 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
 */
 public function execute()
 {
 if (!$this->_formKeyValidator->validate($this->getRequest())) {
 return $this->resultRedirectFactory->create()->setPath('*/*/');
 }
 $params = $this->getRequest()->getParams();
 try {
 if (isset($params['qty'])) {
 $filter = new \Zend_Filter_LocalizedToNormalized(
 ['locale' => $this->_objectManager->get(
 \Magento\Framework\Locale\ResolverInterface::class
 )->getLocale()]
 );
 $params['qty'] = $filter->filter($params['qty']);
 }
 $product = $this->_initProduct();
 $related = $this->getRequest()->getParam('related_product');
 /**
 * Check product availability
 */
 if (!$product) {
 return $this->goBack();
 }
 $this->cart->addProduct($product, $params);
 if (!empty($related)) {
 $this->cart->addProductsByIds(explode(',', $related));
 }
 $this->cart->save();
 /**
 * @todo remove wishlist observer \Magento\Wishlist\Observer\AddToCart
 */
 $this->_eventManager->dispatch(
 'checkout_cart_add_product_complete',
 ['product' => $product, 'request' => $this->getRequest(), 'response' => $this->getResponse()]
 );
 if (!$this->_checkoutSession->getNoCartRedirect(true)) {
 if (!$this->cart->getQuote()->getHasError()) {
 $message = __(
 'You added %1 to your shopping cart.',
 $product->getName()
 );
 $this->messageManager->addSuccessMessage($message);
 }
 return $this->goBack(null, $product, [
 'sku' => $product->getSku(),
 'name' => $product->getName(),
 'price' => $product->getPrice(),
 'qty' => isset($params['qty'])?$params['qty']:null
 ]);
 }
 } catch (\Magento\Framework\Exception\LocalizedException $e) {
 if ($this->_checkoutSession->getUseNotice(true)) {
 $this->messageManager->addNotice(
 $this->_objectManager->get(\Magento\Framework\Escaper::class)->escapeHtml($e->getMessage())
 );
 } else {
 $messages = array_unique(explode("\n", $e->getMessage()));
 foreach ($messages as $message) {
 $this->messageManager->addError(
 $this->_objectManager->get(\Magento\Framework\Escaper::class)->escapeHtml($message)
 );
 }
 }
 $url = $this->_checkoutSession->getRedirectUrl(true);
 if (!$url) {
 $cartUrl = $this->_objectManager->get(\Magento\Checkout\Helper\Cart::class)->getCartUrl();
 $url = $this->_redirect->getRedirectUrl($cartUrl);
 }
 return $this->goBack($url);
 } catch (\Exception $e) {
 $this->messageManager->addException($e, __('We can\'t add this item to your shopping cart right now.'));
 $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
 return $this->goBack();
 }
 }
 /**
 * Resolve response
 *
 * @param string $backUrl
 * @param \Magento\Catalog\Model\Product $product
 * @return $this|\Magento\Framework\Controller\Result\Redirect
 */
 protected function goBack($backUrl = null, $product = null, $result = [])
 {
 if (!$this->getRequest()->isAjax()) {
 return parent::_goBack($backUrl);
 }
 if ($backUrl || $backUrl = $this->getBackUrl()) {
 $result['backUrl'] = $backUrl;
 } else {
 if ($product && !$product->getIsSalable()) {
 $result['product'] = [
 'statusText' => __('Out of stock')
 ];
 }
 }
 $this->getResponse()->representJson(
 $this->_objectManager->get(\Magento\Framework\Json\Helper\Data::class)->jsonEncode($result)
 );
 }
}

app/code/VendorName/ModuleName/view/frontend/requirejs-config.js

var config = {
 config: {
 mixins: {
 'Magento_Catalog/js/catalog-add-to-cart': {
 'VendorName_ModuleName/js/catalog-add-to-cart-mixin': true
 },
 }
 }
};

app/code/VendorName/ModuleName/view/frontend/web/js/catalog-add-to-cart-mixin.js

define([
 'jquery',
], function ($) {
 'use strict';
 return function (widget) {
 $.widget('mage.catalogAddToCart', widget, {
 /**
 * @param {String} form
 */
 ajaxSubmit: function (form) {
 var self = this;
 $(self.options.minicartSelector).trigger('contentLoading');
 self.disableAddToCartButton(form);
 $.ajax({
 url: form.attr('action'),
 data: form.serialize(),
 type: 'post',
 dataType: 'json',
 /** @inheritdoc */
 beforeSend: function () {
 if (self.isLoaderEnabled()) {
 $('body').trigger(self.options.processStart);
 }
 },
 /** @inheritdoc */
 success: function (res) {
 alert(JSON.stringify(res));
 var eventData, parameters;
 $(document).trigger('ajax:addToCart', form.data().productSku);
 if (self.isLoaderEnabled()) {
 $('body').trigger(self.options.processStop);
 }
 if (res.backUrl) {
 eventData = {
 'form': form,
 'redirectParameters': []
 };
 // trigger global event, so other modules will be able add parameters to redirect url
 $('body').trigger('catalogCategoryAddToCartRedirect', eventData);
 if (eventData.redirectParameters.length > 0) {
 parameters = res.backUrl.split('#');
 parameters.push(eventData.redirectParameters.join('&'));
 res.backUrl = parameters.join('#');
 }
 window.location = res.backUrl;
 return;
 }
 if (res.messages) {
 $(self.options.messagesSelector).html(res.messages);
 }
 if (res.minicart) {
 $(self.options.minicartSelector).replaceWith(res.minicart);
 $(self.options.minicartSelector).trigger('contentUpdated');
 }
 if (res.product && res.product.statusText) {
 $(self.options.productStatusSelector)
 .removeClass('available')
 .addClass('unavailable')
 .find('span')
 .html(res.product.statusText);
 }
 self.enableAddToCartButton(form);
 }
 });
 }
 });
 return $.mage.catalogAddToCart;
 }
});
answered Aug 24, 2018 at 13:30

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.