web-dev-qa-db-ja.com

AJAXによって生成されたフォームアイテムのコールバックAJAX

AJAX以前にAJAXによってレンダリングされたフォーム要素へのコールバックを追加しましたが、うまくいきませんでした。以下のコードを追加します。

少し説明。ここには3つの主要な方法があります。

  1. buildForm-基本フォーム
  2. extraField-AJAXに添付されたコールバック['month']
  3. choosePerson-AJAXコールバックが添付されている:['week_day']['hour']

BuildFormメソッドで、AJAX 'month' select要素のコールバックを使用して基本フォームを作成します。AJAXコールバックで、extraFieldメソッドを見つけることができます。このメソッドには、 「時間」と呼ばれるフォーム要素($form['week_day']['hour'])この要素は適切にレンダリングされます。ただし、この要素にはAJAXコールバックも含まれます。これは機能しません。「person_container」要素と「person」選択は生成されません。

以前にajaxによってレンダリングされた要素をajax化する方法はありますか?

class ReservationForm extends FormBase {

  public function getFormId() {
    return 'reservation_form';
  }

  public function buildForm(array $form, FormStateInterface $form_state) {

    $form['month'] = array(
      '#type' => 'select',
      '#title' => $this->t('Select month'),
      '#options' => array($this->t('January'), $this->t('February'), $this->t('March')),
      '#ajax' => array(
        'callback' => array($this, 'extraField'),
        'event' => 'change',
        'wrapper' => 'week-day',
      ),
    );

    // Disable caching on this form.
    $form_state->setCached(FALSE);

    $form['week_day'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'week-day'],
    ];
  }

  public function extraField(array &$form, FormStateInterface $form_state) {
    $month = $form_state->getValue('month');

    $hour_options = array();

    if ($month == '0') {
      $hour_options[0] = $this->t('08:00');
      $hour_options[1] = $this->t('09:00');
      $hour_options[2] = $this->t('10:00');
    }

    if ($month == '1') {
      $hour_options[0] = $this->t('12:00');
      $hour_options[1] = $this->t('13:00');
      $hour_options[2] = $this->t('14:00');
    }

    if ($month == '2') {
      $hour_options[0] = $this->t('18:00');
      $hour_options[1] = $this->t('19:00');
      $hour_options[2] = $this->t('20:00');
    }

    $form['week_day']['hour'] = array(
      '#type' => 'select',
      '#title' => $this->t('Choose hours @month', array('@month' => $month)),
      '#options' => $hour_options,
      '#ajax' => array(
        // tried with that callback too: [ $this, 'choosePerson']
        'callback' => array($this, 'choosePerson'),
        'event' => 'change',
        'wrapper' => 'person',
      ),
    );

    $form['week_day']['person_container'] = array(
      '#type' => 'container',
      '#attributes' => ['id' => 'person-container'],
    );

    $form['week_day']['person_container']['person'] = array(
      '#type' => 'select',
      '#title' => $this->t('Choose person'),
      '#options' => ['John', 'Sarah', 'Peter'],
    );

    return $form['week_day'];
  }

  public function choosePerson(array &$form, FormStateInterface $form_state) {
    $form['week_day']['person_container']['person'] = array(
      '#type' => 'select',
      '#title' => $this->t('Choose person'),
      '#options' => ['John', 'Sarah', 'Peter'],
    );

   return $form['week_day']['person_container'];
  }
}  
2
David

質問のディスカッションに投稿された Link 4k4が解決策を提供します。

