web-dev-qa-db-ja.com

Ajaxを使用してプログラムでWebフォームを送信する方法は?

Drupal 7.のWebform submitのAjax実装に取り​​組んでいます。Webformの送信ボタンを変更して '#ajaxを追加するための適切なhookが見つかりません'という形で、外部スクリプトからこの機能を実装する Drupal 6モジュール を調べました。

したがって、私は独自のモジュールとJavaScriptコードを使用して、hook_menu()、Drupal 7.で定義したカスタムメニューコールバックにAjax投稿リクエストを発行することにしました。

JavaScriptの部分は正常に機能しますが、プログラムでWebフォームを送信しようとすると問題が発生します。

これが私の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を使用しており、コードを取得したモジュールもバージョン3のwebformに依存していますが、Drupal 6。 :これは、D7フォーム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).

-編集-

私は今、1行ずつデバッグしています。最後に、このコードは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);
_

現在、D7には存在しないdrupal_execute()に相当するものを見つけようとしています。

-編集(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オブジェクトでエラーを送り返すことができるようにしたいと思います。何か案は ?

8

私は同じようなことをしていて、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配列から「確認メッセージ」を取得して、 webform UI。

4
wesnick