1

I have an ajax dropdown that loads another form based on the selection. When a staff member is selected, it loads the follow up form fine. However, when the follow up form's ajax is fired, it returns an ajax error containing the whole page.

When the second ajax form is used manually (not from being loaded by ajax) it functions perfectly.

My Initial Ajax Form:

  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['form']['staff'] = [
      '#type' => 'select',
      '#options' => ['Select'] + $this->dbService->getStaffList(),
      '#ajax' => [
        'callback'  => [$this, 'loadStaffAjax'],
        'progress'  => [
          'type'    => 'throbber',
          'message' => null,
        ],
      ],
    ];

    return $form;
  }

loadStaffAjax method:

  public function loadStaffAjax(array &$form, FormStateInterface $form_state) {
    $response = new AjaxResponse();

    $forms = [
      '#weekPopup_wrapper'    => 'Drupal\MODULE_NAME_REDACTED\Form\WeekPopupForm',
    ];

    $staff = $form_state->getValue('staff', null);

    if (!is_null($staff) && $staff > 0) {
      //Load each form.
      foreach ($forms as $form_id => $form_path) {
        $form = \Drupal::formBuilder()->getForm(
          $form_path,
          $staff
        );

        $response->addCommand(new HtmlCommand($form_id, $form));
      }
    } else {
      //Clear each form.
      foreach ($forms as $form_id => $form_path) {
        $response->addCommand(new HtmlCommand($form_id, ''));
      }
    }


    $status_messages = ['#type' => 'status_messages'];
    $response->addCommand(new HtmlCommand('.highlighted aside .region', $status_messages));

    return $response;
  }

Answer: The answer provided by Berdir resolved my issue. I was thinking about the process in the wrong way, instead of breaking each section up into different forms I modified the code to be one single form.

Example:

  public function buildForm(array $form, FormStateInterface $form_state, $admin = FALSE) {
    $form['form']['admin'] = [
      '#type'  => 'hidden',
      '#value' => $admin? '1' : '0',
    ];

    $form['form']['staff'] = [
      '#type' => 'select',
      '#options' => ['Select'] + $this->dbService->getStaffList(),
      '#ajax' => [
        'callback'  => [$this, 'loadStaffAjax'],
        'progress'  => [
          'type'    => 'throbber',
          'message' => null,
        ],
      ],
    ];

    if ($form_state->getValue('staff', 0) > 0) {
      $selectedDay = '';

      $form['form']['weekOf'] = [
        '#type'                 => 'textfield',
        '#title'                => $this->t('The week of'),
        '#size'                 => 20,
        '#default_value'        => $selectedDay,
        '#ajax'                 => [
          'callback'  => [$this, 'weekSelectedAjax'],
          'event'     => 'change',
          'progress'  => [
            'type'    => 'throbber',
            'message' => null,
          ],
        ],
      ];
    }

    return $form;
  }

  public function loadStaffAjax(array &$form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    $response->addCommand(new HtmlCommand('#staffDropdownForm', $form));

    return $response;
  }
1

I don't think you want to display another form, why not just update the form that you have with additional fields?

The (or at least my) golden rule for ajax in forms is that the ajax callback must not contain any form logic. An ajax callback should trigger a submit callback that rebuilds the form, there you re-generate the form based on the submitted values and then the ajax callback does nothing but update the part of the form that was changed (or multiple parts, but in most cases, one is enough. You can even replace the whole form).

| improve this answer | |
  • Thank you Berdir. I've adjusted my method as you recommended and now the secondary ajax functions as expected. I had each portion of the form seperated into it's own formController, but I suppose it makes more sense to have 1 single form for each step and to rebuild it as it changes. – EmGee Nov 23 '15 at 17:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.