コールバック関数(#ajax ['callback']という名前)を作成します。これは一般に非常に単純な関数で、元のページで置き換えられるフォームの部分を選択して返すだけです。フォームAPIセキュリティシステムの一部として、送信時にエラーがスローされ、コールバックで作成された要素の#ajaxも機能しないため、コールバック関数で新しいフォーム要素を作成できないことに注意してください。 ajax submitで新しい要素を作成する必要がある場合、それらをフォーム定義に追加する必要があります。$ form_stateの値を使用して、フォームビルドプロセスは、最初のフォームロード、または#ajaxによって開始されるロードです。

したがって、次のコード例は機能しています。

class ReservationForm extends FormBase {

  public function getFormId() {
    return 'reservation_form';
  }

  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['month'] = [
      '#type' => 'select',
      '#title' => $this->t('Select month'),
      '#options' => [
        $this->t('January'),
        $this->t('February'),
        $this->t('March'),
      ],
      '#ajax' => [
        'callback' => [$this, 'extraField'],
        'event' => 'change',
        'wrapper' => 'week-day',
      ],
    ];

    // Disable caching on this form.
    $form_state->setCached(FALSE);

    $form['week_day'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'week-day'],
    ];

    if ($form_state->getUserInput()['_triggering_element_name'] == 'month') {
      $month = $form_state->getValue('month');
      $hour_options = [];

      if ($month == '0') {
        $hour_options[0] = $this->t('08:00');
        $hour_options[1] = $this->t('09:00');
        $hour_options[2] = $this->t('10:00');
      }

      if ($month == '1') {
        $hour_options[0] = $this->t('12:00');
        $hour_options[1] = $this->t('13:00');
        $hour_options[2] = $this->t('14:00');
      }

      if ($month == '2') {
        $hour_options[0] = $this->t('18:00');
        $hour_options[1] = $this->t('19:00');
        $hour_options[2] = $this->t('20:00');
      }

      $form['week_day']['hour'] = [
        '#type' => 'select',
        '#title' => $this->t('Choose hours @month', ['@month' => $month]),
        '#options' => $hour_options,
        '#ajax' => [
          'callback' => [$this, 'choosePerson'],
          'event' => 'change',
          'wrapper' => 'person-container',
        ],
      ];

      $form['week_day']['person_container'] = [
        '#type' => 'container',
        '#attributes' => ['id' => 'person-container'],
      ];

      $form['week_day']['person_container']['person'] = [
        '#type' => 'select',
        '#title' => $this->t('Choose person'),
        '#options' => ['John', 'Sarah', 'Peter'],
      ];
    }

    if ($form_state->getUserInput()['_triggering_element_name'] == 'hour') {
      $form['week_day']['person_container']['person'] = [
        '#type' => 'select',
        '#title' => $this->t('Choose person'),
        '#options' => ['Hans', 'Frank', 'Emma'],
      ];
    }

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
  }

  public function extraField(array &$form, FormStateInterface $form_state) {
    return $form['week_day'];
  }

  public function choosePerson(array &$form, FormStateInterface $form_state) {
    return $form['week_day']['person_container'];
  }

}
8
schneidolf

コールバックまたはvalidateForm()で要素を変更することはできません。buildForm()メソッドに配置する必要があります。

ここに完全な例があります:

    /method buildForm
    $result = \Drupal\my_module\Controller\Contaminante::list(); //database logic
    foreach ($result as $it){
        $arrSelectContaminantes[$it["id_contaminante"]] = t($it["descripcion"]);
    }

    $form['select_contaminantes'] = array(
        '#type' => 'select',
        '#options' => $arrSelectContaminantes,
        '#ajax' => [
            'callback' => '::seleccionContaminantes',
            'disable-refocus' => false,
            'event' => 'change',
            'wrapper' => 'el-select-estaciones',
            'method' => 'replaceWith'
        ]
    );

    $selected_value = $form_state->getValue('select_contaminantes');
    $opciones = array();

    if(isset(selected_value)){
         $resultado;
         if($form_state->getValue("select_contaminantes") != 0){
            $opciones["0"] = t("ALL");
            $resultado = \Drupal\montar_mapa\Controller\Estacion::lista($form_state->getValue("select_contaminantes")); //DB LOGIC
        }else{
            $resultado = \Drupal\montar_mapa\Controller\Estacion::lista(); //DB LOGIC
        }

        foreach ($resultado as $it){
            $opciones[$it["id"]] = t($it["nombre"]);
        }
    }

    $form['select_estaciones'] = array(
        '#type' => 'select',
        '#id' => "el-select-estaciones",
        '#options' => $opciones,
        '#empty_option' => $this->t('-Select contaminante first'),
        '#validated' => TRUE,
    );

本当に重要:

依存フィールド(例では$ form ['select_estaciones')を印刷するたびに、検証する必要があります(オプションで '#validated' => TRUE)

Nullであるかどうかにかかわらず、トリガーフィールド(例では$ form ['select_contaminante])の選択した値を比較する必要があります。直接比較すると、値が0の場合、「選択なし」と解釈されます。

0
Nacho Escursell