web-dev-qa-db-fra.com

Comment soumettre un formulaire Web par programme avec Ajax?

Je travaille sur une implémentation Ajax pour la soumission Webform sur Drupal 7. Je n'ai pas pu trouver de bon hook pour modifier le bouton de soumission Webform et ajouter '#ajax 'sous la forme, j'ai donc jeté un œil à un module Drupal 6 qui implémente cette fonctionnalité à partir d'un script externe.

J'ai donc décidé d'utiliser mon propre module et mon code JavaScript pour lancer une demande de publication Ajax vers un rappel de menu personnalisé que j'ai défini dans hook_menu(), dans Drupal 7.

La partie JavaScript fonctionne bien, mais je rencontre des problèmes pour envoyer le formulaire Web par programme.

Voici mon code JavaScript:

function formSubmit(event, formId) {

  event.preventDefault();

  var form = jQuery("#" + formId);
  var postData = form.serialize();
  var nodeId = formId.substring(20);
  var msg = '';

  msg += form.find('#edit-submitted-name').attr('value') ? '' : 'Please enter your name';
  console.log(form.find('#edit-submitted-name').attr('value'));
  console.log(form.find('#edit-submitted-e-mail').attr('value'));

  if(msg) {
    alert(msg);
  } else {
    jQuery.ajax({
      url: Drupal.settings.basePath + 'webform_ajax/' + nodeId,
      fid:formId,
      type: 'POST',
      data: postData,
      success: function(ajaxData) {
        console.log(ajaxData);
        console.log('Hello world');
        // can't get here
      }
    });
  }
}

Et mon code de module (basé sur le module webform_ajax):

function custom_menu() {
  $items = array();
  $items['webform_ajax/%'] = array(
    'page callback' => '_custom_webform_ajax',
    'page arguments' => array(1,2),
    'access callback' => '_custom_webform_ajax_access',
  );
  return $items;
}

function _custom_webform_ajax($nid, $data) {
  //$sid = $_POST['details']['sid'];

  $local_POST = $_POST;
  $form_build_id = $_POST['form_build_id'];

  $form_id = 'webform_client_form_' . $nid;

  $node = node_load($nid);

  $submission = array();
  $form_state = array();

  $form = form_get_cache($form_build_id, $form_state);
  $form_array = drupal_rebuild_form($form_id, $form_state, array($form_state, $node, $submission), $form_build_id);
  $form_state['clicked_button'] = $form_array['actions']['submit'];

  if (is_array($local_POST['submitted'])) {
    foreach ($local_POST['submitted'] as $submit_index => $submit) {
      $form_state['storage']['submitted'][$submit_index] = $submit;
      $form_state['values']['submitted'][$submit_index] = $submit;
    }
  }

  // Clearing empty values from $form_state
  if (is_array($form_state['values']['submitted'])) {
    foreach ($form_state['values']['submitted'] as $value_index => $value) {
      if (!$value) {
        unset($form_state['values']['submitted'][$value_index]);
      }
    }
  }

  // Executing the pressed button action
  drupal_execute($form_id, $form_state, $node, array());

  // Get the HTML for the error messages
  $error_html = theme('status_messages', 'error');

  // Building the resulting form after the processing of the button
  $form_array = drupal_rebuild_form($form_id, $form_state, array($form_state, $node, $submission), $form_build_id);
  $form = drupal_render_form($form_id, $form_array);

  return drupal_json_output(array(
    'message' => $error_html,
    'status' => 'sent',
  ));

}

function _custom_webform_ajax_access() {
  // Todo: Add webform access conditions
  return true;
}

Lorsque je soumets mon formulaire, j'obtiens 500 erreurs de serveur.

Je suppose que les API de formulaire D6 et D7 sont assez différentes et je ne sais pas par où commencer pour que ce morceau de code fonctionne. J'ai essayé de le déboguer mais je n'arrive pas à comprendre ce qui génère les 500 erreurs.

J'utilise webform 3 et le module que j'ai pris le code repose également sur la version 3 de webform mais pour Drupal 6. Mais les deux modules devraient fournir les mêmes fonctions et le même type de fonctionnalités derrière. Première solution de contournement : Il peut provenir des valeurs que je passe qui ne seraient pas compatibles avec l'api de forme D7.

Dans mon journal, j'ai:

Argument 1 passed to drupal_array_nested_key_exists() must be an array, null given, called in D:\wamp\www\productionsite\includes\form.inc on line 1986 and defined in drupal_array_nested_key_exists() (line 6296 of D:\wamp\www\productionsite\includes\common.inc).

