Reputation: 3323
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?
Upvotes: 13
Views: 39263
Reputation: 91
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.'));
}
Upvotes: 9
Reputation: 874
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:
#ajax['wrapper']
#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.");
}
Upvotes: 20
Reputation: 1342
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!
Upvotes: 0
Reputation: 370
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;
}
Upvotes: 10
Reputation: 17
//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;
});
Upvotes: -1
Reputation: 3323
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>");
Upvotes: 7