0

I am using a custom composite field("test") in drupal8 webform in a webform_form_alter() hook. Two select fields-"out_part" and "out_serial" are added to this composite field("test"). "out_serial" is dependent on "out_part" i.e. upon selecting an out_part value from the dropdown, the dropdown values of out_serial are generated. I was able to achieve this with ajax callbacks.

    $form['elements']['test']['#element'] = array(
    'out_part' => array(
            '#type' => 'select',
            '#id' => 'out_part',
            '#options' => array(
                '80002192'=>'80002192',
                '80002191'=>'80002191'
                ),
            '#ajax' => array(
                'event' => 'change',
                'wrapper' => 'serialNumber_wrapper',
                'callback'=> 'populateOutSerialNumbers',
                'method'=> 'replace'
                )
            ),
    'out_serial' => array(
            '#type' => 'select',
            '#id' => 'out_serial',
            '#validated' => TRUE,
            '#attributes' => [
                                'id' => ['serialNumber_wrapper'],
                              ],
            ));         

    function populateOutSerialNumbers($form, $form_state){
        $partNumber = $form_state->getValue('test')[1]['out_part'];
        $partNumber = isset($partNumber) ? $partNumber : 'Onboard';

        // Update the $result with dynamic database query results with respect to selected out_part
        Drupal\Core\Database\Database::setActiveConnection('***');  
        $db = Drupal\Core\Database\Database::getConnection();
        $query = $db->query("select distinct T1.serialnumber from assets T1 where T1.dbid <> 0 and (T1.manufacturerpartno = :partNumber)", [':partNumber' => $partNumber]);
        $result = $query->fetchAllKeyed(0,0);

        $form['elements']['test']['#element']['out_serial']['#options'] = $result;

        db_set_active();
        return $form['elements']['test']['#element']['out_serial'];
    }                                                               

This callback works only on the first set of values of the custom composite field. When I click on "Add", the ajax fails to work on the second set of values. Any suggestions on how to overcome this? Do I need to add the ajax to $form['elements']['test']['items'] ?

1
  • You can't modify $form in an ajax callback. You'll find examples for dependent dropdowns in the Examples module.
    – 4k4
    Aug 31 '19 at 16:35
0

You can not modify the $form in the ajax callback. The option for the element out_serial should be set inside form build not in ajax callback. Try with following approach:

// Inside your form build or alter function.
$form['elements']['test']['#element'] = array(
  'out_part' => array(
    '#type' => 'select',
    '#id' => 'out_part',
    '#options' => array(
      '80002192'=>'80002192',
      '80002191'=>'80002191'
    ),
    '#ajax' => array(
      'event' => 'change',
      'wrapper' => 'serialNumber_wrapper',
      'callback'=> 'populateOutSerialNumbers',
      'method'=> 'replace'
      )
    ),
  'out_serial' => array(
    '#type' => 'select',
    '#id' => 'out_serial',
    '#validated' => TRUE,
    '#attributes' => [
        'id' => ['serialNumber_wrapper'],
      ],
    )
);         

// Set value here as when you return the element in ajax callback.
// the form will come here again for rebuild with $form_state having filled values.
if (!empty($form_state->getValue('test'))) {
  $partNumber = $form_state->getValue('test')[1]['out_part'];
  $partNumber = isset($partNumber) ? $partNumber : 'Onboard';

  // Update the $result with dynamic database query results with respect to selected out_part
  Drupal\Core\Database\Database::setActiveConnection('***');  
  $db = Drupal\Core\Database\Database::getConnection();
  $query = $db->query("select distinct T1.serialnumber from assets T1 where T1.dbid <> 0 and (T1.manufacturerpartno = :partNumber)", [':partNumber' => $partNumber]);
  $result = $query->fetchAllKeyed(0,0);

  $form['elements']['test']['#element']['out_serial']['#options'] = $result;

  db_set_active();
}
// End of your build or form alter function.

/**
 * Ajax callback of out_part element.
 */
function populateOutSerialNumbers($form, $form_state){
  return $form['elements']['test']['#element']['out_serial'];
}

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.