Drupal 8 add ajax form element after ajax callback

ⅰ亾dé卋堺 提交于 2021-01-27 11:39:57

问题


I am building a drupal form with multiple ajax enabled form elements.

I have one select list that does an ajax callback after change. The problem is that it adds a new select list to the page, which is also ajax enabled. This does not seem to work, which seems logical to me because the ajax is actually bundled an added to the page so it is lost in the replacecommand.

Is there anyone experienced with this, and does anyone have a solution ?

This is my code

  /**
     * {@inheritdoc}
     */
    public function buildForm(array $form, FormStateInterface $form_state)
    {
        $form['city'] = [
            '#type' => 'select',
            '#title' => $this->t('Station'),
            '#description' => $this->t('City'),
            '#options' => array(
                'Aalst' => $this->t('Aalst'),
                'Brussel' => $this->t('Brussel'),
                'Hasselt' => $this->t('Hasselt'),
                'Leuven' => $this->t('Leuven'),
            ),
            '#ajax' => [
                'callback' => array($this, 'extendFormAjax'),
                'event' => 'change',
                'progress' => array(
                    'type' => 'throbber',
                    'message' => t('Choose City'),
                ),
            ],
            '#suffix' => '<div id="extended-form"></div>',
        ];

        $form['submit'] = [
            '#type' => 'submit',
            '#value' => t('Submit'),
        ];

        return $form;
    }

    /**
     * Ajax callback to validate the email field.
     */
    public function extendFormAjax(array &$form, FormStateInterface $form_state)
    {
        $parking = [
            '#type' => 'select',
            '#title' => $this->t('Parking'),
            '#description' => $this->t('Parking'),
            '#options' => [
                'P1' => $this->t('P1'),
                'P2' => $this->t('P2'),
            ],
            '#ajax' => [
                'callback' => array($this, 'extendFormAjax'),
                'event' => 'change',
                'progress' => array(
                    'type' => 'throbber',
                    'message' => t('Choose parking'),
                ),
            ],
        ];

        $response = new AjaxResponse();
        $response->addCommand(new InsertCommand('#extended-form', $parking));

        return $response;
    }

回答1:


I had a similar issue and i resolved it by adding the element in buildForm and adding a wrapper for it and sending the form element via HtmlCommand

  /**
 * {@inheritdoc}
 */
public function buildForm(array $form, FormStateInterface $form_state)
{
    $form['city'] = [
        '#type' => 'select',
        '#title' => $this->t('Station'),
        '#description' => $this->t('City'),
        '#options' => array(
            'Aalst' => $this->t('Aalst'),
            'Brussel' => $this->t('Brussel'),
            'Hasselt' => $this->t('Hasselt'),
            'Leuven' => $this->t('Leuven'),
        ),
        '#ajax' => [
            'callback' => array($this, 'extendFormAjax'),
            'event' => 'change',
            'progress' => array(
                'type' => 'throbber',
                'message' => t('Choose City'),
            ),
        ],
    ];
     $form['parking'] = [
        '#prefix' => '<div id="extended-form">',
        '#suffix' => '</div>',
        '#type' => 'select',
        '#title' => $this->t('Parking'),
        '#description' => $this->t('Parking'),
        '#options' => [
            'P1' => $this->t('P1'),
            'P2' => $this->t('P2'),
        ],
        '#ajax' => [
            'callback' => array($this, 'extendFormAjax'),
            'event' => 'change',
            'progress' => array(
                'type' => 'throbber',
                'message' => t('Choose parking'),
            ),
        ],
    ];

    $form['submit'] = [
        '#type' => 'submit',
        '#value' => t('Submit'),
    ];

    return $form;
}

/**
 * Ajax callback to validate the email field.
 */
public function extendFormAjax(array &$form, FormStateInterface $form_state)
{
    $parking = [
        '#type' => 'select',
        '#title' => $this->t('Parking'),
        '#description' => $this->t('Parking'),
        '#options' => [
            'P1' => $this->t('P1'),
            'P2' => $this->t('P2'),
        ],
        '#ajax' => [
            'callback' => array($this, 'extendFormAjax'),
            'event' => 'change',
            'progress' => array(
                'type' => 'throbber',
                'message' => t('Choose parking'),
            ),
        ],
    ];

    $response = new AjaxResponse();
    $response->addCommand(new HtmlCommand('#extended-form', $parking));

    return $response;
}

Try it like this. I have not tested the code.




回答2:


Try call somewhere in JS Drupal.attachBehaviors();




回答3:


