it-swarm.it

Come inviare il modulo web a livello di codice con Ajax?

Sto lavorando su un'implementazione Ajax per l'invio di Webform su Drupal 7. Non sono stato in grado di trovare alcun buon hook per modificare il pulsante di invio Webform e aggiungere '#ajax 'nel modulo, quindi ho dato un'occhiata a un modulo Drupal 6 che implementa questa funzionalità da uno script esterno.

Così ho deciso di utilizzare il mio modulo e il mio codice JavaScript per inviare una richiesta di post Ajax a un callback di menu personalizzato che ho definito in hook_menu(), in Drupal 7.

La parte JavaScript funziona bene ma sto riscontrando problemi nel tentativo di inviare il modulo Web a livello di codice.

Ecco il mio codice 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
      }
    });
  }
}

E il mio codice del modulo (basato sul modulo 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;
}

Quando invio il modulo ricevo 500 errori del server.

Immagino che le API dei moduli D6 e D7 siano piuttosto diverse e non sono sicuro da dove iniziare a far funzionare questo pezzo di codice. Ho provato a eseguire il debug ma non riesco a capire cosa sta generando i 500 errori.

Uso webform 3 e il modulo che ho preso il codice si basa anche sulla versione 3 di webform ma per Drupal 6. Ma entrambi i moduli dovrebbero fornire le stesse funzioni e lo stesso tipo di funzionalità dietro. Prima soluzione : Potrebbe venire dai valori che passo che non sarebbero compatibili con D7 da API.

Nel mio registro ho:

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).

-- MODIFICARE --

Sto eseguendo il debug riga per riga ora, alla fine questo pezzo di codice potrebbe valere la pena di diventare un modulo D7;)

Ho trovato nella documentazione di D7 che drupal_rebuild_form () gli argomenti sono cambiati da D6 e che $form_state Non può più essere vuoto in questa fase, quindi ho aggiornato il mio codice in questo modo:

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

Ora sto cercando di trovare l'equivalente di drupal_execute (), che non esiste più in D7.

- Modifica (2) -

Ho funzionato qualche giorno fa e sono tornato per condividere la soluzione e forse ottenere alcuni consigli e suggerimenti di miglioramento.

<?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;
}

Per fare un ulteriore passo, vorrei ora ottenere gli errori dal modulo elaborato in modo da poterli rispedire indietro con l'oggetto json. Qualche idea ?

8

Stavo facendo qualcosa di simile e ho trovato la soluzione di E. de Saint Chamas per lavorare principalmente per me. Tuttavia, c'erano alcune cose che dovevo aggiungere:

Innanzitutto, ho dovuto aggiungere questo all'array form_state prima di elaborare il modulo

'method' => 'post',

Quindi, verso il basso, alcune modifiche per elaborare il modulo e restituire eventuali messaggi di errore:

  // 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'],
  ));

Non sono sicuro che sia il modo migliore per farlo, ma ho scoperto che ha funzionato per me. Naturalmente, potresti voler semplicemente andare avanti e visualizzare i messaggi di errore e restituire una finestra di messaggio di errore con rendering completo e, inoltre, potresti estrarre il "messaggio di conferma" dall'array $ form_state in modo da poter controllare il messaggio di successo dal interfaccia utente webform.

4
wesnick