I've been working on a form submission module where the user effectively uploads a file and gets the form returned to them for the chance to upload another file. The AJAX function needs to work every time as there will be video(stream) playing on the page that would be very inconvenient for the user to restart on a full page load.

The AJAX function rebuilds perfectly for infinite submissions if I place the form inside the main content area of a page, but if the form is inside a block or a view then it only works for the first submission; the second submission reloads the entire page. Why is the behaviour different? If anyone knows the answer and how to fix it I'd be very grateful.

A bit of my code from the form:

$form['submit'] = array(
  '#type' => 'submit',
  '#ajax' => array(
	'callback' => 'marioart_comp_ajax_callback',
	'wrapper' => 'artcompform',
	'effect' => 'fade',
  ),
  '#value' => t('Upload'),
);

and from the AJAX callback:

function marioart_comp_ajax_callback($form, $form_state) {
  $errors = form_get_errors();
  if( $errors ) {
	return array('#markup' => '<div id="artcompform"><div class="formerror">' . $errors['file'] . $errors['required'] . '</div>' . drupal_render($form) . '</div>');
  } else {
	form_clear_error();
	return array('#markup' => '<div id="artcompform"><div class="formdone">The file was uploaded successfully.</div>' . drupal_render($form) . '</div>');
  }
}

$form_state['rebuild'] = TRUE; is being called in the submit hook as well, but I should stress that the fail on the second submission occurs regardless of whether or not the initial submission passed validation or not.

Edit: The error that firebug throws up - TypeError: $("a.views-remove-link").once is not a function

