3

I have an element $form['elements']['manufacturer']. On change, I want to change $form['elements']['form_factor'] and $form['elements']['model'].

Currently I have:

$form['elements']['manufacturer']['#ajax'] = [
    'callback' => 'formChanged',
    'wrapper' => 'form-factor',
    'event' => 'change',
];

which works and changes the form-factor. But, I want to change the model as well.

Iniside formChanged return form-factor in the callback function, so I can't return model element.

function formChanged(array &$form, FormStateInterface $formState){
  $form["elements"]["form_factor"]["#value"] = 0;
  return $form["elements"]["form_factor"];
}

Reading from past posts, one option was to return the whole form inside formChanged (return $form), but this doesn't seem like a good approach.

I can't do something like, having 2 callbacks:

$form['elements']['manufacturer']['#ajax'] = [
   [
    'callback' => 'formChanged',
    'wrapper' => 'form-factor',
    'event' => 'change',
   ],
   [
    'callback' => 'anothercallback',
    'wrapper' => 'another-one',
    'event' => 'change',
   ]
];

2 Answers 2

4

Remove the wrapper key

$form['elements']['manufacturer']['#ajax'] = [
  'callback' => 'formChanged',
  'event' => 'change',
];

Your callback

public function formChanged(array &$form, FormStateInterface $formState){
    $form['elements']['form_factor']['#value'] = 0;
    $form['elements']['model']['#value'] = 0;
    $response = new \Drupal\Core\Ajax\AjaxResponse();
    $response->addCommand(new \Drupal\Core\Ajax\ReplaceCommand(".form-item-form-factor", $form['elements']['form_factor']));
    $response->addCommand(new \Drupal\Core\Ajax\ReplaceCommand(".form-item-model", $form['elements']['model']));
    return $response;
}
2
  • works like a charm! thank you Oct 9, 2020 at 16:15
  • I didn't have that 'elements' array (maybe it's D9 change) but I had structure like: $form['field_name']['widget']['#value'] = 0;
    – MilanG
    Sep 14, 2022 at 8:19
3

Instead of returning a single render array (of all or part of your form) from your callback, you will need to return an AjaxResponse that contains a ReplaceCommand for each piece of the form you want to replace:

For example, in your callback:

$response = new AjaxResponse();
$response
  ->addCommand(new ReplaceCommand('#edit-form-factor', $form_factor_element))
  ->addCommand(new ReplaceCommand('#edit-model', $model_element));
return $response;

See the guide: https://www.drupal.org/docs/drupal-apis/ajax-api/basic-concepts#sub_form

And the Ajax commands reference: https://www.drupal.org/docs/drupal-apis/ajax-api/core-ajax-callback-commands

3
  • Actually the 2nd param of ReplaceCommand does accept render arrays
    – No Sssweat
    Oct 9, 2020 at 3:41
  • Thanks for fixing that - I should've read more closely. Oct 9, 2020 at 3:48
  • @BradTreloar Thanks for the links! It not only works, but I understand it now. Oct 9, 2020 at 16:16

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.