AJAX form validate and submit
Asked Answered
E

6

13

I created a form in Drupal 7 and want to use AJAX. I added this to the submit button array:

"#ajax" => array(
  "callback" => "my_callback",
  "wrapper" => "details-container",
  "effect" => "fade"
)

This works but the whole validation function is ignored. How can I validate the form before my_callback() is called? And how can I display the status or error messages on a AJAX form?

Eliaseliason answered 26/10, 2011 at 13:11 Comment(4)
Are you positive validation is being ignored? I've done this dozens of times and the validation has never, ever been ignored (unless I have specifically told Drupal to ignore them using #limit_validation_errors). Also the error messages are automatically loaded into the wrapper element by default so once you've got the first bit fixed it should just fall right into place. Could you post some more of your code?Illuminati
@Illuminati I just made another test form, same results. Here's the form: function dr_search_test_form($form, &$fstate) { $form["wrapper"] = array( "#markup" => "<div id='test-ajax'></div>" ); $form["name"] = array( "#type" => "textfield", "#required" => true, "#title" => "Name" ); $form["submit"] = array( "#type" => "submit", "#value" => "Send", "#ajax" => array( "callback" => "dr_search_test_form_callback", "wrapper" => "test-ajax", "effect" => "fade" ) ); return $form; }Eliaseliason
function dr_search_test_form_callback($form, &$fstate) { return "sadsadas"; } function dr_search_test_form_validate($form, &$fstate) { form_set_error("name", "Some error to display."); }Eliaseliason
I just see the text from the callback function "sadsadas" but no validation takes place....Eliaseliason
E
7

Ok, I figure it out. Apparently you should return an array on your ajax callback function, not just a text message...

Something like this:

return array("#markup" => "<div id='wrapper'></div>");
Eliaseliason answered 27/10, 2011 at 8:6 Comment(0)
A
20

This question and answer helped guide me to the right solution, but it isn't exactly crystal clear. Let's make it so.

Things to be very aware of:

  1. Validation error messages will be placed inside whatever is specified as the #ajax['wrapper']
  2. Pay close attention to where the Drupal Forms API documentation of the ajax wrapper says that "the entire element with this ID is replaced, not just the contents of the element."
  3. Because that element is replaced, you had better provide it again. That is why Marius Ilie's answer works - not because of the array and #markup, but rather because he is including the div with the wrapper id set.

Here is code that was working for me based off what Marius put in the comment above:

function dr_search_test_form($form, &$fstate) {
  $form["wrapper"] = array("#markup" => "<div id='test-ajax'></div>");

  $form["name"] = array(
    "#type" => "textfield",
    "#required" => true,
    "#title" => "Name"
  );

  $form["submit"] = array(
    "#type" => "submit",
    "#value" => t("Send"),
    "#ajax" => array(
      "callback" => "dr_search_test_form_callback",
      "wrapper" => "test-ajax",
      "effect" => "fade",
    ),
  );
  return $form;
}

function dr_search_test_form_callback($form, &$fstate) {
  return "<div id='test-ajax'>Wrapper Div</div>";
}

function dr_search_test_form_validate($form, &$fstate) {
  form_set_error("name", "Some error to display.");
}
Amelina answered 28/6, 2012 at 2:54 Comment(2)
+1 for sharing your experience way after the question closed; this is true community Q&A.Quern
Working fine. How to clear form values after submit ?Franco
W
10

I found an excellent solution to this problem.

Credit goes to this guy's blog:

http://saw.tl/validate-form-ajax-submit-callback

The solution he proposes is the following:

// when creating or altering the form..
{
  $form['#prefix'] = '<div id="formwrapper">';
  $form['#suffix'] = '</div>';
  // the submit button
  $form['save']['#ajax'] = array(
    'callback' => 'mymodule_form_ajax_submit',
    'wrapper' => 'formwrapper',
    'method' => 'replace',
    'effect' => 'fade',
  );
 // ...
}

function mymodule_from_ajax_submit($form, &$form_state) {
  // validate the form
  drupal_validate_form('mymodule_form_id', $form, $form_state);
  // if there are errors, return the form to display the error messages
  if (form_get_errors()) {
    $form_state['rebuild'] = TRUE;
    return $form;
  }
  // process the form
  mymodule_form_id_submit($form, $form_state);
  $output = array(
    '#markup' => 'Form submitted.'
  );
  // return the confirmation message
  return $output;
}
Wadmal answered 6/3, 2014 at 13:46 Comment(2)
$form['#prefix'] and $form['#suffix'] do not work in my _form_alter hook.Delamare
@Delamare It should apply to any element of a form, including the form itself. Checkout the Form API ReferenceWadmal
N
9