-- ÉDITER --

Je débogue ligne par ligne maintenant, à la fin ce morceau de code pourrait valoir la peine de devenir un module D7;)

J'ai trouvé dans la documentation de D7 que les arguments drupal_rebuild_form () ont changé par rapport à D6, et que $form_state Ne peut plus être vide à ce stade, j'ai donc mis à jour mon code de cette manière:

$form_state = array('submitted' => false, 'values' => array());
$form = form_get_cache($form_build_id, $form_state);
$form_array = drupal_rebuild_form($form_id, $form_state, $form);

Maintenant, j'essaie de trouver l'équivalent de drupal_execute (), qui n'existe plus en D7.

- Modifier (2) -

Je l'ai fait fonctionner il y a quelques jours et je reviens partager la solution, et peut-être obtenir des conseils et des suggestions d'améliorations.

<?php

function custom_menu() {
  $items = array();
  $items['webform_ajax/%'] = array(
    'page callback' => '_custom_webform_ajax',
    'page arguments' => array(1,2),
    'access callback' => '_custom_webform_ajax_access',
  );
  return $items;
}

function _custom_webform_ajax($nid, $data) {

  $local_POST = $_POST;
  $form_build_id = $_POST['form_build_id'];

  $form_id = 'webform_client_form_' . $nid;

  $node = node_load($nid);

  $submission = array();
  $form_state = array(
    'submitted' => false, 
    'values' => array(),
    'build_info' => array(
      'args' => array(
        $node,
        array(),
        FALSE
      )
    )
  );

  $form = form_get_cache($form_build_id, $form_state);
  $form_array = drupal_rebuild_form($form_id, $form_state);

  // Add the clicked button before processing the form
  $form_state['clicked_button'] = $form_array['actions']['submit'];

  if (is_array($local_POST['submitted'])) {
    foreach ($local_POST['submitted'] as $submit_index => $submit) {
      $form_state['values']['submitted'][$submit_index] = $submit;
    }
  }

  // Clearing empty values from $form_state
  if (is_array($form_state['values']['submitted'])) {
    foreach ($form_state['values']['submitted'] as $value_index => $value) {
      if (!$value) {
        unset($form_state['values']['submitted'][$value_index]);
      }
    }
  }

  $form_state['values']['details']['nid'] = $nid;

  // Executing the pressed button action
  drupal_build_form($form_id, $form_state);

  return drupal_json_output(array(
    'message' => t('Your submission has been received. Thank you for contacting us.'),
    'status' => 'sent',
  ));  

}

function _custom_webform_ajax_access() {
  // TODO: Add user role / perm check
  return true;
}

Pour aller plus loin, je voudrais maintenant obtenir les erreurs du formulaire traité afin que je puisse les renvoyer avec l'objet json. Des idées ?

8
E. de Saint Chamas

Je faisais quelque chose de similaire et j'ai trouvé la solution d'E. De Saint Chamas pour travailler principalement pour moi. Cependant, je devais ajouter quelques éléments:

Tout d'abord, j'ai dû l'ajouter au tableau form_state avant de traiter le formulaire

'method' => 'post',

Ensuite, vers le bas, quelques ajustements pour traiter le formulaire et renvoyer les messages d'erreur le cas échéant:

  // Prevent the form from redirecting the request
  $form_state['no_redirect'] = TRUE;
  // Executing the pressed button action
  drupal_build_form($form_id, $form_state);
  // See if the form submitted successfully
  if (!$form_state['executed']) {
    // If the form didn't submit successfully, get the errors
    // which are set bu drupal_set_message
    $messages = drupal_get_messages('error');
    $messages = implode('<br />', $messages['error']);
  }
  else {
    // If form submitted successfully, create a Nice message.
    $messages = "Thanks for contacting us! We will let you know when the Beta is live!";
  }
  // drupal_json_output seems to confuse some browsers, who want to save as a file 
  print drupal_json_encode(array(
    'message' => $messages,
    'status' => $form_state['executed'],
  ));

Je ne sais pas si c'est la meilleure façon de le faire, mais j'ai trouvé que cela fonctionnait pour moi. Bien sûr, vous souhaiterez peut-être simplement continuer et afficher les messages d'erreur et renvoyer une boîte de message d'erreur entièrement rendue.En outre, vous pouvez extraire le "message de confirmation" du tableau $ form_state afin de pouvoir contrôler le message de réussite à partir de la interface utilisateur du formulaire Web.

4
wesnick