Estoy trabajando en una implementación de Ajax para el envío del formulario web en Drupal 7. No pude encontrar nada bueno hook
para alterar el botón de envío del formulario web y agregar '#ajax' en el formulario, así que eché un vistazo a un módulo Drupal 6 que implementa esta funcionalidad desde un script externo.
Así que decidí ir con mi propio módulo y código JavaScript para enviar una solicitud de publicación de Ajax a una devolución de llamada de menú personalizada que he definido hook_menu()
en Drupal 7.
La parte de JavaScript funciona bien, pero tengo problemas para enviar el formulario web mediante programación.
Aquí está mi código 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
}
});
}
}
Y mi código de módulo (basado en el módulo 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;
}
Cuando envío mi formulario obtengo 500 errores de servidor.
Supongo que las API de formularios D6 y D7 son bastante diferentes y no estoy seguro de dónde comenzar a tener este código funcionando. He intentado depurarlo, pero no puedo entender qué genera los 500 errores.
Uso webform 3 y el módulo que tomé el código también se basa en la versión 3 de webform pero para Drupal 6. Pero ambos módulos deben proporcionar las mismas funciones y el mismo tipo de funcionalidades. Primera solución: puede provenir de los valores que paso que no serían compatibles con la api del formulario D7.
En mi registro tengo:
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).
- EDITAR -
Estoy depurando línea por línea ahora, al final este código podría valer la pena convertirse en un módulo D7;)
En la documentación de D7 encontré que los argumentos drupal_rebuild_form () han cambiado de D6, y que $form_state
ya no pueden estar vacíos en esta etapa, así que actualicé mi código de esta manera:
$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);
Ahora estoy tratando de encontrar el equivalente de drupal_execute (), que ya no existe en D7.
- Editar (2) -
Lo hice funcionar hace unos días y vuelvo para compartir la solución, y tal vez obtener algunos consejos y sugerencias de mejoras.
<?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;
}
Para ir un paso más allá, me gustaría obtener ahora los errores del formulario procesado para poder enviarlos de regreso con el objeto json. Algunas ideas ?
Dígame si estoy equivocado, pero dado que el envío de un formulario web es un nodo, ¿por qué no crear directamente el nodo mediante programación
page callback
(con validación de campo (o podría hacerlo antes de enviar usando JavaScript))Podría ser algo como
Et voilà! :)
fuente