web-dev-qa-db-ja.com

ajax呼び出しで複数の「フィールドコレクション」フィールドを作成(および事前入力)する方法

これは、この質問の拡張です-" ノード形式で複数の「フィールドコレクション」フィールドに事前入力する方法 "

私は同じことをやろうとしていますが、フォームの読み込みではなくajax呼び出しで機能するようにしています。

フォームが読み込まれ、ユーザーがドロップダウンのオプションを選択すると、フォームは自動的にいくつかのフィールドコレクションにajaxを入力します。

問題

上記の質問に対する既存の解​​決策は、フォームを最初に作成したときに、以下を変更することによってフォームを変更することです。

 $form_state['field']['--machine-name-of-field--'][LANGUAGE_NONE]['items_count']

そして、新しいフォーム状態値を使用してフォームを再構築します。

Ajax呼び出しの問題は、コールバックで$form_stateに加えられた変更を無視することです。つまり.

function ajax_get_parent_field_collection ($form, &$form_state) {
  $form_state['field']['field_collection_entity']['und']['items_count'] = '3';
  return $form['field_collection_entity'];
}

上記の$ form_stateで行われた変更は無視されるため、フォームが再構築されても何も起こらず、$form_stateをダンプしても、行われた変更は保存されません。

フィールドコレクションエンティティを手動で作成して挿入することはできましたが、より賢明な答えがあることを望んでいました。誰かが以前にこれに取り組みましたか?

編集:

現在、ajaxは選択フィールドで呼び出されているため、selectドロップダウンを使用すると、ajaxがトリガーされます。

$form['field_company_for_center']['und']['#ajax'] = array (
  'callback' => 'ajax_get_parent_field_collection',
  'wrapper' => 'ajax-wrapper',
  'effect' => 'fade',
);
3
Dominic Woodman

items_countを変更した後、フォームを再度ビルドする必要があります。

function MYMODULE_form_alter (&$form, &$form_state, $form_id) {
  if($form_id == 'MYFORM'){
    $form['#attributes']['id'] = 'MYMODULE-form-ajax-wrapper';

    // Handle triggered ajax element.
    if(!empty($form_state['triggering_element']['#array_parents'][0])) {
      if ($form_state['triggering_element']['#array_parents'][0] == 'field_node_reference') {
        $form_state['field']['field_collection_entity'][LANGUAGE_NONE]['items_count'] = '3';
      }
    }

    // Add ajax callback.
    $form['field_node_reference'][LANGUAGE_NONE]['#ajax'] = array (
      'callback' => 'MYMODULE_ajax_rebuild_form',
      'wrapper' => 'MYMODULE-form-ajax-wrapper',
    );
  }
}

/**
 * Ajax callback, rebuilds and returns the entire form.
 */
function MYMODULE_ajax_rebuild_form ($form, &$form_state) {
  return drupal_rebuild_form($form_state['build_info']['form_id'], $form_state, $form);
}
2
milkovsky

これについてmilkovskyと話し合ったときに思いついたいくつかの周囲の考えと事柄。問題は、フォームが正しく再構築されていないことに起因するようです。

上記のように、ajaxコールバックで$form_stateに加えられた変更は、すべてが返されると消去されるようです。

それが条件付きの理由です。 ajax呼び出しでは$form_stateに値を設定できないため、代わりにajax呼び出しが再作成された後にのみ実行されるhook_form_alterに条件を配置します。

しかし、drupal_rebuild_formを明示的に返すことにより、ajaxコールバックで$form_stateに加えられた変更が保存されているように見えます。

したがって、条件付きを削除して、コールバックを次のように変更できます。

function MYMODULE_ajax_rebuild_form ($form, &$form_state) {
  $form_state['field']['field_collection_entity'][LANGUAGE_NONE]['items_count'] = '3';
  return drupal_rebuild_form($form_state['build_info']['form_id'], $form_state, $form);
}

保存されていないため、ajaxコールバックで$form_state['rebuild'] = TRUEを設定することはできません(フォームが適切に再構築されないためです。皮肉なことに、これは達成しようとしていることです)。

$form_state['rebuild'] = TRUEを送信ハンドラに入れて、selectフィールドに送信を強制的に呼び出そうとした here が、それも機能しませんでした。

フォームにも事前入力しようとしている場合

デフォルトでは、ajaxはフォームのキャッシュバージョンをリロードするため、hook_form_alterにデフォルトで加えられた変更は、フォームがajaxによって再構築されるときに、$formに表示されても適用されません。印刷する。

キャッシュされていないフォームを強制するには、ajaxコールバックで$form_state['input']をワイプできます。

$form_state['input'] = array();

この解決策は AJAX submit の後にノードフォームをリセットする)からのものであり、その質問の詳細を確認できます。

うまくいけば、追加の説明が役立ちます。これ以上追加できる場合は、実行してください!

フィールドコレクションを読み込んで事前入力する2番目の方法

これを行うために2つ目の方法を見つけました(少なくとも私の状況では)1つ目よりも便利です。別のノードからフィールドコレクションを事前に設定しようとしています。これを行う別の方法は、偽のフォームインスタンスを作成し、それを元のフォームに接続することです。

メソッドはこのブログ投稿の最後の部分から来ました: http://drupal.cocomore.com/blog/field-collections-exposed

この例とブログの例の唯一の違いは、この例はajaxコールバックで偽のフォームを構築し、すべてのフィールドをループするのではなく、1つのフィールドのみを変更することです。

function ajax_get_parent_field_collection ($form, &$form_state) {
  //1. load parent node
  $parent_node = node_load($form_state['values']['field_node_reference'][LANGUAGE_NONE][0]['nid']);

  //prebuild fields
  $node_fields =  field_info_instances('node', 'field_collection_entity');

  //Re-create a fake form with all the trimmings which we can then attach
  //as a replacement.
  $tmpform = array();
  $tmpform['#node'] = $parent_node;
  $tmpform['type']['#value'] = 'node_type';
  $tmpform_state = array('build_info' => array('form_id' => $form['#form_id']) );
  field_attach_form('node', $parent_node, $tmpform, $tmpform_state, entity_language('node', $parent_node));

  //replace current form with our custom version
  $form['field_collection_entity'] = $tmpform['field_collection_entity'];
  $form_state['field']['field_collection_entity'] = $tmpform_state['field']['field_collection_entity'];
  $langcode = field_language('node', $parent_company, 'field_collection_entity');

  //iterate over the fields resetting the item and revision id so new
  //field collections are created rather than linking existing fc's
  $field_childs = &$form_state['field']['field_collection_entity'][$langcode]['entity'];
  foreach(element_children($field_childs) as $idx => $fc_entity) {
    $field_childs[$idx]->item_id = NULL;
    $field_childs[$idx]->revision_id = NULL;
  }

  //reset input to make sure cached version of the form isn't used
  $form_state['input'] = array();
  return drupal_rebuild_form($form_state['build_info']['form_id'], $form_state, $form);
}
2
Dominic Woodman