Hi, we are having a little bit of trouble adding ajax to the COMMERCE MODULE Add to Cart form so it changes some elements besides the Shopping Cart.

This is our code in the hook_form_FORM_ID_alter() function to add Ajax support:

$form['#submit'][] = 'MYMODULE_add_to_cart_form_submit';
$form['submit']['#ajax'] = array(
  'callback' => 'MYMODULE_add_to_cart_form_ajax',
  'wrapper' => 'shoppingcart', // Our Shopping Cart VIEW has an id="shoppingcart".
  'method' => 'replace',
  'effect' => 'none',
  'progress' => array('type' => 'none'), // Don't want any throbber or progress bar.
);

In our submit function the only thing we are doing here is to REBUILD our form. We got this from reading this help http://api.drupal.org/api/drupal/includes--form.inc/function/drupal_rebu...

function MYMODULE_add_to_cart_form_submit($form, &$form_state) {
  // This rebuilds the form from cache and invokes the defined #ajax['callback'].
  $form_state['rebuild'] = TRUE;
}

So our main problem here is about about Drupal Messages.

If we use this code on our AJAX callback function...

function MYMODULE_add_to_cart_form_ajax($form, $form_state) {
  $uid = $form['uid']['#value'];
  $cart_order = commerce_cart_order_load($uid);
  $shoppingcart = commerce_embed_view('commerce_cart_block', 'default', array($cart_order->order_id));
  return $shoppingcart;
}

...then the Shopping Cart View is updated correctly AND a Drupal Message is added to the Shopping Cart Block, which is not a problem because we can move it to the correct location (via jQuery).

But we want to change more elements apart from the Shopping cart so we tried using Ajax COMMANDS in our AJAX callback function. We re-wrote our function to...

function MYMODULE_add_to_cart_form_ajax($form, $form_state) {
  $uid = $form['uid']['#value'];
  $cart_order = commerce_cart_order_load($uid);
  $shoppingcart = commerce_embed_view('commerce_cart_block', 'default', array($cart_order->order_id));

  $commands = array();
  $commands[] = ajax_command_replace('#full-node-shoppingcart', $shoppingcart);
  // We add here more commands but for the purpose of this example we add only one.

  return array('#type' => 'ajax', '#commands' => $commands);
}

...here the Shopping Cart View is updated correctly BUT no message is sent. In the next page full load (F5) it shows as a normal Drupal message. So if a user adds a Product and then goes to his Profile, the "Product has been added to your cart" message is shown in the Profile page. This also applies to validation errors (no stock for that quantity).

Is there a way to use ajax commands and still get the first functionality (the message is sent by Ajax so is not shown in the next page load)?
Thanx in advance.

Comments

rfay’s picture

I'm not sure you're going to get everything you want here, but you might. The key is to look at ajax_deliver() and see what the default response is and how it packages up the commands on a default response.

  else {
    // Like normal page callbacks, simple Ajax callbacks can return HTML
    // content, as a string or render array. This HTML is inserted in some
    // relationship to #ajax['wrapper'], as determined by which jQuery DOM
    // manipulation method is used. The method used is specified by
    // #ajax['method']. The default method is 'replaceWith', which completely
    // replaces the old wrapper element and its content with the new HTML.
    $html = is_string($page_callback_result) ? $page_callback_result : drupal_render($page_callback_result);
    $commands[] = ajax_command_insert(NULL, $html);
    // Add the status messages inside the new content's wrapper element, so that
    // on subsequent Ajax requests, it is treated as old content.
    $commands[] = ajax_command_prepend(NULL, theme('status_messages'));
  }

You can essentially do the same thing as here but do something different with the status messages.

rfay’s picture

Category: task » support
nevets’s picture

You could try adding

  $commands[] = ajax_command_replace('.messages', drupal_get_messages());
EndEd’s picture

Status: Fixed » Active

Hi, thanks both of you :)

We manage to sort this. Here's the new code of our AJAX callback function:

function MYMODULE_add_to_cart_form_ajax($form, $form_state) {
  $uid = $form['uid']['#value'];
  $cart_order = commerce_cart_order_load($uid);
  $shoppingcart = commerce_embed_view('commerce_cart_block', 'default', array($cart_order->order_id));

  $commands = array();
  $commands[] = ajax_command_replace('#full-node-shoppingcart', $shoppingcart);
  
  // Set message.
  $commands[] = ajax_command_remove('#messages-wrap');
  $commands[] = ajax_command_after('#breadcrumb-wrap', '<div id="messages-wrap">' . theme('status_messages') . '</div>');

  return array('#type' => 'ajax', '#commands' => $commands);
}

Using theme('status_messages') with no parameters gives us the themed message. This theme function already calls drupal_get_messages() so this is the way.

We had to remove and then add the message wrappper div because using ajax_command_replace only works if there's already a message (so the wrapper is there). This is strange because we read here that if no matched content is found it inserts, and if matched content is found it replaces, but we can't get it to work.

Anyway, thanks again, it was as simple as that.

EDIT: Forgot to say that in our page.tpl.php our $messages variable is printed inside a div with an id of "messages-wrap".

rfay’s picture

Status: Active » Fixed

Congratulations and thanks for reporting back.

EndEd’s picture

Issue summary: View changes

Corrected a few typos

Status: Active » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

timodwhit’s picture

Thanks the answer. Appreciate the help.

jason.fisher’s picture

Thanks. I was able to use this with my theme instead of a wrapper:

      $commands[] = ajax_command_remove('div.messages');
      $commands[] = ajax_command_before('#main-content', theme('status_messages'));
Atomox’s picture

This was a huge help! Thanks.

Atomox’s picture

Issue summary: View changes

changed code to php

f0ns’s picture

Thanks a lot! Man i've been breaking my head over this for quite some time! THANKS!

hurricane66’s picture

Extremly well written issue with valuable feedback of possible solutions. It's now 2014, some 3 years after the issue was written, and this documentation are as valid as ever before. Thanks all!

fnandogp’s picture

Same feeling here #11.

This helped me alot. Thank you guys.

vrwired’s picture

#8 is an easy way to get this done

elijah lynn’s picture

Crosslinking related forum thread => https://www.drupal.org/node/2081517 (form_set_error message not displayed when using an AJAX field on a form (with a AJAX callback using commands)).

shashwat purav’s picture

$commands[] = ajax_command_prepend(NULL, theme('status_messages'));

This worked for me. :)