Problem/Motivation
Building #options using YAML is not intuitive for most users.
Proposed resolution
Provide a simple UI for building #options for select menus, radios, and checkboxes.
Remaining tasks
- Create a YamlFornOptions element
- Add multiple options to be added
- Add Source (YAML) tab to Edit YAML Form Options. See: yamlform_ui_entity_type_alter()
- Add example to tests/modules/yamlform_test/config/install/yamlform.yamlform.test_element_extras.yml
- Write test verify rendering and processing
- Update YamlFormOption entity edit page
- Update YamlFormElementOptions element using by #select, #radios, and #checkboxes,
Notes
- Reuse D8 core table drag
- Add more should use #ajax
- Add more should include number of options.
- Add optgroup should also be included
- Must support optgroup
- Keep it simple.
- Hopefully code can be reused to create conditional states UI
Code Example
$form['options] = [
'#type' => 'yamlform_options',
'#title' => 'Options',
'#default_value' => [
1 => 'Option 1',
2 => 'Option 2',
'OptGroup' => [
3 => 'Option 3',
],
'#optgroup' => TRUE,
'#required' => TRUE,
],
];
References
Development Notes
- Branch Name: 2759527-create-options-element
- Commit message: Issue #2759527: Create a UI for editing #options
Comments
Comment #2
jrockowitz commentedComment #5
scott_euser commentedHi Jacob,
Simplest is probably following this example but a much nicer interface would be ajaxified, perhaps with an interface similar to the inline entity form widget like this sceenshot. That uses the table drag and the code from it could be used as jump start perhaps.
If built in the latter way as a widget of sorts, it would probably be more reuseable for states, etc.
Would you like my help with it? I could work on it later in the week (Thurs/Fri). Perhaps before that we can arrange to meet on Drupal's IRC, Skype, Hangouts, or whatever your preferred medium is. Also completely understand if you prefer to do it yourself (ex, if you have a vision for it already and how you'd like it to work for states, etc)
Thanks,
Scott
Comment #6
jrockowitz commentedComment #7
jrockowitz commentedComment #8
jrockowitz commentedComment #9
jrockowitz commented@scott_euser Help is always going to appreciated.
I think the best approach is to do this in small steps, which could include...
Below is the only immediate reference I found for creating render elements. There definitely needs to be more documentation on how to create custom form elements for Drupal and the YAML form module.
Some more notes
I am on vacation this week but next week I can do a Google Hangout.
Comment #10
jrockowitz commentedAdding AJAX example to above references.
Comment #11
scott_euser commentedI don't think I've managed to get my head around your intentions on 'Create a YamlFormOptions element yet to be able to make any progress on this.
I've been tinkering within \Drupal\yamlform\Element\YamlFormElementOptions and it seems easy enough to add a draggable table of fields and eventually ajaxify it to dynamically add in rows (when Custom type is selected for the 'Options' within the Add Element form). I think that is not what you are looking for though.
Are you intending to create a new field type like you've done with yamlform_codemirror? So something like:
Then have a new field widget handle the display (ie, creating the renderable array for the table with tabledrag, etc).
Perhaps I'm way off the mark!
Comment #12
jrockowitz commentedYou are not far off.
There needs to be new YamlFormOptions element which can used by the YamlFormElementOptions element and the YamlFormOptionsForm (/admin/structure/yamlform/settings/options/manage/add)
Also creating a new dedicated YamlFormOptions element will be easier to test.
Comment #13
jrockowitz commented@scott_euser I am back from vacation. If you want to do a Google Hangout, just email me.
Comment #14
jrockowitz commentedComment #15
scott_euser commented@jrockowitz I am making progress (attached) but am struggling with a couple things and hoping to get your advice (perhaps you've addressed it elsewhere in YAML Form already?):
Even if (1) is solved, I am not sure if we'll be able to avoid rebuilding the entire form as there doesn't seem to be a way to retrigger #tabledrag if you add in rows to an already rendered table.
At the moment to test, you'd need a form that already has options (and potentially option groups) as I haven't yet started the saving of values. The adding of new options and option group inputs works + handling of existing ones and allowing you to drag them around. It supports options within option groups, options on their own, and mixed.
Hope you can help point me in the right direction for the above bits!
Thanks,
Scott
Comment #16
jrockowitz commented@scott_euser
The below code
Generates the needed widget which would need an 'Add Option Group' Button added below it.
Also, you don't need to the fieldset container
The below code can be changed from
to
Some more notes
Comment #17
scott_euser commented@jrockowitz Thanks for the pointers! One further question; we are still ultimately storing it in YAML right? In the current structure is just value: label so would the unique ID just be a temporary ID until saved?
Comment #18
jrockowitz commented@scott_euser We should be returning (and storing) an associative array of options. We are going to have to convert the existing YamlFormOptions from storing YAML to an associative array. This can be done after the widget is setup and working.
Comment #19
scott_euser commented@jrockowitz Thanks for the info, I think I'm slowly getting there but running into a fair few hiccups connecting the YAML Form Element with the Ajax API.
I haven't been able to get valueCallback to populate already saved data via the new table loaded with the Ajax API unless I do like the attached patch and call buildForm. The attached patch works but feels clunky / hacky.
Note that problem doesn't happen if you simply create a new select element, add some values, then click Add 10 more options - it only happens if you already have saved values and you go in to edit them.
Comment #20
jrockowitz commented@scott_euser Thanks, I will look at the code and see what I can do to help.
Comment #23
jrockowitz commented@scott_user I can now see how difficult and frustrating this is going to be to implement. I think the only way we are going to be able to do this is to completely reverse engineer https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Field!WidgetBase.... and start with just getting basic options with no optgroups working with no AJAX.
By removing all the AJAX and table drag code I was able to get the population and validation of options working in a '2759527-ui-options' branch. I still need to figure out how to get the add button work.
I think once we get the non AJAX working we could gradually layer in the AJAX.
I need a few more hours to get the non AJAX version working.
Comment #28
jrockowitz commented@scott_euser
Wow, this is insanely difficult to sort out. I really appreciate you starting this and feel bad that I had to reapproach the code from a different angle. The good news is if we can get this working correctly it should be very possible to add a UI to the #states API.
I had to go back to looking at Port ajax example add more and remove example from drupal 7 to drupal 8 to figure out how to properly setup the add more button.
Then, I still had to look at the WidgetBase class to figure out that the form state for the number of options needs to be stored via a unique key.
Then, I got completely burned by #1342066: Document that buttons with the same #value need a unique #name for the form API to distinguish them, or change the form API to assign unique #names automatically
Finally, I was able to get the add more working correctly. You can test the add more behavior using /yamlform/test_element_options in the test branch.
Now, I am a little stuck on how to remove an existing option. I can't find any examples of an Element that supports removing values in core or contrib.
A few take aways....
Comment #29
scott_euser commentedNo problem at all, glad it wasn't just me struggling with it! Apologies I've had a busy week, I'll try to take a look asap at your progress and see if I can find anything around the remove. Perhaps looking at how Paragraphs does it could point us in the right direction.
Comment #31
jrockowitz commented@scott_euser I managed to get a buggy but correctly coded 'Remove' button working by looking at \file_managed_file_submit() and using the below example
There is still a bug where it is adding the incorrect number of rows after removing an option but this should be easy to fix.
Comment #35
scott_euser commented@jrockowitz Looks good! I couldn't reproduce the incorrect number of rows being added bug you described, but I did have issues with the multiple select elements in one form with default values prepopulated (options_default_value for instance if you do a clean install of yamlform_test). The issue happens when you hit remove when you have multiple select elements on the page.
Looks like ajaxCallback and removeOptionSubmit just aren't being called at all when the select element is not the first one on the page, so an empty table is returned and all rows are removed.
I couldn't see anything obvious as the callback on the remove button appears identical.
Comment #38
jrockowitz commentedAs of right now, I am not seeing any bugs.
I am using /form/test-element-options for testing.
Here is a screenshot of the form.
I am also attaching a patch with no new tests but I just want to confirm that nothing is broken.
Next I have to write a dedicated test for just the YamlFormOptions element.
Comment #42
jrockowitz commented@scott_euser This might done or at least committable. I am expecting that the element and code will need some more tweaks/improvements in the near future.
Comment #43
jrockowitz commentedComment #44
jrockowitz commentedHere is the actual patch and not a screenshot of some random error from my local machine.
Comment #47
jrockowitz commentedComment #49
scott_euser commentedThat last issue I had with multiple select elements on the same page appears solved.
All seems to work fine for me!
Okay if I revisit optgroup based on this in a simple form? If mixed optgroup and non-optgroup (which appears to be a valid case) then still yaml only perhaps.
Comment #50
jrockowitz commented@scott_euser I am going merge what is done here.
You should create a new ticket for adding optgroup support to YamlFormOptions element.
Right now, optgroups can only be created via editing the YAML source code, which I am okay with.
In the next week or two, I am going to start working on the UI for #states.
Comment #52
jrockowitz commented