Problem/Motivation
On #2900409: [PP-1] Reference Field -- Sort By settings -- only shows 1 field label from 1 random bundle (postponed on this issue), we realized that resolving that issue would be much simpler if the Select element had the ability to sort its options by their labels (after translation). This would presumably be useful for many other use cases.
Proposed resolution
Add options to the Select form element to sort by label. The sorting should allow skipping the first N elements (so that things like "- NONE -" stay at the top). Turned off by default (for backwards compatibility).
Note that option labels will need to be cast to string in order to sort them. However, the labels passed into the Twig templates should be left as TranslatableMarkup objects (assuming they were translatable objects before).
Completed tasks
- Make a patch.
- Add a test to \Drupal\Tests\system\Functional\Form\FormTest::testSelect() to test the new behavior.
Remaining tasks
- Credit alexpott and benjifisher from the other issue, who worked on, reviewed, and consulted on this idea.
User interface changes
Select elements will have optional sorting by label (turned off by default).
API changes
Select elements will have new optional properties to facilitate sorting.
Data model changes
None.
Release notes snippet
The #type => 'select' form element (Select form element class) has new options to allow the options in the list to be sorted by their labels:
- #sort_options: Set to TRUE (default is FALSE) to sort the options by their (translated) labels.
- #sort_start: Set to an integer (default is 0) to start the sorting at that index in the labels. For instance, if your first option is "- none -", start the sorting at index 1 to make sure that first option stays at the top of the list of options.
Either of these can be used within option groups, to sort that group of options. See the Select form element class documentation for more information on Select elements.
Usage example, if you made a list of $options elsewhere in the code:
$form['example_select'] = [
'#type' => 'select',
'#title' => $this->t('Select element'),
'#options' => [
'first' => $this->t('First option'),
] + $options,
'#ajax' => TRUE,
'#sort_options' => TRUE,
'#sort_start' => 1,
];