web-dev-qa-db-fra.com

AJAX formulaire valider et envoyer

J'ai créé un formulaire dans Drupal 7 et je souhaite utiliser AJAX. J'ai ajouté ceci au tableau des boutons d'envoi:

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

Cela fonctionne mais la fonction de validation entière est ignorée. Comment puis-je valider le formulaire avant que my_callback() soit appelé? Et comment puis-je afficher les messages d'état ou d'erreur sur un formulaire AJAX?

13
Marius Ilie

Ok, j'ai compris. Apparemment, vous devriez retourner un tableau sur votre fonction de rappel ajax, pas seulement un message texte ...

Quelque chose comme ça:

return array("#markup" => "<div id='wrapper'></div>");
7
Marius Ilie

Cette question et cette réponse m'ont aidé à trouver la bonne solution, mais ce n'est pas tout à fait clair. Faisons-le.

Les choses à connaître très:

  1. Les messages d'erreur de validation seront placés à l'intérieur de tout ce qui est spécifié en tant que #ajax['wrapper']
  2. Portez une attention particulière à l'endroit où la documentation de l'API Drupal Forms de l'encapsuleur ajax indique que "l'élément entier portant cet ID est remplacé, pas seulement le contenu de l'élément." 
  3. Parce que cet élément est remplacé, vous feriez mieux de le fournir à nouveau. That est la raison pour laquelle la réponse de Marius Ilie fonctionne - non pas à cause du tableau et de #markup, mais plutôt parce qu'il inclut la div avec le jeu d'id de wrapper.

Voici le code qui fonctionnait pour moi basé sur ce que Marius a mis dans le commentaire ci-dessus:

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.");
}
17
Joshua Stewardson

J'ai trouvé une excellente solution à ce problème.

Le crédit va au blog de ce type:

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

La solution qu'il propose est la suivante:

// 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;
}
10
bmunslow

Rien de tout cela ne fonctionne pour moi. La fonction ajax du formulaire de soumission appelle toujours la fonction de rappel directement, en ignorant la validation, la soumission et en faisant en sorte que le bouton ne puisse pas être cliqué plusieurs fois. Les messages de validation ne sont pas affichés. J'ai littéralement copié et collé du code Joshua Stewardson et cela n'a pas fonctionné.

Le fait que cette utilisation soit si difficile et sans papiers est très troublant. Pour moi, cela semble être la requête la plus élémentaire pour une API de formulaire AJAX. Ok, j'ai fini par évacuer ma frustration vers la solution.

Voici ce que j'ai fini par faire pour que cela fonctionne. Il se sent hacky et attardé. Cela se cassera également s'il y a plusieurs instances du formulaire sur une seule page, mais c'était le mieux que je pouvais faire. Si quelqu'un peut nous éclairer, VEUILLEZ le faire!

Fondamentalement, vous devez remplacer le formulaire entier par lui-même dans votre rappel et ajouter manuellement tous les messages définis à l'objet de formulaire. Pour ce faire, déclarez le wrapper comme étant l'identifiant de votre formulaire (il se brisera s'il existe plusieurs instances de votre formulaire sur une seule page, car l'identifiant sera mis à jour). 

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.'));
}
9
Brent Hartmann

J'ai cherché plusieurs heures pour trouver un moyen de le faire correctement. Malheureusement, la plupart de ces solutions reposent toujours sur la validation côté serveur de Drupal pour déterminer si les résultats ajax ou les messages d'erreur côté client doivent être placés dans le wrapper. S'appuyer sur le résultat du serveur est plus lent que la validation côté client, qui devrait être pratiquement instantanée. Aussi, remplacer le formulaire ... par un formulaire ... par les messages d'erreur est un peu trop compliqué à mon goût.

Utilisez les méthodes de validation de jquery pour déclencher un événement ajax avec un déclencheur javascript:

// 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);

Référencez le déclencheur javascript comme votre événement ajax écouté pour:

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

Désormais, la validation est déclenchée dès que l'utilisateur clique sur le bouton d'envoi et la validation côté serveur n'a lieu que lorsqu'elle est valide!

0
CLL