None of this works for me. The form submit's ajax function still just calls the callback function directly, bypassing validation, submit, and also making it so the button cannot be clicked multiple times. The validation messages do NOT get displayed. I literally copied and pasted Joshua Stewardson code and it did not work.

The fact that this usage case is so hard and undocumented is very upsetting. To me, this seems like the most basic of requests for an AJAX form API. Okay, done venting my frustration, onto the solution.

Here's what I ended up doing to get this to work. It feels wrong. It will also break if there are multiple instances of the form on a single page, but it was the best I could do. If anyone can shed light on this, PLEASE do!

Basically, you have to replace the whole form with itself inside your callback, and manually prepend any set messages to the form object. Do this by declaring the wrapper to be the id of your form (it will break if there are multiple instances of your form on a single page, because the ID will be updated).

function productsearchbar_savesearch_form($form, &$form_state) {

  $form["wrapper"] = array("#markup" => "<div class='inline-messages'></div>");

  $form["name"] = array(
    "#type" => "textfield", 
    "#required" => true,
    "#title" => "Name"
  );
    
  $form["submit"] = array(
    "#type" => "submit", 
    "#value" => "Send", 
    "#ajax" => array(
      "callback" => "productsearchbar_savesearch_form_callback", 
      "wrapper" => "productsearchbar-savesearch-form", 
      "effect" => "fade"
    )
  );

  return $form;
}

function productsearchbar_savesearch_form_callback($form, &$form_state) {
  $messages = theme('status_messages');

  if($messages){
    $form["wrapper"] = array("#markup" => "<div class='inline-messages'>$messages</div>");
  }
  return $form;
}

function productsearchbar_savesearch_form_validate($form, &$form_state) {
  if ($form_state['values']['name'] == '') {
   form_set_error('', t('Name field is empty!'));
  }
}

function productsearchbar_savesearch_form_submit($form, &$form_state) {
  drupal_set_message(t('Your form has been saved.'));
}
Needy answered 11/12, 2012 at 16:5 Comment(1)
I am experiencing the opposite, the Ajax callback gets triggered and then the form submit function is called and the message in the submit handler is coming back with the Ajax response saying it was saved. Which is not what I want to happen. Since this one triggers a batch operation. This is Drupal 7 if it matters.Staw
E
7

Ok, I figure it out. Apparently you should return an array on your ajax callback function, not just a text message...

Something like this:

return array("#markup" => "<div id='wrapper'></div>");
Eliaseliason answered 27/10, 2011 at 8:6 Comment(0)
A
0

I searched many hours for a way to do this properly. Unfortunately, most of these solutions still rely on Drupal's server side validation to determine whether the ajax results or the client side error messages should be placed in the wrapper. Relying on the server result is slower than client side validation, which should be virtually instantaneous. Also, replacing the form...with a form...with the error messages is a bit too messy for my preference.

Use jquery validation's methods to trigger an ajax event with a javascript trigger:

// Prevent form submission when there are client-side errors, trigger ajax event when it is valid
(function ($) {
    Drupal.behaviors.submitForm = { 
        attach: function (context) {
            var $form = $("form#validated_form", context);
            var $submitButton = $('input[type="submit"]', $form);

            $form
                .once('submitForm')
                .off('submit')
                .on('submit', function(e){

                    // Prevent normal form submission
                    e.preventDefault();
                    var $form = $(this);

                    // The trigger value should match what you have in your $form['submit'] array's ajax array
                    //if the form is valid, trigger the ajax event
                    if($form.valid()) {
                        $submitButton.trigger('submit_form');
                    }
            });

        }
    };
})(jQuery);

Reference the javascript trigger as your ajax event that is listened for:

$form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
    '#ajax' => array(
      'event' => 'submit_form',
      'callback' => 'callback_function_for_when_form_is_valid',
      'wrapper' => 'validated_form'
    )
);

Now, the validation is triggered as soon as the submit button is clicked, and the server side validation only happens once it's valid!

Ambi answered 13/1, 2015 at 4:38 Comment(0)
A
-1

//you can use jquery form validation

jQuery('#button-id').mousedown(function() {
  var textval = $("#get-text-val").val();
  if (textval == '') {
    $("#apend-error-msg").append('<div id="add-text-error" class="add-text-error">error msg</div>');
   return false;
  }
  else {
    return true;
  }
  return false;
 });
Armbrecht answered 29/10, 2013 at 5:57 Comment(1)
Going outside of Drupal for validation can serve to be problematic when you want to check more than string length.Delinquent

© 2022 - 2024 — McMap. All rights reserved.