DrupalのForm APIで #ajaxというプロパティがありそれについてのご紹介をしたいと思います。

#ajaxプロパティとは

例えば、セレクトボックスの選択状態によって、別のセレクトボックスの選択値を切り替える場合
通常であればJavaScriptを実装し、表示内容を変更する対応を行うと思います。

Drupalの場合、この #ajax プロパティにコールバック関数を指定すると、DrupalがJavaScriptを生成し
バックエンドで指定したコールバック関数を実行することが可能になります。

既存フォームへの #ajax プロパティの実装例

今回は既存のノード編集フォームへ #ajax プロパティを追加してみます。
例として 都道府県 フィールドの内容によって 市区町村 フィールドの選択値を切り替えます。

モジュール構造

モジュールのファイル構成は以下の通りです

d842_form_ajax
├── d842_form_ajax.info.yml
└── d842_form_ajax.module

コンテンツタイプ(基本ページ)定義

基本ページコンテンツタイプに画像のように2つのフィールドを追加します。

  • 都道府県(field_pref)
  • 市区町村(field_city)

image1

タクソノミー(都道府県、市区町村)定義

ノード編集フォームで利用する為のタクソノミーを定義します。

  • 都道府県市区町村(pref_city)

都道府県毎に市区町村を指定する為、階層化しておきます。

image2

ノード編集フォーム(#ajax 実装前)

ajax 実装前は以下のように 都道府県 を変更しても 市区町村 は何も変わりません。

movie1

モジュール実装

都道府県フィールドの内容によって市区町村フィールドを変更したい為
処理のきっかけである都道府県フィールドに #ajax プロパティを追加します。

また、コールバック関数で市区町村フィールドの内容を更新する処理を実装します。

<?php

/**
 * @file
 * ノード編集フォームの特定のフィールドに#ajaxプロパティを追加.
 */

use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_form_FORM_ID_alter().
 */
function d842_form_ajax_form_node_page_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  // 都道府県フィールドにコールバック関数を追加.
  $form['field_pref']['widget']['#ajax'] = [
    'event' => 'change',
    'callback' => '_d842_form_ajax_set_city_callback',
    'wrapper' => 'edit-field-city-wrapper',
    'method' => 'replace',
  ];

  // 市区町村フィールドの選択値クリア.
  $form['field_city']['widget']['#options'] = ['_none' => '- なし -'];
}

/**
 * 都道府県フィールド変更時、市区町村フィールドを更新.
 *
 * @param array $form
 *   Form array.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   Form object.
 *
 * @return array
 *   市区町村フィールド定義.
 *
 * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
 */
function _d842_form_ajax_set_city_callback(array $form, FormStateInterface $form_state) {
  // 都道府県フィールドの内容取得.
  $pref_value = $form['field_pref']['widget']['#value'];
  // 市区町村フィールド情報取得.
  $field_city = $form['field_city'];
  // 複数回#ajaxが動くよう、IDを固定.
  $field_city['#id'] = 'edit-field-city-wrapper';

  // 都道府県未選択の場合、市区町村そのまま返却.
  if ($pref_value === '_none') {
    return $field_city;
  }

  // 市区町村の初期値.
  $options = ['_none' => '- なし -'];

  // Taxonomyから取得した都道府県に紐付く市区町村を取得.
  $terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree('pref_city');
  foreach ($terms as $term) {
    if ($term->parents[0] == $pref_value) {
      $options[$term->tid] = $term->name;
    }
  }
  // フィールドの選択値に取得した市区町村をセット.
  $field_city['widget']['#options'] = $options;
  // 初期値セット.
  $field_city['widget']['#value'] = '_none';

  return $field_city;
}

ノード編集フォーム(#ajax 実装後)

ajax 実装後は以下のように 都道府県 を変更すると 市区町村 も紐付いたものだけが選択できる状態になります。

movie2

まとめ

以上のようにForm APIの #ajax プロパティを利用すると選択項目によって動的に他のフィールドを変更することが可能になります。
バックエンドの値を取得する際、JavaScriptで実装するより短いコードで実装できますので、是非使ってみてください。

簡単ですが、Form APIの #ajax プロパティのご紹介でした。


共に働く新しい仲間を
募集しています

スタジオ・ウミは「Drupal」に特化したサービスを提供する Drupal のエキスパートチーム。
フルリモート&フレックス制だから、働く場所を選ばず時間の使い方も自由です。
そんなワークライフバランスの整った環境で、当ブログに書かれているような
様々な技術を共に学びながら、Drupalサイト開発に携わってみたい方を募集しています。
まずはお話だけでも大歓迎!ぜひお気軽にご連絡ください。