Làm cách nào để gửi biểu mẫu web theo chương trình với Ajax?


8

Tôi đang làm việc trên một thực hiện Ajax cho Webform nộp trên Drupal 7. Tôi đã không thể tìm thấy bất kỳ tốt hookđể thay đổi nút Webform nộp và thêm '#ajax' theo hình thức do đó, tôi đã có một cái nhìn vào một mô-đun Drupal 6 mà thực hiện chức năng này từ một tập lệnh bên ngoài.

Vì vậy, tôi đã quyết định sử dụng mô-đun và mã JavaScript của riêng mình để gửi yêu cầu bài đăng Ajax tới một cuộc gọi lại menu tùy chỉnh mà tôi đã xác định trong hook_menu(), trong Drupal 7.

Phần JavaScript hoạt động tốt nhưng tôi gặp sự cố khi gửi Webform theo chương trình.

Đây là mã JavaScript của tôi:

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

Và mã mô-đun của tôi (dựa trên mô-đun 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;
}

Khi tôi gửi biểu mẫu của mình, tôi nhận được 500 lỗi máy chủ.

Tôi đoán API biểu mẫu D6 & D7 khá khác nhau và tôi không chắc bắt đầu từ đâu để đoạn mã này hoạt động. Tôi đã cố gắng gỡ lỗi nhưng tôi không thể tìm ra cái gì tạo ra 500 lỗi.

Tôi sử dụng webform 3 và mô-đun tôi lấy mã cũng dựa trên phiên bản 3 của webform nhưng đối với Drupal 6. Nhưng cả hai mô-đun nên cung cấp cùng chức năng và cùng loại chức năng phía sau. Giải pháp đầu tiên: Nó có thể đến từ các giá trị tôi vượt qua sẽ không tương thích với api mẫu D7.

Trong nhật ký của tôi, tôi có:

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

-- BIÊN TẬP --

Bây giờ tôi đang gỡ lỗi từng dòng, cuối cùng đoạn mã này có thể xứng đáng để trở thành mô-đun D7;)

Tôi đã tìm thấy trong tài liệu D7 rằng các đối số drupal numbuild_form () đã thay đổi từ D6 và $form_statekhông thể để trống nữa ở giai đoạn này, vì vậy tôi đã cập nhật mã của mình theo cách này:

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

Bây giờ tôi đang cố gắng tìm tương đương với drupal_execute (), không còn tồn tại trong D7 nữa.

- Chỉnh sửa (2) -

Tôi đã làm cho nó hoạt động vài ngày trước và quay lại để chia sẻ giải pháp, và có thể nhận được một số lời khuyên và đề xuất cải tiến.

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

Để tiến thêm một bước tôi muốn bây giờ nhận lỗi từ biểu mẫu đã xử lý để tôi có thể gửi lại với đối tượng json. Có ý kiến ​​gì không?

Câu trả lời:


4

Tôi đã làm một cái gì đó tương tự và tìm thấy giải pháp của E. de Saint Chamas chủ yếu làm việc cho tôi. Tuy nhiên, có một vài điều mà tôi cần thêm:

Đầu tiên, tôi phải thêm phần này vào mảng form_state trước khi xử lý biểu mẫu

'method' => 'post',

Sau đó, về phía dưới, một số điều chỉnh để xử lý biểu mẫu và trả về thông báo lỗi nếu có:

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

Tôi không chắc đây có phải là cách tốt nhất để làm hay không, nhưng thấy nó hiệu quả với tôi. Tất nhiên, bạn có thể muốn tiếp tục và hiển thị các thông báo lỗi và trả lại hộp thông báo lỗi được hiển thị đầy đủ và ngoài ra, bạn có thể lấy "thông báo xác nhận" từ mảng $ form_state để bạn có thể kiểm soát thông báo thành công từ giao diện người dùng web.


Điều này thật tuyệt, nhưng tôi cứ bị lỗi ($ form_state ['exec'] = false). Và không có gì trong drupal_get_messages ('lỗi'). Tự hỏi làm thế nào tôi có thể gỡ lỗi này.
gian mạng

Tôi nên làm rõ rằng tôi đang cố gắng gửi qua curl, như curl -vvv -X POST -H "X-Requested-With: XMLHttpRequest" -d 'đã gửi [contact_fullname] = %% 20name của tôi và đã gửi [contact_email] = test% 40example. com & đã gửi [contact_message] = test% 20message '" localhost / fubar / 31 ". Nội dung được gửi và form_state được điền, nhưng drupal_form_build () không được thực thi / gửi.
gian mạng

-1

Hãy cho tôi biết nếu tôi sai nhưng vì việc gửi biểu mẫu web là một nút, tại sao không trực tiếp tạo nút theo chương trình trong page callback(với xác thực trường (hoặc có thể làm trước khi gửi bằng javascript))

Nó có thể là một cái gì đó như

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;

Et voilà! :)


3
Trên thực tế đệ trình webform không phải là nút. Webform lưu các bài nộp trong bảng riêng của mình. Vì vậy, chúng tôi không thể có một nút mới được tạo để thêm trình. Ngoài ra, tôi muốn có toàn bộ quy trình xác thực biểu mẫu web được kích hoạt sau khi biểu mẫu được thực thi để nó kiểm tra các trường bắt buộc, v.v ...
E. de Saint Chamas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.