Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Given this code:
/**
* Implements hook_form_FORM_ID_alter().
*/
function store_form_uc_product_add_to_cart_form_alter(&$form, &$form_state, $form_id) {
$form['actions']['submit']['#ajax'] = array(
'callback' => 'store_ajax_cart_add',
'progress' => FALSE,
);
}
/**
* Ajax Callback, Add a Product to the cart.
*/
function store_ajax_cart_add($form, &$form_state) {
// Load the array of shopping cart items.
$total_qty = uc_cart_get_total_qty();
$items = uc_cart_get_contents();
$commands = array();
$build = array();
// Display the empty cart page if there are no items in the cart.
if (empty($items)) {
$build['#theme'] = 'uc_empty_cart';
}
else {
$build = drupal_get_form('uc_cart_view_form', $items) + array(
'#prefix' => '<div id="cart-form-pane">',
'#suffix' => '</div>',
);
}
unset($build['cart_form']['actions']['continue_shopping']);
$commands[] = ajax_command_html('.block-uc-cart .content', '');
$commands[] = ajax_command_html('.block-uc-cart .content', drupal_render($build));
$commands[] = ajax_command_before('#'.$form['#id'], '<div class="ajax-hidden remove-soon" style="display:none; opacity:0;">'.theme('status_messages').'</div>');
$commands[] = ajax_command_invoke('div.ajax-hidden', 'ajaxSlide');
$commands[] = ajax_command_invoke('div.ajax-hidden', 'removeClass', array('ajax-hidden'));
if (!empty($total_qty)) {
$commands[] = ajax_command_after('.cart-block-icon-empty', ' <span class="cart-block-item-count"></span>');
$commands[] = ajax_command_invoke('.cart-block-item-count', 'text', array(number_format($total_qty)));
$commands[] = ajax_command_invoke('.cart-block-icon-empty', 'addClass', array('cart-block-icon-full'));
$commands[] = ajax_command_invoke('.cart-block-icon-empty', 'removeClass', array('cart-block-icon-empty'));
}
return array('#type' => 'ajax', '#commands' => $commands);
}
Every time the form is submitted (with Ajax) I get this Javascript error:
TypeError: element_settings.url.replace is not a function
this.url = element_settings.url.replace(/\/nojs(\/|$|\?|&|#)/g, '/ajax$1');
ajax.js?v=7.14 (line 132)
I discovered that this has to do with the drupal_get_form in the ajax callback. When I remove the form get, the error disappears.
Also, if I go to misc/ajax.js and remove line 132 it also clears up the errors.
I'd like to not modify core (misc/ajax.js), and I'd also like to return the form with Ajax.
Am I doing something wrong is is this a Drupal bug?
Comment | File | Size | Author |
---|---|---|---|
#23 | 1715508.patch | 2.11 KB | RobLoach |
#21 | drupal-1715508-19-ajax_js_error.patch | 763 bytes | RobLoach |
#19 | drupal-1715508-19-ajax_js_error.patch | 837 bytes | RobLoach |
#18 | drupal-ajax_javascript_error-1715508-18.patch | 802 bytes | khoomy |
#12 | response.png | 154.22 KB | maciej.zgadzaj |
Comments
Comment #1
davidwbarratt CreditAttribution: davidwbarratt commentedFirst patch attempt. Simply checks to make sure that replace() is a valid function before moving forward.
Comment #2
davidwbarratt CreditAttribution: davidwbarratt commentedHmm, why is the tester ignoring the patch?
Comment #3
nod_You'd want to check that
element_settings.url
is a string instead. No need for the jQuery thing.Comment #4
davidwbarratt CreditAttribution: davidwbarratt commentedgood call! #learnsoemthingneweveryday
try this patch.
Comment #5
aspilicious CreditAttribution: aspilicious commentedI had this before I'm not sure this is the root of the problem.
Comment #6
davidwbarratt CreditAttribution: davidwbarratt commentedI'm not sure if it is or not, but the patch fixes the problem.
thanks!
Comment #7
dgastudio CreditAttribution: dgastudio commentedi have the same problem in d7, using custom views exposed filter.
patch solves it.
thank you.
Comment #8
osopolarelement_settings.url should always be a string, if this is not the case then it's an indication that something else went wrong.
Are you using webforms together with modal_forms? In my case element_settings.url was an object (with two different url's). The reason was a tiny bug introduced in #1326716: Webform module support (see #25 of quoted issue;
ctools_modal_form_wrapper()
was called twice so the form got build two times => this was the reason why there appeared two urls in element_settings).Comment #9
ygerasimov CreditAttribution: ygerasimov commentedI have faced this bug as well (similar case with "Add to cart" commerce button using custom ajax callback) and patch fixes the problem.
Big thanks.
Comment #10
osopolar@ygerasimov Did you check for the reason why element_settings.url was not a string in your case. This is a bit harder to track but seems to be the correct way. IMHO this patch only treats the symptoms but hides the cause instead of fixing it.
I am against this patch until its proven that element_settings.url is allowed to be something else than a string. See for example: #1326716: Webform module support #25.
Comment #11
ygerasimov CreditAttribution: ygerasimov commented@osopolar no I haven't checked that. I agree that it will be better way to find out why element_settings.url is not a string. Lets keep this patch in "needs work" status. But I have no idea where to look at truly to say.
Comment #12
maciej.zgadzaj CreditAttribution: maciej.zgadzaj commentedI have experienced this problem too, twice actually over the last few days, with slightly different messages, on different sites, but the general issue seems to be exactly the same.
The problem is that in JSON returned by ajax callback some
Drupal.settings
values are getting duplicated, and we're left with arrays instead of scalars. (Edit: In both cases it is "caused by" form elements added by custom Views field handlers with defined #ajax callbacks.)See the attached response.png. Check the values of everything inside expanded
settings.ajax.commerce_coupon_remove_2
.For example,
url
should be just"/system/ajax"
(scalar), not["/system/ajax", "/system/ajax"]
(array).The same applies to all other values.
For me this happens only with ajax calls, which for some reason re-add the same setting values turning them from scalars to arrays.
Attached patch to
common.inc
(against 7.x) helps here and gets rid of this problem - not sure though if it is really a proper solution to this...Comment #13
maciej.zgadzaj CreditAttribution: maciej.zgadzaj commentedStatus change.
Comment #15
maciej.zgadzaj CreditAttribution: maciej.zgadzaj commentedPatch against 8.x.
Comment #16
maciej.zgadzaj CreditAttribution: maciej.zgadzaj commentedRelated issues:
#208611: Add drupal_array_merge_deep() and drupal_array_merge_deep_array() to stop drupal_add_js() from adding settings twice
#1875632: JS settings merging behavior: preserve integer keys (allow for array literals in drupalSettings)
Comment #17
maciej.zgadzaj CreditAttribution: maciej.zgadzaj commentedClosing as a duplicate of issues linked to in my previous comment, plus extra few linked from them.
Comment #18
khoomy CreditAttribution: khoomy as a volunteer commentedPatch from related issues as mentioned in #16 does not work.
TypeError: element_settings.url.replace is not a function
Appears when element_settings.url has array instead of string. When it appears as array then there are multiple key value pairs having same keys and values all the time, so in this case we have to pick first value.
Attached patch fixed my issue
Comment #19
RobLoachThe linked issues above don't really look like duplicates. Here's a patch that applies to the Drupal 7 root. Not sure of ajax.js's state in D8.
Comment #21
RobLoachComment #23
RobLoachComment #24
stefan.r CreditAttribution: stefan.r commentedD8 still has that snippet -- is this still an issue there?