Skip to header Skip to main navigation Skip to main content Skip to footer
  • Log in
Home
DrupalVIP
Freelancer service with great care and enthusiasm.
  • Home
  • Products
  • Blog
  • Support
    • Dictionary
    • Drupal Resources
    • External Resources

Select Element, its more hard to deal with Ajax

Breadcrumb

  • Home
  • DrupalVIP Support
  • Select Element, its more hard to deal with Ajax

Drupal Form Select element is harder to deal with when desired to add to it Ajax activities

Ajax is a bit misleading, it's not all on the client side, and if we still want to handle it from the code which is located on the server, e/s program it with the form objects like $form & $form_state it still needs to update the server side within the flow, and the form is still need to have synchronization transactions between the client, server, and cache

not enough documentation on that, especially when working with specific elements like SELECT

My special case started when desire was to create form with arguments, so I will have the ability to initialize variable with in the form in each call, 

public function buildForm(array $form, FormStateInterface $form_state, $dashboard = 0, $project=0, $sprint=0, $redirect='')

but all argument are optional, sprint and projects are sub parts within dashboard, so if not given any arguments, user will have to select dashboard and then select the project and sprint.

the all form will be popped-up as an overlay window.

I use the Form select element to select the desired dashboard, which I added into its array the ajax section:

        '#ajax' => [
          'callback' => '::submitFormDashboardSelected',
          'wrapper' => 'group-select-wrapper',
          'suppress_required_fields_validation' => TRUE,
        ],  

I found out that in order for it to activate the callback function every time, and only at first time, I need to define it correctly, here are my tips:

  1. Don't define '#name'
  2. Don't define '#attribute'->id
  3. Better have the callback as static function: 'callback' => '::submitFormDashboardSelected'

here is the full select definition:

      $form['dashboard_select'] = [
        '#type' => 'select',
        '#title' => t('Dashboard'),
        //'#name' => 'dashboard-select',  <-- prevent the form_state to update
        '#options' => $dashboard_options,
        '#sort_options' => TRUE,
        '#required' => TRUE,
        '#empty_option' => "-- SELECT --",
        '#size' => 1,
        '#default_value' => $dashboard_default,
        '#attributes' => [
          'class' => ['use-ajax'],
          //'id' => "edit-dashboard-select", <-- this prevent the callback
        ],         
        '#ajax' => [
          'callback' => '::submitFormDashboardSelected',
          'wrapper' => 'group-select-wrapper',
          'suppress_required_fields_validation' => TRUE,
        ],        
      ];

 

 

Since my desire that selecting a dashboard will update the project and sprint selection boxes, I have put both of them under 'Field Group' element

      $form['group'] = [
        '#type' => 'fieldgroup',
        '#prefix' => '<div id="group-select-wrapper">',
        '#suffix' => '</div>',         
      ];

When selecting a dashboard, it will rewrite the project list and sprint list

both lists are shown in all cases even if argument has a sprint/project definition

the static callback method was as follows

    public static function submitFormDashboardSelected(array &$form, FormStateInterface $form_state) {
     $dashboard_id = $form_state->getValue('dashboard_select');      
     
     $options[0] = "-- select --";
     $form['group']['project_select']['#default_value'] = 0;
     $form['group']['project_select']['#value'] = 0;
     $form['group']['project_select']['#limit_validation_errors'] = [];
     $form['group']['sprint_select']['#default_value'] = 0;
     $form['group']['sprint_select']['#value'] = 0;
     $form['group']['sprint_select']['#limit_validation_errors'] = [];      
     if ($dashboard_id>0) {        
       $project_options = DashboardController::getProjects($dashboard_id); 
       $project_options_2 = $options + $project_options; //array_merge($options,$project_options );
       $form['group']['project_select']['#options'] = $project_options_2;
       
       $sprint_options = DashboardController::getSprints($dashboard_id);
       $sprint_options_2 = $options + $sprint_options ; //array_merge($options,$sprint_options );
       $form['group']['sprint_select']['#options'] = $sprint_options_2; 
     } 
     else {
       $form['group']['project_select']['#options'] = $options;
       $form['group']['sprint_select']['#options'] = $options;
     }
     return $form['group'];
   }

 

Few tips on that:

  1. empty option in select is not fully implemented and better to add 0 option
  2. to merge arrays is better to use: array+array and not array_merge, this will keep the array item keys
  3. the callback return the updated form part and not AjaxResponse

 

Final part, in order for it to work correctly we must be sure that core ajax library are loaded, we can do it by defining the libraries as follow in the buildForm method

      $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
      $form['#attached']['library'][] = 'core/drupal.ajax';
      $form['#attached']['library'][] = 'core/jquery.form';

 

I also added two buttons, one that cancel the operation and closing to overlay window

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

      $command = new CloseModalDialogCommand();
      $response = new AjaxResponse();
      $response->addCommand($command);
      return $response;
    }

 

the second, activate the actual function according to selections

    public static function submitFormCreate(array $form, FormStateInterface $form_state) {
      $dashboard_id = $form_state->getValue('dashboard_select');
      $project_id = $form_state->getValue('project_select');
      $sprint_id = $form_state->getValue('sprint_select');
            
      self::_createTask($form_state);
      
      $response = new AjaxResponse();
      $response->addCommand(new CloseModalDialogCommand()); 
      return $response;
    }

The from_state -> getValue of select element, returns the key of the selected item

don't forget the pre-define the PHP file with the libraries needed

  use Drupal\Core\Form\FormBase;
  use Drupal\Core\Form\FormStateInterface;
  use Drupal\node\Entity\Node;
  use Drupal\drupalvip_dashboard\Controller\DashboardController;
  use Drupal\Core\Ajax\CloseModalDialogCommand;
  use Drupal\Core\Ajax\AjaxResponse;

 

