0

In drupal 8, I need to create 4 dependent dropdowns to select item from a huge list.

i have no problem creating 2 of them and they work fine with the "ajax" form settings but as soon as I add the 3th one I get "illegal choice" error. It seems as if the options list of the second drop is not updated when the 3 one queries it. same for the 4th.

is there a drupal way to do that or i have to go full JS for this?

here is a huge snippet of who i did it

public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {

        $filters = $items->getSettings()['type'] ?: [];

        $element['category_1'] = array(
            '#type' => 'select',
            '#title' => $this->t('category 1'),
            '#options' => $this->getCategory_1_List($filters),
            '#default_value' => isset($items[$delta]->category_1) ? $items[$delta]->category_1 : NULL,
            '#ajax' => [
                'callback' => [$this, 'category_1_callback'],
                'disable-refocus' => TRUE, // Or TRUE to prevent re-focusing on the triggering element.
                'event' => 'change',
                'wrapper' => 'category_2',
                'progress' => [
                    'type' => 'throbber',
                ],
            ],
        );

        $element['category_2'] = array(
            '#type' => 'select',
            '#title' => $this->t('category 2'),
            '#options' => $this->getCategory_2_List($element['category_1']['#default_value'] ? $element['category_1']['#options'][$element['category_1']['#default_value']] : '--item not good'),
            '#default_value' => isset($items[$delta]->category_2) ? $items[$delta]->category_2 : NULL,
            '#prefix' => '<div id="category_2">',
            '#suffix' => '</div>',
            '#ajax' => [
                'callback' => [$this, 'category_2_callback'],
                'disable-refocus' => TRUE, // Or TRUE to prevent re-focusing on the triggering element.
                'event' => 'change',
                'wrapper' => 'category_3',
                'progress' => [
                    'type' => 'throbber',
                ],
            ],
        );

        $element['category_3'] = array(
            '#type' => 'select',
            '#title' => $this->t('category 3'),
            '#options' => $this->getCategory_3_List($element['category_2']['#default_value'] ? $element['category_2']['#options'][$element['category_2']['#default_value']] : '---item not good'),
            '#default_value' => isset($items[$delta]->category_3) ? $items[$delta]->category_3 : NULL,
            '#prefix' => '<div id="category_3">',
            '#suffix' => '</div>',
            '#ajax' => [
                'callback' => [$this, 'category_3_callback'],
                'disable-refocus' => TRUE, // Or TRUE to prevent re-focusing on the triggering element.
                'event' => 'change',
                'wrapper' => 'Nom_SP',
                'progress' => [
                    'type' => 'throbber',
                ],
            ],
        );

        $element['Nom_SP'] = array(
            '#type' => 'select',
            '#title' => $this->t('Nom SP'),
            '#options' => $this->getNom_SP_List($element['category_2']['#default_value'] ? $element['category_2']['#options'][$element['category_2']['#default_value']] : '---item not good'),
            '#default_value' => isset($items[$delta]->Nom_SP) ? $items[$delta]->Nom_SP : NULL,
            '#prefix' => '<div id="Nom_SP">',
            '#suffix' => '</div>',
        );

        return $element;
    }

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

        $triggeringElement = $form_state->getTriggeringElement();

        $currentField = $triggeringElement['#parents'][0];
        $currentDelta = $triggeringElement['#parents'][1];
        $currentIndex = $triggeringElement['#parents'][2];

        $select = $form_state->getValue($currentField)[$currentDelta][$currentIndex];

        if ($select) {
            $optionText = $form[$currentField]['widget'][$currentDelta][$currentIndex]['#options'][$select];

            $form[$currentField]['widget'][$currentDelta]['category_2']['#options'] = $this->getCategory_2_List($optionText);
        }

        return $form[$currentField]['widget'][$currentDelta]['category_2'];
    }

  • i added more information. – Martin Ouellet Feb 6 at 16:16
  • You're setting the form element [#options] in the AJAX callback, see drupal.stackexchange.com/questions/15989/… – 4k4 Feb 6 at 16:19
  • this was the problem i still have some problems but not with that ty @4k4 – Martin Ouellet Feb 6 at 20:12
  • If you are changing options list in ajax it will through you an error if the option is not present after ajax response. That is the default behavior you can move your condition to formElement and in ajax response, you can return the $form. – Lucifer Feb 7 at 7:15

Browse other questions tagged or ask your own question.