Ajax does not work second time.
I have created a custom module to update custom options.
It works with a button, however it does not work well with Ajax.
Do you have any suggestions for what I can do?
My post was removed when I was editing it to make it clear for everyone.
Frontend:
require(['jquery', 'Magento_Checkout/js/action/get-payment-information', 'Magento_Checkout/js/model/quote', 'mage/storage'], function($, getPaymentInformationAction, quote){ $(document).on( "click", ".product-custom-option", function() { $('#loading-mask').show(); var data = $( "#form-validate" ).serialize(); data.form_key = window.FORM_KEY; data.update_cart_action = "update_ajax_options"; $.ajax({ type: "POST", url: "<?= $block->getUrl('checkout/cart/updatePost') ?>", data: data + "&update_cart_action=update_ajax_options", success: function (data) { console.log(data.cartcontent); var totalsData=data.subtotaldata.totalsData; quote.setTotals(totalsData); if(data.cartcontent && Number(totalsData.subtotal)>0){ $('.cart-container form#form-validate').replaceWith(data.cartcontent); $('[data-block="minicart"]').trigger('contentLoading'); $('[data-block="totals"]').trigger('contentLoading'); $('.cart-sidebar .checkout-methods-items').replaceWith(data.checkout_method); // $('.item-options').replaceWith(data.item-options); $('.cart-sidebar').trigger('contentUpdated'); if ($(".messages")[0]){ $('.messages').replaceWith(data.page_messages); }/**/ } $('#loading-mask').hide(); }, failure: function (errMsg) { console.log(errMsg); $('#loading-mask').hide(); } }) }); });
in UpdatePost.php
public function execute() { $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->addInfo("execute"); /** @var \Magento\Framework\Controller\Result\Json $resultJson */ if (!$this->_formKeyValidator->validate($this->getRequest())) { // return $this->resultRedirectFactory->create()->setPath('*/*/'); } $updateAction = (string)$this->getRequest()->getParam('update_cart_action'); switch ($updateAction) { case 'empty_cart': $this->_emptyShoppingCart(); break; case 'update_qty': $this->_updateShoppingCart(); break; case 'update_ajax_options': $this->_updateShoppingCart(); return $this->_getTotalsHtml(); break; default: $this->_updateShoppingCart(); } return $this->_goBack(); } protected function _getTotalsHtml() { $response2 = $this->resultFactory->create(ResultFactory::TYPE_PAGE); $layout = $response2->addHandle('checkout_cart_index')->getLayout(); $response['cartcontent'] = $this->_view->getLayout()->getBlock('checkout.cart.form')->toHtml(); $response['checkout_method'] = $this->_view->getLayout()->getBlock('checkout.cart.methods.bottom')->toHtml(); $response['page_messages'] = $this->_view->getLayout()->getBlock('checkout.cart.validationmessages')->toHtml(); // $response['cart_item'] = $this->_view->getLayout()->getBlock('checkout.cart.item')->toHtml(); $response['content'] = $layout->renderNonCachedElement('checkout.cart.empty'); $cartQuote= $this->cart->getQuote()->setTotalsCollectedFlag(false)->collectTotals(); $response['subtotaldata'] = $this->_objectManager->create('Magento\Checkout\Model\DefaultConfigProvider')->getConfig(); $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON); $resultJson->setData($response); $this->_checkoutSession->getQuote()->collectTotals()->save(); return $resultJson; } protected function _updateAjaxOptions(){ $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->addInfo("_updateAjaxOptions"); $this->_updateShoppingCart(); return; } /** * Reload cart to display custom options correctly in AJAX response */ protected function _reloadCart() { $currQuoteId = $this->_checkoutSession->getQuoteId(); $this->_checkoutSession->unsetAll(); $this->_checkoutSession->setQuoteId($currQuoteId); $cart = $this->cart; if ($cart->getQuote()->getItemsCount()) { $cart->save(); } } /** * Update customer's shopping cart * * @return void */ protected function _updateShoppingCart() { $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->addInfo("_updateShoppingCart"); try { $cartData = $this->getRequest()->getParam('cart'); $this->_checkoutSession->setMyValue($cartData); if (is_array($cartData)) { $filter = new \Zend_Filter_LocalizedToNormalized( ['locale' => $this->_objectManager->get( \Magento\Framework\Locale\ResolverInterface::class )->getLocale()] ); foreach ($cartData as $index => $data) { if (isset($data['qty'])) { $cartData[$index]['qty'] = $filter->filter(trim($data['qty'])); } } if (!$this->cart->getCustomerSession()->getCustomerId() && $this->cart->getQuote()->getCustomerId()) { $this->cart->getQuote()->setCustomerId(null); } $cartData = $this->cart->suggestItemsQty($cartData); $this->cart->updateItems($cartData)->save(); $this->_reloadCart(); $this->_checkoutSession->setMyValue($cartData); } } catch (\Magento\Framework\Exception\LocalizedException $e) { $this->messageManager->addError( $this->_objectManager->get(\Magento\Framework\Escaper::class)->escapeHtml($e->getMessage()) ); } catch (\Exception $e) { $this->messageManager->addException($e, __('We can\'t update the shopping cart.')); $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e); } }
Solved! Go to Solution.
I have fixed the issue. When it's loading layout after ajax call, it was writing a wrong html as there is a condition to see if this is "checkout_cart_index". As this was "checkout_cart_Updatepost", it should load the same code as "checkout_cart_index".
It only gets this error in exception.log. I am not sure if it's related to the problem I have.
main.CRITICAL: Dotmailer connector API endpoint cannot be empty. {"exception":"[object] (Magento\\Framework\\Exception\\LocalizedException(code: 0): Dotmailer connector API endpoint cannot be empty. at /vendor/dotmailer/dotmailer-magento2-extension/Model/Apiconnector/Client.php:118)"} []
You can just disable Dotmailer Module by app/etc/config.php with
'Dotdigitalgroup_Email' => 0,
remove generated folder from root and check again. If Still not working then enable dotmailer module and issue related to your custom module.
It still the same. It looks like it's not updating input values ... for instance when there is a checked checkbox and a customer unchecked it, it does not mark as unchecked - stay checked in the backend, but it displayes as unchecked.
I can change quantity on 2nd time, it's just custom options stops working.
If refresh the page it works again, I think it's matter of refreshing cart in backend.
You need to create sections.xml file in your module etc/frontend scope,
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd"> <action name="[frontName]/[ActionPath]/[ActionName]"> <section name="cart"/> </action> </config>
You need to set in above [frontName]/[ActionPath]/[ActionName] from your module name.
You need to set [frontName]/[ActionPath]/[ActionName] from your module name.
Maybe it's because I'm using a custom code on Catalog/Product/Options/Type/Select.php.
Any suggestions...?
in function getValuesHtml();
$this->setSkipJsReloadPrice(1); // Remove inline prototype onclick and onchange events if ($_option->getType() == \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_DROP_DOWN || $_option->getType() == \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_MULTIPLE ) { $require = $_option->getIsRequire() ? ' required' : ''; $extraParams = ''; $select = $this->getLayout()->createBlock( \Magento\Framework\View\Element\Html\Select::class )->setData( [ 'id' => 'select_' . $_option->getId(), 'class' => $require . ' product-custom-option admin__control-select' ] ); if ($_option->getType() == \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_DROP_DOWN) { $select->setName('options[' . $_option->getid() . ']')->addOption('', __('-- Please Select --')); } else { $select->setName('options[' . $_option->getid() . '][]'); $select->setClass('multiselect admin__control-multiselect' . $require . ' product-custom-option'); } foreach ($_option->getValues() as $_value) { $priceStr = $this->_formatPrice( [ 'is_percent' => $_value->getPriceType() == 'percent', 'pricing_value' => $_value->getPrice($_value->getPriceType() == 'percent'), ], false ); $select->addOption( $_value->getOptionTypeId(), $_value->getTitle() . ' ' . strip_tags($priceStr) . '', ['price' => $this->pricingHelper->currencyByStore($_value->getPrice(true), $store, false)] ); } if ($_option->getType() == \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_MULTIPLE) { $extraParams = ' multiple="multiple"'; } if (!$this->getSkipJsReloadPrice()) { $extraParams .= ' onchange="opConfig.reloadPrice()"'; } $extraParams .= ' data-selector="' . $select->getName() . '"'; $select->setExtraParams($extraParams); if ($configValue) { $select->setValue($configValue); } return $select->getHtml(); } if ($_option->getType() == \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_RADIO || $_option->getType() == \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_CHECKBOX ) { $selectHtml = '<div class="options-list nested" id="options-' . $_option->getId() . '-list">'; $require = $_option->getIsRequire() ? ' required' : ''; $arraySign = ''; switch ($_option->getType()) { case \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_RADIO: $type = 'radio'; $class = 'radio admin__control-radio'; if (!$_option->getIsRequire()) { $selectHtml .= '<div class="field choice admin__field admin__field-option">' . '<input type="radio" id="options_' .$iCurrentItemId.'_'. $_option->getId() . '" class="' . $class . ' product-custom-option" '. ($this->_request->getFullActionName()=="checkout_cart_index"? 'name="cart['.$iCurrentItemId.'][cart_options][' .$_option->getId() .'] ' : 'name="options[' .$_option->getId() .']"' ). ' data-selector="options[' . $_option->getId() . ']"' . ($this->getSkipJsReloadPrice() ? '' : ' onclick="opConfig.reloadPrice()"') . ' value=""'. ($this->_request->getFullActionName()=="checkout_cart_index" ? '' : 'checked="checked"' ) .' /><label class="label admin__field-label" for="options_' . $_option->getId() . '"><span>' . __('None') . '</span></label></div>'; $selectHtml .= "";
Thank you,
I have created sections.xml and placed this code below, but it remains same:
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd"> <action name="checkout/cart/updatepost"> <section name="cart"/> </action> </config>
I have created routes.xml and sections.xml. However the problem is still there.
routes.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/App/etc/routes.xsd"> <router id="standard"> <route id="vender_module" frontName="vender_module"> <module name="Vender_Module" /> </route> </router> </config>
sections.xml:
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd"> <action name="vender_module/checkout/updatepost"> <section name="cart"/> </action> </config>
I have fixed the issue. When it's loading layout after ajax call, it was writing a wrong html as there is a condition to see if this is "checkout_cart_index". As this was "checkout_cart_Updatepost", it should load the same code as "checkout_cart_index".
Can you please explain the solution in detail as I'm also stuck on the same issue, ajax working only one time.