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;
}
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 Jul 28 '16 at 7:55
  • see edited answer
    – 4k4
    Jul 28 '16 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 Jul 28 '16 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.
    – 4k4
    Jul 28 '16 at 11:41
  • after debugging it seems the terms array is null and I resolve the problem Jul 28 '16 at 11:57

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.