Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Hi all.
I have a simple form with a textfield with autocomplete that update with his value a field container to display a checkboxes field. The container will be updated but do not display the checkboxes or radios. Select type field works fine.
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['company_name'] = [
'#type' => 'textfield',
'#title' => t('1: Find a Company by Name'),
'#autocomplete_route_name' => 'ect_company.find_company_by_name_controller_findByName',
'#autocomplete_route_parameters' => [
'type' => 'broker',
],
'#ajax' => [
'callback' => array($this, 'findUsers'),
'event' => 'autocompleteselect',
'wrapper' => 'users-wrapper',
'progress' => array(
'type' => 'throbber',
'message' => t('Searching Users...'),
),
],
];
$form['users_wrapper'] = [
'#type' => 'container',
'#attributes' => ['id' => 'users-wrapper'],
];
$form['#attached']['library'][] = 'ect_event/drupal.ect_event_add_user.form';
$form_state->setCached(FALSE);
return $form;
}
/**
* Ajax callback to find company users.
*/
public function findUsers(array &$form, FormStateInterface $form_state) {
$companyName = $form_state->getValue('company_name');
if (preg_match('/\((\d+)\)/', $companyName, $matches)) {
$companyId = $matches[1];
$schedulerData = [
[
"value" => "11",
"label" => "Tivo Preserva",
],
[
"value" => "90",
"label" => "Ente Fet",
]
];
foreach ($schedulerData as $item) {
$options[$item['value']] = $item['label'];
}
$form['users_wrapper']['users'] = [
'#type' => 'checkboxes',
'#title' => t('2: Select users to add from the Company Members'),
'#options' => $options,
];
}
else {
// Create an Ajaxcommand response to display the message
$message = $this->t('Error on retrieve company id');
}
return $form['users_wrapper'];
}
Comments
Comment #2
vincenzodb CreditAttribution: vincenzodb as a volunteer commentedComment #3
vincenzodb CreditAttribution: vincenzodb as a volunteer commentedI guess that is a rendering related problem because `processCheckboxes` method it's not called
Comment #6
donaldp CreditAttribution: donaldp commentedI've independently found this problem with a similar problem replacing one set of radio buttons with another. Similarly with checkboxes. It would appear that the '#options' field is being ignored.
There are comments about this in a number of places including here: https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!Element!Ch...
In my case I've got something similar to the following in my ajax callback.
The resulting code on the page, with debug twig messages is:
The title makes it through but not the options.
I'm going to look a bit deeper into this but I don't have much time to resolve this issue and might have to use a workaround.
Comment #7
donaldp CreditAttribution: donaldp commentedI thought I had found a simple fix for this - but this causes other issues:
You can run the array through the appropriate processor to expand them.
Example:
with of course, the appropriate use clause:
use Drupal\Core\Render\Element\Checkboxes;
or
use Drupal\Core\Render\Element\Radios;
EDIT: I've just noted that although the options appear, this is creating a number of PHP warnings. I will try to determine what the issues is...
Comment #9
javier.martin CreditAttribution: javier.martin commentedI have same issue in my code:
If i remove line. ' Checkboxes::processCheckboxes($form['container']['checkboxes'], $form_state, $form);' an empty checkboxes control is returned. Even with this line, #default_value array is not processed an is imposible return a checboxes control with default lines checked.
I think drupal have same issue with checkbox, radio or tableselect form control on ajax callback.
Comment #10
javier.martin CreditAttribution: javier.martin commentedI have find a fix for this problem. "Checkboxes::processCheckboxes" generate an array like this that finally will be an array of checkbox:
At the end of this array indivual checkbox have been generated so we can modify this array to add '#checked' property with TRUE value to all checkbox that must be checked by default.
Comment #11
dawehnerYou are abusing the ajax system in a way it was not designed to be used.
The ajax callback is meant to be used to simply return the substructure of the form array you want to use to replace in the rendered HTML.
In your form builder you need to build up the form you want to render later in the ajax callback.
Given that you have to use the $form_state to build the form dynamically, in your example provide the checkboxes you actually need, and then return them out in your ajax callback.
Comment #12
javier.martin CreditAttribution: javier.martin commentedYou are right!!!!
- I shouldn't call Checkboxes::processCheckboxes, but is the only way to return checkboxes with value on ajax callback.
- I shouldn't add #checked property, but is the only way to return checkboxes checked by default from ajax callback.
The right code for ajax callback should be:
Comment #13
javier.martin CreditAttribution: javier.martin commentedI think i have solved this issue and dawehner on #11 will be agree with me:
I have included ajax on checkboxes updating a status message.
Enjoy!!!!!
Comment #15
Pascal- CreditAttribution: Pascal- commentedWhy does this work properly for a select list but not for checkboxes?
My code works perfecly when I change '#type' => 'checkboxes' to '#type' => 'select' in my ajax callback.
The checkboxes also work fine if I use them in my buildForm()
What I want to do is:
- I have a select list on my form that loads a taxonomy term id
- Based on the id selected, I want to display a field from that taxonomy term as checkboxes on my form
In short: I want to load the '#options' of my checkboxes field in my ajax callback.
I'm getting the following two errors, only when using 'checkboxes' in my ajax callback:
Notice: Undefined index: #title_display in Drupal\Core\Render\Element\Checkboxes::preRenderCompositeFormElement() (line 20 of /app/www/core/lib/Drupal/Core/Render/Element/CompositeFormElementTrait.php)
Notice: Undefined index: #id in Drupal\Core\Render\Element\Checkboxes::preRenderCompositeFormElement() (line 30 of /app/www/core/lib/Drupal/Core/Render/Element/CompositeFormElementTrait.php)
Comment #16
Pascal- CreditAttribution: Pascal- commentedAfter some further investigation the two errors above don't seem to have to do anything with the actual problem.
Removing the #title field from the checkboxes also removes the notices, but the checkboxes still do not show.
If anyone has some pointers to where I can continue looking, I'd like to fix this issue if possible.
Comment #17
vincenzodb CreditAttribution: vincenzodb as a volunteer commentedI guess the point is that the call to the `Checkboxes::processCheckboxes` appens only by the `buildForm` method and the related elements will be correctly processed only if they are present in this method.
We can correctly manage form alterations only if form elements are already present during the build form.
I guess that there's not a bug here but a design choice.
Comment #20
dsmythjr CreditAttribution: dsmythjr commentedI was running into the same issue, and looking within #9 allows the checkboxes options to be populated.
In my ajax callback:
Does this cover the original issue stated?
Comment #22
marioki CreditAttribution: marioki as a volunteer commented#11 is right, you need to build the structure of the form in buildForm.
You can't alter or add new elements in the callback function.
What you need to do is return the wrapper element in the callback and use your business logic in buildForm to alter the Form.
In my form, I needed to change radios' options depending on a different form element (let's call it $form['dep']).
In the callback function I just return $form['wrapper'] and in buildForm I check the value of 'dep' ($form_state->getValue('dep')) and react accordingly in buildForm. If you do this it works with radios too, without processing them in the callback.
Processing in the callback also caused the radio to break for me, it chose the option that was selected before the callback, not the option I chose after the callback.