4

I'm trying to make dynamic form in my module: I have one field of type select containing some options, and when selecting one option a new field should be added dynamically to the form which in turn will contain another list of options. here what I try to do but nothing seems to work correctly

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

    $form['#attached']['library'][] = 'Place_Ads/general';
    $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' => 'Drupal\Place_Ads\Form\Place_AdsForm::level1SelectedCallback',
            // Effect when replacing content. Options: 'none' (default), 'slide', 'fade'.
            '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();
    if ($form_state->getValue('level1') != false) {
        $form['level2'] = array(
            '#type' => 'select',
            '#description' => 'Please select level two term',
            //'#options' => $terms,
            '#attributes' => array(
                'class' => array(
                    'mycategory'
                ),
            ),
        );
        $form_state->setRebuild(TRUE);
    }

    return $ajax_response;
}

1 Answer 1

2

Build form elements in buildForm() only, not in ajax callback. The ajax callback is only for preparing the ajax response. When the ajax callback is called, buildForm() has already run with the updated $form.

Your ajax response is empty. You didn't add any ajax command to it. See ajax examples how you can do this.

But in your case you don't need any code in ajax callback. It would be enough to simply return the changed part of $form in a div container.

For this put an empty container in buildForm() and move the select form element from the ajax callback to buildForm() and put it in the container, if the condition in $form_state is met:

$form['ajax_wrapper'] = [
  '#type' => 'container',
  '#attributes' => ['id' => 'ajax-wrapper'],
];

if ($form_state->getValue('level1') != false) {
        $form['ajax_wrapper']['level2'] = array(
            '#type' => 'select',
            '#description' => 'Please select level two term',
            //'#options' => $terms,
            '#attributes' => array(
                'class' => array(
                    'mycategory'
                ),
            ),
        );

And the ajax callback:

public function ajaxCallback(array &$form, FormStateInterface $form_state) {
  return $form['ajax_wrapper'];

change #ajax to:

'#ajax' => [
  'callback' => '::ajaxCallback',
  'wrapper' => 'ajax-wrapper',
],
6
  • please help me how to do what you suggest Commented Jul 28, 2016 at 7:55
  • see edited answer
    – 4uk4
    Commented Jul 28, 2016 at 9:23
  • oh thanks @4k4 it works perfectly, but I want some more help which is I want to fill in the level2 select with options. those options I retrieve from database in my controller function named getTermChild($termid) which return array of retrieved children what I did is: ` $val = $form_state->getValue('level1'); $terms = $controller->getTerms($val); $form['ajax_wrapper']['level2']['options'] = $terms; return $form['ajax_wrapper']; ` but still the select is empty Commented Jul 28, 2016 at 11:26
  • It's hard to tell, why the select is empty. Did you examine what the controller function returns in $term? When you have more information, ask another question.
    – 4uk4
    Commented Jul 28, 2016 at 11:41
  • after debugging it seems the terms array is null and I resolve the problem Commented Jul 28, 2016 at 11:57

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.