You need add ajax elements in buildForm methods and rebuild form. Something like this:

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, $no_js_use = FALSE) {

    // We want to deal with hierarchical form values.
    $form['#tree'] = TRUE;

    $form['step'] = [
      '#type' => 'value',
      '#value' => !empty($form_state->getValue('step')) ? $form_state->getValue('step') : 1,
    ];

    switch ($form['step']['#value']) {
      case 1:
        $limit_validation_errors = [['step']];
        $form['step1'] = [
          '#type' => 'fieldset',
          '#title' => $this->t('Step 1: Personal details'),
        ];
        $form['step1']['name'] = [
          '#type' => 'textfield',
          '#title' => $this->t('Your name'),
          '#default_value' => $form_state->hasValue(['step1', 'name']) ? $form_state->getValue(['step1', 'name']) : '',
          '#required' => TRUE,
        ];
        break;
      case 2:
        $limit_validation_errors = [['step'], ['step1']];
        $form['step1'] = [
          '#type' => 'value',
          '#value' => $form_state->getValue('step1'),
        ];
        $form['step2'] = [
          '#type' => 'fieldset',
          '#title' => t('Step 2: Street address info'),
        ];
        $form['step2']['address'] = [
          '#type' => 'textfield',
          '#title' => $this->t('Your street address'),
          '#default_value' => $form_state->hasValue(['step2', 'address']) ? $form_state->getValue(['step2', 'address']) : '',
          '#required' => TRUE,
        ];
        break;
      case 3:
        $limit_validation_errors = [['step'], ['step1'], ['step2']];
        $form['step1'] = [
          '#type' => 'value',
          '#value' => $form_state->getValue('step1'),
        ];
        $form['step2'] = [
          '#type' => 'value',
          '#value' => $form_state->getValue('step2'),
        ];
        $form['step3'] = [
          '#type' => 'fieldset',
          '#title' => $this->t('Step 3: City info'),
        ];
        $form['step3']['city'] = [
          '#type' => 'textfield',
          '#title' => $this->t('Your city'),
          '#default_value' => $form_state->hasValue(['step3', 'city']) ? $form_state->getValue(['step3', 'city']) : '',
          '#required' => TRUE,
        ];
        break;
    }

    $form['actions'] = ['#type' => 'actions'];
    if ($form['step']['#value'] > 1) {
      $form['actions']['prev'] = [
        '#type' => 'submit',
        '#value' => $this->t('Previous step'),
        '#limit_validation_errors' => $limit_validation_errors,
        '#submit' => ['::prevSubmit'],
        '#ajax' => [
          'wrapper' => 'ajax-example-wizard-wrapper',
          'callback' => '::prompt',
        ],
      ];
    }
    if ($form['step']['#value'] != 3) {
      $form['actions']['next'] = [
        '#type' => 'submit',
        '#value' => $this->t('Next step'),
        '#submit' => ['::nextSubmit'],
        '#ajax' => [
          'wrapper' => 'ajax-example-wizard-wrapper',
          'callback' => '::prompt',
        ],
      ];
    }
    if ($form['step']['#value'] == 3) {
      $form['actions']['submit'] = [
        '#type' => 'submit',
        '#value' => $this->t("Submit your information"),
      ];
    }

    $form['#prefix'] = '<div id="ajax-example-wizard-wrapper">';
    $form['#suffix'] = '</div>';

    return $form;
  }

  public function prompt(array $form, FormStateInterface $form_state) {
    return $form;
  }

  public function nextSubmit(array $form, FormStateInterface $form_state) {
    $form_state->setValue('step', $form_state->getValue('step') + 1);
    $form_state->setRebuild();
    return $form;
  }

  public function prevSubmit(array $form, FormStateInterface $form_state) {
    $form_state->setValue('step', $form_state->getValue('step') - 1);
    $form_state->setRebuild();
    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    $messenger = \Drupal::messenger();
    $messenger->addMessage($this->t('Your information has been submitted:'));
  }



回答4:


I experienced this issue and resolved it by this way : For each element which were populated by Ajax, I add the property "#validated" => true and in the callback, the returned field must have the same attributes (id, name) that the original field :

$form['example_field'] = array(
        '#type'         => 'select',
        '#required'     => FALSE,
        '#options'      => getDynamicOptions(),
        '#prefix'       => '<div id="etablissement-type-wrapper">',
        '#suffix'       => '</div>',
        '#attributes'   => [
            'data-drupal-selector'  =>  "edit-example",
            'id'    =>  "edit-example",
            'name'  =>  "example",
        ],
        '#validated' => TRUE,
    );


来源:https://stackoverflow.com/questions/41425020/drupal-8-add-ajax-form-element-after-ajax-callback

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!