Drupal Development

Drupal Development
Code Snippet
    public function buildForm(array $form, FormStateInterface $form_state, $dashboard = 0, $project=0, $sprint=0, $redirect='') {  //
      $config = \Drupal::config('drupalvip_task.settings');
      $log = $config->get('log');
      ($log)? \Drupal::logger("drupalvip_task")->debug(__FUNCTION__ . ": START "):'';      
      ($log)? \Drupal::logger("drupalvip_task")->debug("Form Args: da[$dashboard] pr[$project] sp[$sprint] rd[$redirect]"):'';
      
      $form['redirect'] = array(
          '#type' => 'value',
          '#value' => $redirect,
      );
      
      //dashboard select
      $dashboard_default = ($dashboard==0) ? null : $dashboard;
      $dashboard_options = DashboardController::getDashboards();
      $form['dashboard_select'] = [
        '#type' => 'select',
        '#title' => t('Dashboard'),
        //'#name' => 'dashboard-select',  <-- prevent the form_state to update
        '#options' => $dashboard_options,
        '#sort_options' => TRUE,
        '#required' => TRUE,
        '#empty_option' => "-- SELECT --",
        '#size' => 1,
        '#default_value' => $dashboard_default,
        '#attributes' => [
          'class' => ['use-ajax'],
          //'id' => "edit-dashboard-select", <-- this prevent the callback
        ],         
        '#ajax' => [
          'callback' => '::submitFormDashboardSelected',
          'wrapper' => 'group-select-wrapper',
          'suppress_required_fields_validation' => TRUE,
        ],        
      ];      
      
      $form['group'] = [
        '#type' => 'fieldgroup',
        '#prefix' => '<div id="group-select-wrapper">',
        '#suffix' => '</div>',         
      ];      
        $options[0] = "-- select --";        
        $form['group']['project_select'] = [
          '#type' => 'select',
          '#title' => $this->t('Project'),
          '#options' => $options,
          '#limit_validation_errors' => [],
          //'#empty_option' => "-- select --",
          '#size' => 1,        
          '#default_value' => 0, 
        ]; 
        if ($dashboard > 0) {
          $project_options = DashboardController::getProjects($dashboard);
          $project_options_2 = $options + $project_options ;
          $form['group']['project_select']['#options'] = $project_options_2; //$project_options; 
          $form['group']['project_select']['#default_value'] = $project;
        }      

        $form['group']['sprint_select'] = [
          '#type' => 'select',
          '#title' => $this->t('Sprint'),
          '#options' => $options,
          '#limit_validation_errors' => [],
          //'#empty_option' => "-- select --",
          '#size' => 1,        
          '#default_value' => 0, 
        ]; 
        if ($dashboard > 0) {
          $sprint_options = DashboardController::getSprints($dashboard);
          $sprint_options_2 = $options + $sprint_options ;
          $form['group']['sprint_select']['#options'] = $sprint_options_2; 
          $form['group']['sprint_select']['#default_value'] = $sprint;
        }      
        
      $form['subject'] =  [
        '#type' => 'textfield',
        '#title' => $this->t('Subject'),
        '#required' => TRUE,
        '#attributes' => [
          //'id' => "task-subject-box",
        ],        
      ];
      
      $form['actions'] = [
        '#type' => 'actions',
        '#attributes' => [
          'class' => ['form_actions'],
        ],         
      ];
        $form['actions']['cancel'] = [
          '#type' => 'submit',
          '#value' => $this->t('Cancel'),
          '#attributes' => [
            'class' => ['button','use-ajax','form-submit-modal','action-cancel' ],
          ],
          '#ajax' => [
            'callback' => [$this, 'submitFormClose'],
            'event' => 'click',
          ],
        ];       
        $form['actions']['create'] = [
          '#type' => 'submit',
          '#value' => $this->t('Create'),
          '#attributes' => [
            'class' => ['button','use-ajax','form-submit-modal','action-create' ],
          ],
          '#ajax' => [
            'callback' => [$this, 'submitFormCreate'],
            'event' => 'click',
            'onclick' => 'javascript:var s=this;setTimeout(function(){s.value="Saving...";s.disabled=true;},1);',
          ],
        ];              

      $form['#attributes']['class'][] = 'drupalvip_form';  
      $form['#attached']['library'][] = 'drupalvip_task/content';
      $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
      $form['#attached']['library'][] = 'core/drupal.ajax';
      $form['#attached']['library'][] = 'core/jquery.form';
      
      ($log)? \Drupal::logger("drupalvip_task")->debug(__FUNCTION__ . ": RETURN FORM "):'';
      return $form;    
    }
Read More
Tags
Drupal Support
Drupal 10
Ajax
Ajax Form
use-ajax
Select Element
Form Element
AjaxResponse
CloseModalDialogCommand
getValue
Code Snippet

The Freelancer Assistance

Drupal Development

Drupal Development

Drupal Shared Space

Drupal Shared Space

Proactive Maintenance

Proactive Maintenance

Drupal Training

drupal training session

Fullstack Service

Fullstack Service

Site Management

Site Management
Review All Services

Buy Hourly Support

 

Drupal platform support for complex websites. The service includes support, training, troubleshooting, fixes, updates, tool creation and module building.
* Minimum order is for 5 hours of support
* For every 20 hours of order you will be entitled to an additional hour of support
* For every 50 hours of order you will be entitled to 5 additional hours of support

 

>> Payment <<

 
cards

מופעל על-ידי paypal

Legal

  • Home
  • Contact
  • Products

Footer menu

  • Home
  • Contact
  • Products

Copyright © 2026 DrupalVIP project of Automatic Frameworks - All rights reserved

Developed and Maintain by Jonathan Ben Hur Freelancer