1

I have a form with one shown field of type select with ajax callback to show another form field dynamically of type select and with ajax callback again, the problem is second field ajax callback should show a third field dynamically but nothing is shown. here is my code

public function buildForm(array $form, FormStateInterface $form_state) {
    $controller = new Place_AdsController();
    $terms = $controller->content();

    $form['#attached']['library'][] = 'Place_Ads/general';
    $form['level1value'] = array(
        '#type' => 'hidden',
    );
    $form['level1'] = array(
        '#type' => 'select',
        '#description' => 'Please select level one term',
        '#options' => $terms,
        '#attributes' => array(
            'class' => array(
                'mycategory'
            ),
        ),
        '#ajax' => array(
            // Function to call when event on form element triggered.
            'callback' => '::level1SelectedCallback',
            // Effect when replacing content. Options: 'none' (default), 'slide', 'fade'.
            'wrapper' => 'ajax-wrapper2',
            'effect' => 'fade',
            // Javascript event to trigger Ajax. Currently for: 'onchange'.
            'event' => 'change',
            'progress' => array(
                // Graphic shown to indicate ajax. Options: 'throbber' (default), 'bar'.
                'type' => 'throbber',
                // Message to show along progress graphic. Default: 'Please wait...'.
                'message' => NULL,
            ),
        ),
    );
    $form['ajax_wrapper2'] = [
        '#type' => 'container',
        '#attributes' => ['id' => 'ajax-wrapper2'],
    ];
    $form['ajax_wrapper3'] = [
        '#type' => 'container',
        '#attributes' => ['id' => 'ajax-wrapper3'],
    ];

    if ($form_state->getValue('level1') != false) {
        $form['ajax_wrapper2']['level2'] = array(
            '#type' => 'select',
            '#description' => 'Please select level two term',
            //'#options' => '',
            '#attributes' => array(
                'class' => array(
                    'mycategory'
                ),
            ),
            '#ajax' => array(
                // Function to call when event on form element triggered.
                'callback' => '::level2SelectedCallback',
                // Effect when replacing content. Options: 'none' (default), 'slide', 'fade'.
                'wrapper' => 'ajax-wrapper3',
                'effect' => 'fade',
                // Javascript event to trigger Ajax. Currently for: 'onchange'.
                'event' => 'change',
                'progress' => array(
                    // Graphic shown to indicate ajax. Options: 'throbber' (default), 'bar'.
                    'type' => 'throbber',
                    // Message to show along progress graphic. Default: 'Please wait...'.
                    'message' => NULL,
                ),
            ),
        );
    }
    if ($form_state->getValue('level2') != false) {
        //$form['ajax_wrapper3'][0]['#suffix'] = '</div>';
        $form['ajax_wrapper3']['level3'] = array(
            '#type' => 'select',
            '#description' => 'Please select level three term',
            //'#options' => '',
            '#attributes' => array(
                'class' => array(
                    'mycategory'
                ),
            ),
            '#ajax' => array(
                // Function to call when event on form element triggered.
                'callback' => '::level3SelectedCallback',
                // Effect when replacing content. Options: 'none' (default), 'slide', 'fade'.
                'wrapper' => 'ajax-wrapper4',
                'effect' => 'fade',
                // Javascript event to trigger Ajax. Currently for: 'onchange'.
                'event' => 'change',
                'progress' => array(
                    // Graphic shown to indicate ajax. Options: 'throbber' (default), 'bar'.
                    'type' => 'throbber',
                    // Message to show along progress graphic. Default: 'Please wait...'.
                    'message' => NULL,
                ),
            ),
        );
    }

    return $form;
}

public function level1SelectedCallback(array &$form, FormStateInterface $form_state) {
    // Instantiate an AjaxResponse Object to return.
    $ajax_response = new AjaxResponse();
    $controller = new Place_AdsController();
    $terms = array();
    if ($form_state->getValue('level1') != false) {
        $val = $form_state->getValue('level1');
        $terms = $controller->getTerms($val);

    }

    $form['ajax_wrapper2']['level2']['#options'] = $terms;
    $ajax_response->addCommand(new HtmlCommand('#ajax-wrapper2', $form['ajax_wrapper2']['level2']));
    // We can still invoke the change command on #edit-user-name so it triggers Ajax on that element to validate username.
    $ajax_response->addCommand(new InvokeCommand('#ajax-wrapper2', 'change'));
    $ajax_response->addCommand(new InvokeCommand('#level2', 'change'));

    return $ajax_response;
}

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

    $ajax_response = new AjaxResponse();
    $controller = new Place_AdsController();
    $terms = array();
    if ($form_state->getValue('level2') != false) {
        $val = $form_state->getValue('level2');
        $terms = $controller->getTerms($val);

    }

    $form['ajax_wrapper3']['level3']['#options'] = $terms;
    $ajax_response->addCommand(new HtmlCommand('#ajax-wrapper3', $form['ajax_wrapper3']['level3']));
    // We can still invoke the change command on #edit-user-name so it triggers Ajax on that element to validate username.
    $ajax_response->addCommand(new InvokeCommand('#ajax-wrapper3', 'change'));
    $ajax_response->addCommand(new InvokeCommand('#level3', 'change'));

    return $ajax_response;

}

public function level3SelectedCallbackold(array &$form, FormStateInterface $form_state) {
    return null;
}
2

1 Answer 1

0

Changing the option list in an ajax callback like this

$form['ajax_wrapper2']['level2']['#options'] = $terms;

does not work, because the formbuilder does not know about this and will not recognize the new options. You have to move this code to buildForm().

Otherwise you will see a select element, but when you choose an option, nothing will happen or an error occurs that you have chosen the wrong option.

2
  • this piece of code is working fine and the select "#level2" is shown successfully with its ajax callback being fired, however the problem is in the 3rd level "#level3" select not shown even with empty options. So the question why its working with level2 but never with level3? Aug 2, 2016 at 8:57
  • sorry, can't debug the whole code, but this was the most obvious problem, i explain this a bit more, see the edit
    – 4uk4
    Aug 2, 2016 at 9:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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