$('a.views-remove-link').once('views-processed').click(function(event) { - line 21 of base.js

Looking at ajax.js, it removes the old content before it process the new content. Is it possible that this error is stopping the ajax.js from continuing and adding the drupal behaviours that are required to make the ajax work again? And what is causing the error? Views? ajax.js itself? As I've mentioned before, any help is greatly appreciated.

Comments

jaypan’s picture

An example ajax callback would look something like this:

function my_module_ajax_callback($form, &$form_state)
{
  return render($form['some_part_of_the_form']);
}

Your problem lies with your ajax callback.

Contact me to contract me for D7 -> D10/11 migrations.

kfowler83’s picture

Thank you for your reply, but even if I simplify the AJAX callback to just return render($form); I still have the same problem. The page build creates the form with AJAX functioning correctly, but the AJAX build fails to add the functionality so the second incarnation of the form (the one returned by the AJAX callback function) does a full page reload when submit is clicked.

After a lot more reading, I believe it is the drupal.attachbehaviours() not working in the ajax.js script. The comments inside the javascript suggest that the form needs to be near top level and I don't think that's the case when the form is inside all of the markup from a view or block, whereas the form rebuilds correctly when the form is in the main page content. Trouble is, I don't know how to attach the behaviours myself and the form needs to be located inside a view for the particular website I am creating.

kfowler83’s picture

After another 8 hours of reading documentation and forums, I've isolated the error to the file field. Removing the file field from the form allows the form to be rebuilt an infinite number of times regardless of its location (ie. main body of page or in a block).

A solution is still beyond my grasp however...

kfowler83’s picture

Solved! There are obviously several layers to this problem, but essentially the submit button requires a unique id to be provided directly on the form, otherwise it'll get assigned one automatically by drupal. That's fine for a form in the main page area as it receives the same id every time (edit-submit), but forms placed in a block area get an incremented id after every submission so essentially the link between the initial form and the regenerated form is lost (and the AJAX along with it. Why this problem is specific to forms with a file field though I still don't know (and have no intention and wasting any more time on what would only be academic at this point).

So, from the code in my original post, all that has changed is the form function:

$form['submit'] = array(
  '#type' => 'submit',
  '#ajax' => array(
	'callback' => 'marioart_user_ajax_callback',
	'wrapper' => 'artuserform',
	'effect' => 'fade',
  ),
  '#value' => t('Upload'),
  '#id' => 'myuniqueid',
);
marksims0003’s picture

I realize this is an older post, but I just wanted to say thanks for posting this info. I was able to resolve a similar issue in under 30 minutes. Thanks!

geerlingguy’s picture

I had to set the form ID for my form manually ($form['#id'] = 'form-id-here';) in order for a complex multi-step and multi-element AJAX setup to work correctly. Because of the form's structure, I had to return the entire $form array in the primary AJAX callback, and since Drupal incremented (changed) the form's HTML ID every time an AJAX request went through, the form wasn't updating correctly.

__________________
Personal site: www.jeffgeerling.com

klonos’s picture

I know this is many years later, but in the hope that this helps anyone else struggling with this, this was exactly what the issue was in my case as well.

In my use case, I was targeting a fieldset with AJAX, but each time the button that would trigger the AJAX was clicked, the HTML ID of the fieldset would be auto-incremented (by appending "--x" to the default ID assigned by Form API to the fieldset, where x is a number). So because the target ID was only there for the first AJAX call (after the initial clicking of the submit button), subsequent clicks would not be able to find a valid target present in the DOM.

The trick was to manually set the ID that AJAX would target (the ['#ajax']['wrapper] property of the submit button) for the fieldset, by specifying "['#attributes']['id']['custom-id']". Once the HTML ID for the fieldset is set manually, subsequent AJAX calls and form rebuilds do not auto-increment the custom ID, and since this custom ID remains the same after each click and form rebuild, AJAX would have a valid target.

papradie’s picture

I had similar problem. I had element of type "image_button". On click, I wanted to make ajax form submit. My element had unfortunately set property '#executes_submit_callback' = true.

After I changed this property to false, it worked.

    $form['element'] = array(
		'#type' => 'image_button',
		'#src' => 'img_src',
		'#executes_submit_callback' => false,
		'#ajax' => array(
			'callback' => 'my_callback',
			'wrapper' => $element_id,
			'method' => 'replace',
		),
	);
RavindraSingh’s picture

In your code just remove the line '#executes_submit_callback' => false from form $form['element'] attributes.

jnpwebdeveloper’s picture

Thank you soo much mate! I was debugging a user registration form and could not for the life of me figure out why the form was not returning correctly. Turns out I had two registrations forms and the submit ID's were interfering with each other. Your post pointed this out and I was able to fix it immediately. You have saved me loads of time. Thank you for this.

orgnsm’s picture

I'm also loading reg form into a container and debugging the ajax submission of said form. I'd love to see your working code because I can't find my error. Cheers

jpat14’s picture

I know this thread is three years old, but you just solved a problem I've spent a couple of days scratching my head about.

RavindraSingh’s picture

I am facing the same problem in my code. i have added unique id and tried all above given solutions but still unable the find out the solution.

When form rebuild the form actions gets changes into system/ajax action then no java script works.

orgnsm’s picture

Same with me, if anyone could take a look at my code and offer advice, I'd greatly appreciate it - http://drupal.org/node/2142355

ntg’s picture

Hi,
I had a similar issue with javascript not being executed after a form was reloading with Ajax.

As posted here https://drupal.org/node/1936178 the issue is: "Your code is using an abbreviation of jQuery.ready() which only works upon initial page load. What you need to use are Drupal's 'behavior' system, which is called after most ajax changes to the page".

Drupal.behaviors.myBehavior = {
  attach: function (context, settings) {

   //your code here

  }
};

I hope this helps.
Nik

michaelsilverman’s picture

I created a form where the user could add parent items via an "add more" submit button and then wanted the ability to add multiple child items for a specific parent via a second "add child" submit button. I could not get the child submit button to work until I added '#id' => $childId, at which points things started working as desired.

Thanks!

almaudoh’s picture

This was still very helpful after all these years. Thanks.

mahimajulka’s picture

Hi
I have a form altered to have a submit like this
$form['submit'] = array(
'#type' => 'submit',
'#ajax' => array(
'callback' => 'ajax_xxx_form_callback',
'wrapper' => 'xxx-form-wrapper',
'event' => 'submitmyform',
),
'#value' => t('Submit'),
);

This form is called in a block which is being rendered through ajax

My Drupal.settings.ajax looks like
edit-submit--3
Object { callback=[2], wrapper=[2], event=[2], more...}
callback -- ["ajax_xxx_form_callback", "ajax_xxx_form_callback"]
element -- input#edit-submit--3.form-submit.ajax-processed attribute value = "Submit"
event -- ["submitmyform", "submitmyform"]
selector -- "#edit-submit--3"
submit -- Object { _triggering_element_name=[2], _triggering_element_value=[2]}
url -- ["/system/ajax", "/system/ajax"]
wrapper -- ["xxx-form-wrapper", "xxx-form-wrapper"]

Now In my template file for this user-login form
I am using
var submitButtonpopup = jQuery("[id^='edit-submit']");
submitButtonpopup.trigger('submitmyform');

This never fires the form submission

Its like ajax is changing the callback and adding multiple callback and multiple events for this.
This works fine when the Block is added without ajax

jaypan’s picture

You probably need to call Drupal.attachBehaviors() after inserting your block into the page.

Contact me to contract me for D7 -> D10/11 migrations.

mahimajulka’s picture

Drupal.settings.ajax value
WITHOUT LOADING BLOCK AS AJAX
edit-submit--3
Object { callback="ajax_xxx_form_callback", wrapper="xxx-form-wrapper", event="submitmyform", more...}

WITH LOADING BLOCK AS AJAX
edit-submit--2
Object { callback=[2], wrapper=[2], event=[2], more...}
edit-submit--3
Object { callback="ajax_xxx_form_callback", wrapper="xxx-form-wrapper", event="submitmyform", more...}

I moved the
Drupal.behaviors.loginAjax code to inside this func $(document).ajaxStop(function() { --
Still the same issue

jaypan’s picture

Did you add Drupal.attachBehaviors()? I don't see this in your post.

Contact me to contract me for D7 -> D10/11 migrations.

mahimajulka’s picture

I have used the following code in page.footer.inc

<script>
(function ($) {
    $(document).ajaxStop(function() {
        Drupal.attachBehaviors(jQuery("#login-popup [id^='edit-submit']"));
        console.log('ajax is done');
    });  
}(jQuery));	

</script>

Again the same thing happens
The event "submitmyform" is not triggered using the JS code

var submitButtonpopup = jQuery("#login-popup [id^='edit-submit']");
submitButtonpopup.trigger('submitmyform'); 
jaypan’s picture

I'm sorry, I don't know this method you're using with $.ajaxStop() so I can't help much, but I can say that you should be using Drupal.attachBehaviors(), not Drupal.attachBehaviors(jQuery("#login-popup [id^='edit-submit']")). The way you have done it, attach behaviors will only be called on #login-popup [id^='edit-submit'], which isn't the element you want ajaxified.

If that doesn't work, I can't really help though, because I don't know this method you are using.

Contact me to contract me for D7 -> D10/11 migrations.

mahimajulka’s picture

The issue is that the Callback which was attached via form is not getting called as the event attached to that submit is not called
I tried calling Drupal.attachBehaviors() as well
After this call I can see that Drupal.behavior.MYMETHOD was triggered.
But what happens to the callback attached via form element ?

ps not the function I used is fired when all AJAX requests on the page end.
I had tried firing Drupal.attachBehaviors() in firebug console as well.
That also gives same response

Thanks for putting in this much effort anyways