Cart quantity update ajax

Created on 10 April 2018, almost 7 years ago
Updated 25 March 2025, 12 days ago

For usability it's better to auto update (with ajax) the totals of the cart, when you change the quantity of a line item. When the auto update works you don't need the update cart button, like how it works in Magento or Prestashop.

Feature request
Status

Closed: won't fix

Version

2.0

Component

Cart

Created by

🇳🇱Netherlands dvanbrenk

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇧🇪Belgium flyke

    This is what works for me in a Drupal 11.1.4 project with Commerce 3.0.0.
    I post this here because this was the first google result I found for my question but I did not find a working answer here, so I'll post mine.

    use Drupal\Core\Form\FormStateInterface;
    use Drupal\Core\Ajax\AjaxResponse;
    use Drupal\commerce_order\Entity\OrderInterface;
    use Drupal\Core\Url;
    use Drupal\Core\Ajax\RedirectCommand;
    
    /**
     * Implements hook_form_alter().
     */
    function mymodule_form_alter(&$form, FormStateInterface $form_state, $form_id) {
    
      // Alter the cart form (/cart page).
      if (strpos($form_id, 'views_form_commerce_cart_form') !== FALSE) {
        _mymodule_alter_cartform($form, $form_state);
      }
    }
    
    /**
     * Alter the cart form (/cart page).
     */
    function _mymodule_alter_cartform(&$form, FormStateInterface $form_state) {
    
      // Add ajax callback to each quantity element.
      foreach ($form['edit_quantity'] as $key => &$quantity_field) {
        if (!is_numeric($key) || !is_array($quantity_field)) {
          continue;
        }
        // Add AJAX callback to quantity field.
        $quantity_field['#ajax'] = [
          'callback' => 'mymodule_cart_ajax_refresh',
          'event' => 'change',
        ];
      }
    }
    
    /**
     * AJAX callback function to refresh the cart.
     */
    function mymodule_cart_ajax_refresh(array &$form, FormStateInterface $form_state) {
      // Prepare a response.
      $response = new AjaxResponse();
      // Get cart order quantities from the cart form.
      // They can be updated and differ from the ones saved in the cart.
      $quantities = $form_state->getValue('edit_quantity');
    
      // Do nothing if there are no quantities.
      if (!$quantities || empty($quantities)) {
        return $response;
      }
    
      // Get the cart.
      $cart_provider = \Drupal::service('commerce_cart.cart_provider');
      // Get the current user's cart.
      $carts = $cart_provider->getCarts();
      $cart = reset($carts); // Get the first cart (assuming single cart per user).
    
      // Validate cart.
      if (!$cart instanceof OrderInterface) {
        return $response;
      }
    
      // Get cart items.
      $cart_items = $cart->getItems();
    
      // Compare quantities from the cart form to the saved cart quantities.
      foreach ($quantities as $key => $form_quantity) {
        if (!isset($cart_items[$key])) {
          continue;
        }
        $form_quantity = number_format((float) $form_quantity, 2, '.', '');
        $cart_quantity = $cart_items[$key]->getQuantity();
    
        // Do nothing if nothing is chaged.
        if ($form_quantity === $cart_quantity) {
          continue;
        }
    
        // Change the quantity in the cart item to that from the cart form.
        $cart_items[$key]->setQuantity($form_quantity);
        $cart_items[$key]->save();
      }
    
      // Save the cart so that the subtotal and total values will be refreshed.
      $cart->save();
    
    
      // Reload the current page.
      $url = Url::fromRoute('<current>');
      $command = new RedirectCommand($url->toString());
      $response->addCommand($command);
      return $response;
    }
Production build 0.71.5 2024