จะส่งฟอร์มเว็บโดยใช้โปรแกรม Ajax ได้อย่างไร


8

ฉันกำลังใช้งาน Ajax สำหรับ Webform submit บน Drupal 7. ฉันไม่สามารถหาสิ่งที่ดีhookในการเปลี่ยนปุ่มส่ง Webform และเพิ่ม '#ajax' ในแบบฟอร์มดังนั้นฉันจึงดูโมดูล Drupal 6ที่ ใช้ฟังก์ชันนี้จากสคริปต์ภายนอก

ดังนั้นฉันจึงตัดสินใจไปกับโมดูลและโค้ด JavaScript ของตัวเองเพื่อดำเนินการคำขอโพสต์ Ajax ไปยังการเรียกกลับเมนูที่กำหนดเองที่ฉันได้กำหนดไว้hook_menu()ใน Drupal 7

ส่วนของ 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 ครั้ง

ฉันเดาว่า API ของ D6 & D7 มีรูปแบบที่แตกต่างกันมากและฉันไม่แน่ใจว่าจะเริ่มใช้งานโค้ดนี้ได้ยังไง ฉันได้พยายามที่จะแก้ปัญหา แต่ฉันไม่สามารถหาสิ่งที่สร้างข้อผิดพลาด 500

ฉันใช้ webform 3 และโมดูลที่ฉันใช้รหัสก็ขึ้นอยู่กับรุ่นที่ 3 ของ webform แต่สำหรับ Drupal 6 แต่ทั้งสองโมดูลควรมีฟังก์ชั่นเดียวกันและฟังก์ชั่นแบบเดียวกัน วิธีแก้ปัญหาแรก: อาจมาจากค่าที่ฉันส่งผ่านซึ่งจะไม่สามารถทำงานร่วมกับฟอร์ม API D7 ได้

ในบันทึกของฉันฉันมี:

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 ความคิดใด ๆ

คำตอบ:


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 เพื่อให้คุณสามารถควบคุมข้อความสำเร็จจาก UI ของเว็บฟอร์ม


นี่เป็นสิ่งที่ดี แต่ฉันได้รับความล้มเหลว ($ form_state ['execute'] = False) และไม่มีสิ่งใดใน drupal_get_messages ('ข้อผิดพลาด') สงสัยว่าฉันจะแก้ไขข้อบกพร่องนี้ได้อย่างไร
cybertoast

ฉันควรชี้แจงว่าฉันกำลังพยายามส่งผ่าน curl เช่น curl -vvv -X POST -H "X-Requested- ด้วย: XMLHttpRequest" -d ส่งแล้ว [contact_fullname] = my% 20 ชื่อ & ส่ง [contact_email] = ทดสอบ% 40example คอม & ส่ง [contact_message] = ทดสอบ% 20message '" localhost / fubar / 31 " เนื้อหาได้รับการส่งและมีการเติม form_state แต่ drupal_form_build () ไม่ได้รับการดำเนินการ / ส่ง
cybertoast

-1

บอกฉันว่าฉันผิด แต่เนื่องจากการส่งฟอร์มเว็บเป็นโหนดทำไมไม่สร้างโหนดโดยตรงในรูปแบบของคุณpage callback(ด้วยการตรวจสอบฟิลด์ (หรือสามารถทำได้ก่อนส่งโดยใช้จาวาสคริปต์))

มันอาจเป็นอะไรก็ได้

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
จริงๆแล้วการส่งฟอร์มเว็บไม่ใช่โหนด Webform เก็บการส่งในตารางของตัวเอง ดังนั้นเราจึงไม่สามารถสร้างโหนดใหม่เพื่อเพิ่มการส่ง นอกจากนี้ฉันต้องการให้เวิร์กโฟลว์การตรวจสอบความถูกต้องของเว็บทั้งหมดถูกเรียกใช้เมื่อแบบฟอร์มถูกเรียกใช้เพื่อตรวจสอบฟิลด์ที่จำเป็น ฯลฯ ...
E. de Saint Chamas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.