如何使用Ajax以编程方式提交Webform?


8

我正在为Drupal 7上的Webform提交开发Ajax实现。我找不到hook改变Webform提交按钮并在表单中添加“ #ajax”的任何好处,因此我看了一下Drupal 6模块,从外部脚本实现此功能。

因此,我决定使用自己的模块和JavaScript代码向hook_menu()在Drupal 7中定义的自定义菜单回调发送Ajax发布请求。

JavaScript部分工作正常,但在尝试以编程方式提交Webform时遇到问题。

这是我的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
      }
    });
  }
}

和我的模块代码(基于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;
}

当我提交表格时,出现500个服务器错误。

我猜想D6和D7表单API完全不同,我不确定从哪里开始使这段代码起作用。我已经尝试调试它,但是我不知道是什么导致了500个错误。

我使用的是webform 3,而我使用代码的模块也依赖于webform的版本3,但对于Drupal6。但是,这两个模块在后面都应提供相同的功能和相同的功能。第一种解决方法:它可能来自我传递的与D7 form api不兼容的值。

在我的日志中,我有:

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

-编辑-

我现在正在逐行调试,最后这段代码值得成为D7模块;)

我在D7文档中发现drupal_rebuild_form()参数已从D6更改,并且$form_state在此阶段不能再为空,因此我以这种方式更新了代码:

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

现在,我试图找到等效的drupal_execute(),D7中不再存在。

-编辑(2)-

几天前我开始使用它,然后回来分享解决方案,也许还会得到一些建议和改进建议。

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

为了更进一步,我现在想从处理后的表单中获取错误,以便我可以将其与json对象一起发送回去。有任何想法吗 ?

Answers:


4

我在做类似的事情,发现E. de Saint Chamas的解决方案最适合我。但是,我需要添加一些内容:

首先,我必须在处理表单之前将其添加到form_state数组中

'method' => 'post',

然后,对底部进行一些调整,以处理表单并返回错误消息(如果有):

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

我不确定这是否是最好的方法,但是发现它对我有用。当然,您可能只想继续呈现错误消息并返回一个完全呈现的错误消息框,此外,您可以从$ form_state数组中选择“确认消息”,以便可以从$ form_state数组中控制成功消息。网络表单用户界面。


很好,但是我一直失败($ form_state ['executed'] = False)。而且drupal_get_messages('error')中没有任何内容。想知道我该如何调试。
cybertoast 2012年

我应该澄清一下,我正在尝试通过curl提交,例如curl -vvv -X POST -H“ X-Requested-With:XMLHttpRequest” -d'submitted [contact_fullname] = my%20name&submitted [contact_email] = test%40example。 com&submitted [contact_message] = test%20message'“ localhost / fubar / 31 ”。将发送内容并填充form_state,但不会执行/提交drupal_form_build()。
cybertoast 2012年

-1

告诉我我是否错,但是由于Webform提交是一个节点,为什么不以编程方式直接在您的节点中创建该节点page callback(使用字段验证(或可以在使用javascript提交之前进行))

可能是这样的

if(!function_exists("node_object_prepare"))
{
  include_once(drupal_get_path('module', 'node') . '/node.pages.inc');
}
$node = new stdClass();                                                         
$node->is_new = TRUE;
$node->type = 'YOUR_NODE_TYPE_HERE';                                
node_object_prepare($node);

// then all the fields you need

node_validate($node);
$node = node_submit($node);
node_save($node);
$nid = $node->nid;

等等!:)


3
实际上,Web表单提交不是节点。Webform将提交内容存储在其自己的表中。因此,我们无法创建新节点来添加提交。而且我想拥有整个网络表单验证一旦执行形式,因此会检查所需的字段的工作流程被触发,等等
E.德圣沙马
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.