手短に:
Drupal フォームで AJAX コールバックが実行されるように、jQuery を介して外部イベントをトリガーしようとしています。これにより、いくつかの連鎖要素が再構築されます。一度機能しますが、Drupal の別の要素によってフォームが更新されるまで機能しません。
form_state は、最初の試行でトリガーされた要素として適切な要素を検出しますが、その後は form_state['buttons'] 配列で最初に使用可能なボタンにデフォルト設定されます。何かご意見は?
詳細に:
次のような複雑な Drupal フォームがあります。
A (ドロップダウン)
B (実際には B_key と B_literal、2 つのテキスト フィールド) C (ドロップダウン) D (ドロップダウン) E (ドロップダウン)
A が B を更新し、B が C を更新し、C が D を更新するなどです。B を除いて、これらはそれぞれドロップダウン要素です。各項目はキー => 値のペアであり、キーを使用して更新する要素のオプションを再構築します。したがって、C のキーが D のオプションに使用されるため、B のキーは C のオプションを更新します。
これらは完全に Drupal AJAX コールバックとして構築され、適切に動作します。ただし、B は選択ではなく、2 つの別個のテキスト フィールド、1 つはキー、1 つはリテラルです。これは、リストのサイズが大きすぎて select 要素を使用できないため、B の AJAX オートコンプリート ルックアップを実行できるようにするためです。
このルックアップを実行し、これら 2 つのフィールド (B_key と B_literal) にデータを入力する外部 jQuery スクリプトを作成しました。それらを入力したら、フィールドの 'ajax' => 'event' => 'hs_changed' によって参照されるカスタム イベントをトリガーします。これは、jQuery('[name=b_literal]').trigger を使用して jQuery で手動でトリガーします。 (). これは私がこれを初めて実行したときに機能し、C が新しいオプション セットで再構築されます。
ただし、これが一度発生すると、再構築されなくなります。form_state を調べたところ、B の新しい値を選択すると、フォームの状態がボタン (form_state['buttons'] 配列の最初のボタン) がクリックされたと認識し、これが失敗することに気付きました。
ここで、A をリロードすると、通常は B の値があらかじめ設定されているため、すべての子フィールド (B、C、D、E) が適切に更新されます。これが発生したら、もう一度 B を手動で選択できます。もう一度試してみると失敗する前に、一度書かれたとおりに機能します。私のjQueryにはバインディングの問題がないことに注意してください。これは、Bのフィールドを見つけて値を更新できるためです。最初のトリガーの後に毎回失敗するカスタムイベントを手動でトリガーしています(drupalフィールドのajaxをトリガーします)。
コードは次のとおりです。
フォーム:
$form['a'] = array (
'#type' => 'select',
'#options' => $a_options,
'#default_value' => $a_selected,
'#required' => TRUE,
'#prefix' => '<div id="a_wrapper">',
'#suffix' => '</div>',
'#ajax' => array(
'callback' => 'a_ajax_callback',
'method' => 'replace',
'effect' => 'fade',
),
);
$form['b_key'] = array (
'#type' => 'textfield',
'#default_value' => $hierarchy['b_key'],
);
$form['b_literal'] = array (
'#type' => 'textfield',
'#default_value' => $hierarchy['b_literal'],
'#size' => 32,
'#required' => TRUE,
'#ajax' => array(
'callback' => 'b_ajax_callback',
'method' => 'replace',
'effect' => 'fade',
'event' => 'hs_changed',
),
'#prefix' => '<div id="b_wrapper">',
'#suffix' => '</div>',
);
$form['c'] = array (
'#type' => 'select',
'#default_value' => $hierarchy['c'],
'#empty_option' => '- Select -',
'#options' => get_children_options_array($hierarchy['b_key'], TRUE),
'#ajax' => array(
'callback' => 'c_ajax_callback',
'method' => 'replace',
'effect' => 'fade',
),
'#required' => TRUE,
'#prefix' => '<div id="c_wrapper">',
'#suffix' => '</div>',
);
//Assume D and E are identical to C
コールバック:
function a_ajax_callback($form, &$form_state) {
//Return the field to be rebuilt by the AJAX request $commands = array();
$commands[] = ajax_command_replace("#b_key_wrapper", render($form['b_key']));
$commands[] = ajax_command_replace("#b_literal_wrapper", render($form['b_literal']));
//We also unset a bunch of form_state['input'] values and such here
return array('#type' => 'ajax', '#commands' => $commands);
}
//The b_ajax_callback and c_ajax_callback are pretty much identical
jQuery:
jQuery(document).on("focus", '[name=my_search]:not(.ui-autocomplete-input)', function() {
jQuery(this).autocomplete({
source: function(req, res) {
ch_search(req, res);
},
minLength: 3,
select: function(event, ui) {
ch_render_dropdowns(ui.item.id);
}
});
});
function ch_render_dropdowns(ch_node) {
var token = jQuery('[name=ajax_token]').val();
jQuery.ajax({
url: '/ajax/myFunction/' + ch_node
async: false,
cache: false,
data: {
'token': token
},
success: function(data) {
jQuery('#autoComplete_logic').html(data);
jQuery('#autoComplete_logic').hide();
// Once we have the initial results, fill in the d7 form fields
// where we have values.
var b_key = jQuery("#b_key").val();
var b_name = jQuery("#b_literal").text();
// Set our Drupal B Fields
jQuery('[name=b_key]').val(b_key);
jQuery('[name=b_literal]').val(b_name);
//Trigger the refresh of all submenus in Drupal
//This triggers the AJAX callback attached to the b_literal
//to rebuild c, d, and e.
jQuery('[name=b]').trigger('hs_changed');
}
});
}
この問題の範囲外に多くのロジックがあるため、すべてを単純化しました。オートコンプリートは問題ではありません。b_literal フィールドにアタッチされた Drupal AJAX をアクティブ化して c、d、e のリフレッシュを引き起こすことは、Drupal のフォーム API を介して b、c、d、および e を内部的にリフレッシュするフィールド a をヒットしない限り、最初の時間以降は機能しません。 AJAX ロジック。
Form_state (初回は適切に実行):
[トリガー要素] => Array ( [#type] => textfield [#title] => B [#description] => [#default_value] => [#size] => 32 [#maxlength] => 255 [#required ] => 1 [#disabled] => [#ajax] => Array ( [callback] => b_ajax_callback [method] => replace [effect] => fade [event] => hs_changed )
[#prefix] => <div id="b_literal_wrapper">
[#suffix] => </div>
[#input] => 1
[#autocomplete_path] =>
[#process] => Array
(
[0] => ajax_process_form
)
[#theme] => textfield
[#theme_wrappers] => Array
(
[0] => form_element
)
[#pre_render] => Array
(
[0] => ctools_dependent_pre_render
)
[#defaults_loaded] => 1
[#tree] =>
[#parents] => Array
(
[0] => b
)
[#array_parents] => Array
(
[0] => b
)
[#weight] => 0.002
[#processed] =>
[#attributes] => Array
(
)
[#title_display] => before
[#id] => edit-b--4
[#name] => b_literal
[#value] =>
[#needs_validation] => 1
)
Form_state (2 回目以降は毎回不適切に実行されます):
[triggering_element] => Array
(
[#type] => submit
[#value] => Submit
[#weight] => 100
[#attributes] => Array
(
[class] => Array
(
[0] => btn
[1] => btn-primary
)
)
[#after_build] => Array
(
[0] => _load_assets_b_select
)
[#input] => 1
[#name] => op
[#button_type] => submit
[#executes_submit_callback] => 1
[#limit_validation_errors] =>
[#process] => Array
(
[0] => ajax_process_form
)
[#theme_wrappers] => Array
(
[0] => button
)
[#defaults_loaded] => 1
[#tree] =>
[#parents] => Array
(
[0] => submit
)
[#array_parents] => Array
(
[0] => submit
)
[#processed] =>
[#required] =>
[#title_display] => before
[#id] => edit-submit--2
)
[clicked_button] => Array
(
[#type] => submit
[#value] => Submit
[#suffix] => </div></section>
[#weight] => 100
[#attributes] => Array
(
[class] => Array
(
[0] => btn
[1] => btn-primary
)
)
[#after_build] => Array
(
[0] => _load_assets_b_select
)
[#input] => 1
[#name] => op
[#button_type] => submit
[#executes_submit_callback] => 1
[#limit_validation_errors] =>
[#process] => Array
(
[0] => ajax_process_form
)
[#theme_wrappers] => Array
(
[0] => button
)
[#defaults_loaded] => 1
[#tree] =>
[#parents] => Array
(
[0] => submit
)
[#array_parents] => Array
(
[0] => submit
)
[#processed] =>
[#required] =>
[#title_display] => before
[#id] => edit-submit--2
)