Needs work
Project:
Drupal core
Version:
main
Component:
forms system
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Reporter:
Created:
3 Dec 2008 at 20:53 UTC
Updated:
6 Nov 2023 at 16:26 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
lilou commentedComment #2
stborchertThis patch adds the ability to add attributes to
optionelements in a more general way. Thus you can add a class or title tooptionin select lists.Comment #4
stborchertUps, patch isn't working as expected. One minor change.
Comment #6
wim leersIf you fix the patch, I'll review it. I need this for Hierarchical Select, so it'd save me an override function.
Your code style is wrong: you should now put spaces around dots!
Comment #7
stborchertAh, true. I tried it with d5 and d7 and forgot to add the spaces. Additionally there was something missing in the last patch so here is a new one.
edit: argh, it failed again. Unfortunately I couldn't checkout HEAD from here and have to use latest d7-dev package. Any hints whats wrong now?
Comment #9
stborchertWell, seems latest dev-tarball is not really up to date with head so the patch fails
Will try again later (if I can access CVS again).
Comment #10
wim leersHere's a reroll :)
Comment #11
stborchertThanks for doing this. I must admit, I simply forgot about it :-/
Comment #13
lilou commented@stBorchert : +1 for supports all kind of attributes, but your patch remove classes by default (the scope of this issue and my patch #2), like theme_table (odd, even) and theme_item_list (first, last).
Comment #14
lilou commentedcross post with testbot ;-)
Comment #15
stborchertHi.
The patch doesn't remove anything. It allows you to add the classes on the place you are building the options for the select list. :-)
Thus you are not sticked to "even" and "odd" but you are totally free to add any class to each option.
If it should be striped the modules have to do this on generating the options array. Otherwise there would (I'm pretty sure they would) be complaints about changing the classes, adding a third class, whatever :-)
Stefan
Comment #16
stborchertHm. While looking through the forms api and discussing the fact that using '#value' for the displayed text of an option probably isn't best with a friend (because the value is the one the option would return) I found '#return_value' would be better.
So options should be build like
Passing a simple array of string as options would convert the array key into '#return_value' and the array value into '#value'.
Thoughts?
Comment #17
lilou commentedYes, I quite agree with you, but for
theme_item_lists()andtheme_table(), drupal add classes by default.Back to CNW because patch #10 failed tests.
Comment #18
stborchertWell I found a nasty bug with an unset '#value' that causes the testbot to fail (hopefully no more errors).
@lilou: as you said, its done by theme-functions. Unfortunately this isn't a theme function. Its worth thinking about adding a
theme_option().Comment #20
lilou commentedSmall typo (elseif)
Comment #22
stborchertOk, I ran simpletest on my local machine to see which tests failed and why. The failed tests didn't have to do anything with this patch, they are all "Uncaught exception" (e.g. blog api)
Only on taxonomy, trigger and especially user tests I'm not sure about the errors. E.g. "Failed to set field x to ...". This needs more review.
Comment #23
stborchertWow, this gets more complicated as I initially thought :-)
User.module tests failed because of providing the permissions in
user_filters()as optgroups. The way this is build has to be changed (maybe taxonomy and triggers, too).Now it is:
proper usage after the patch lands:
Unfortunately there are some more points to take care of (e.g. the filter on admin/user/user isn't working) so this would take a while until the testbot is happy.
Comment #24
stborchertOk bot, here's some food for you.
I've ran all tests and didn't see any errors caused by this patch (hopefully).
Comment #26
stborchertPHP syntax error?
I've run the syntax checks of pifr (
pifr_review_check_syntax()) on my local machine without getting any errors:Any ideas why tesbot fails?
Comment #27
stborchertNext try with clean HEAD.
Again, no parse errors found in these 4 files.
Comment #29
stborchertArgh, this happens when you're editing with vi over a web interface :-/
user.admin.inc misses 4 "s". Therefore the user list filter could not be set and the tests failed. Additionally locale.inc has to be modified to use the new
array('#options' => ...).Hope this passes now (local test succeeded without any errors or exceptions).
Comment #30
stborchertforget to update status...
Comment #31
stborchertHm, testbot doesn't recognize the patch so here it is again.
Comment #32
stborchertMaking this a feature request and pushing priority to get more attention.
Comment #33
walkeroukor commentedawesome
Comment #34
apikongzad commentedThanks for doing this.
...
Comment #36
stborchertModified patch to work with current HEAD.
Comment #37
dawehnerone question:
the handling of for examples checkboxes doesn't change?
If yes its confusing for me, why there is additional syntax for select, but not for checkboxes.
Comment #38
stborchertYou're right. The patch changes the syntax for
<option />elements only.I will re-roll the patch to give the ability adding attributes to all children of #options.
Thanks for the hint.
Comment #39
dawehneralso
i would like to have documentation for it in the patch, this adds quite a bit of functionality, but hard to see in code.
Comment #40
stborchertWell, extended the patch to allow adding attributes to checkboxes and radio buttons.
The only thing that has to be done eventually is adding (for example) the
classattribute of the checkbox to its surrounding div ("form-item").Documentation has to be done within the forms-api docu, but here's a short summary of the new behavior.
<option>elements can now be defined using the following syntax:The code for radio buttons and checkboxes looks similar.
(btw.: the old syntax (key-value-pair) is still valid.)
Comment #41
stborchertforgot status change. argh
Comment #42
dawehnerok my personal error
Comment #43
stborchertFor the log: we had a small discussion in IRC about the use of '#return_value' instead of simply using the array key as the return value. As #return_value is standard FAPI (for checkboxes and radios) it is advisable to use it for options also. (Btw: using the array key as return value is working, too)
Changing status back to needs review.
Comment #44
stborchertNow for real.
Comment #46
sun+1
But let's remove the entire, ugly magic here. Why complicated if it can be simple? Let's introduce:
#type = 'optgroup'
#type = 'option'
So, when iterating over #options, just check whether we're dealing with one of those #types, and handle them accordingly. Fall back to keyed, non-recursive arrays for trivial cases.
The resulting logic will work similarly to #type = 'radios' and #type = 'checkboxes' (depending on whether the select is multiple or not). Additionally, this will allow to support #disabled and other stuff like #id and #attributes (which was the original trigger).
Yes. That will make option groups in form arrays a bit more verbose (but then again, it's questionable whether it's that more verbose, compared to using weird, recursive, anonymous objects in #options). However, it removes all of the current limitations and implements those form elements as proper Form API elements.
Comment #48
casey commentedCrosslinking:
#284917: Allow FAPI select, radios, and checkboxes to specify some options as disabled
#414562: Allow to add custom attributes to a <select> <option> tag
Comment #49
casey commentedComment #50
xjmTracking; this would be very useful and prevent the need for a lot of crazy workarounds. I'd find #disabled, #access, and #attributes all especially valuable.
Comment #51
theunraveler commented+1
@sun: so, would the array to create checkboxes look something like this?
If that is the case, I would like to make sure that this does not introduce a regression. We should still be able to define #options as key => value as well.sun already covered this in their comment and I agree completely.Comment #52
casey commentedI would say:
Like this, we could still allow for #options
Comment #53
theunraveler commented@casey: Would whatever is in '#options' then supersede the option definitions as arrays? I think I like it better in '#options', personally.
-or-
in 'options', like most theme functions in D7 work.
Comment #54
casey commentedMy proposal is exactly how Drupal handles its render trees. you could use element_children() and 'option1' and 'option3' would be automatically available in #children.
And to keep backward compatibility form_process_checkboxes() could check for #options and if available expose them as element children.
I guess this is what sun is proposing too.
Comment #55
sunHrm. To me it sounds like a lot more solid architectural planning is required here. Actually tempted to move that architectural discussion into a g.d.o wiki page and mark this issue as postponed...
But since we have new issue summaries, let's try whether that works out. I've updated the issue summary with an architectural proposal.
Comment #56
theunraveler commentedPerhaps I'm being dense, but it seems like the way Drupal 7 handles parametrized theme functions is by prefixing required params with '#'. For example:
It works the same way with theme_item_list(). Using '#options' to define both complex and trivial option sets just seems a bit cleaner to me. If we start defining options as un-prefixed array keys, then it seems like the '#options' key is just sticking around for legacy reasons. I'd rather use one way or the other.
Comment #57
theunraveler commentedNice issue summary, sun. I believe it's missing an example of '#type' => 'option' though. All if the '#options' are simple one-dimensional arrays.
Comment #57.0
theunraveler commentedNew architectural summary.
Comment #58
sun#type 'option' cannot be used on its own. Option elements are automatically expanded from #options into sub-elements for #type 'select' and 'optgroup'.
Comment #59
theunraveler commentedWhy can't '#type' => 'option' be used on its own? It seems silly to write it and not use it.
That would allow us to do things like:
Comment #60
sunSorry, I meant that #type 'option' (as well as 'optgroup') cannot be used outside of a #type 'select' on its own. Of course, the new expansion algorithm for #options would produce elements of #type 'option'.
I've updated the issue summary accordingly to clarify.
Actually, we have a concrete architectural proposal, so let's try to get it signed off or hear about objections now.
Comment #61
theunraveler commentedSorry to ask so many questions, but should we assume that this issue is particular to '#type' => 'select'? It seems that, if we want to do the same thing for '#type' => 'radios' and '#type' => 'checkboxes', it would be a simple patch, since there are already '#type's for 'radio' and 'checkbox'.
Basically, what we are proposing here is to give '#type' => 'select' the same treatment as 'radios' and 'checkboxes', right? That is to say, breaking out it's children into their own '#type's.
Comment #62
xjm#61: type=#checkboxes and type=#radio already support #options, same as type=#select. I believe you are conflating the markup with the FAPI implementation. There is the HTML tag
<option>, and then there is the FAPI #options array, which is a property of a FAPI element (that may or may not be rendered as an<option>tag depending on context). The second is what we are discussing here.The idea is that we make FAPI support adding #disabled, #access, #attributes, etc. to #options--regardless of the #type--and then FAPI takes care of applying these in the way appropriate to the specific markup.
Edited for clarity.
Comment #63
sunNot to #options itself. I don't support the idea of replacing the current whack hack of #type select's #options with another whack hack of #options.
#options should remain as a simple, one-dimensional array of key/value pairs. If you want optgroups, use optgroups.
This introduces consistency across all #types. Wherever #options appear, they will be expanded into sub-elements of #type 'option'. Hence, the behavior will be identical for #type 'checkboxes', 'radios', 'select', and 'optgroup'.
If you want an attribute for a particular option, then apply it on the sub-element.
In D7+, form_process_checkboxes() and form_process_radios() already support you in doing so by allowing for partial sub-element pre-definitions -- the following is working code to apply a class to option "Foo" and disable option "Bar":
Comment #64
sunActually, there's no patch for this yet. Also, better title.
Comment #65
theunraveler commentedThanks for the clarification. This seems very well-defined to me now.
Also, cool little pointer, sun!
Comment #65.0
theunraveler commentedAdded info about expansion into #type 'option'.
Comment #65.1
sunUpdated issue summary.
Comment #66
andypostAutomatic expanding could bring some overhead to rendering & processing forms.
Comment #67
star-szrSubscribe.
Comment #68
HendrikM commentedI´m trying to get this working inside a hook_form_alter. The following code hat so effect at all:
$form['field_publishing_status']['und']['#options']["draft"]['#disabled'] = TRUE;where "draft" is the key for the field.
<input type="radio" class="form-radio" checked="checked" value="draft" name="field_publishing_status[und]" id="edit-field-publishing-status-und-draft">Any idea why? Thanks!
Comment #69
doublejosh commentedHere's how I added #attributes to options.
It also leaves normal form structures intact, including: normal option lists, opt groups, array of option items arrays, plus empty opt groups for placeholder items (like special menu items).
I overwrote the form_select_options() with a theme_registry_alter() and theme_select() to get class #attributes into options for hierarchical jump selects. Here's that code in place: jump_menu.module.
Comment #71
Anonymous (not verified) commentedLove to see this implemented.
Comment #72
franzSimply re-rolled
Comment #74
barrapontore-roll, will address the test results later.
Comment #76
barraponto#74: 342316_option_add_attributes-74.patch queued for re-testing.
Comment #78
andypost#74: 342316_option_add_attributes-74.patch queued for re-testing.
Comment #80
franz#74: 342316_option_add_attributes-74.patch queued for re-testing.
Comment #82
andypostneeds re-roll
Comment #82.0
andypostUpdated issue summary.
Comment #83
Neo13 commentedIs it still impossible to add attributes to an option?
Comment #84
Anonymous (not verified) commented69: 342316_option_add_attributes_69.patch queued for re-testing.
Comment #86
andypostthis needs to be landed before release, otherwise will require bc
Comment #87
tstoecklerWas bitten by this recently, will take a stab at this.
Comment #88
tstoecklerHere's a first stab. Tested manually that options work. Did not test optgroups yet.
I documented a few open questions in @TODOs in code.
Comment #90
tstoecklerThis should be better.
Optgroups in core aren't converted yet, so those will fail, but regular selects should be fine now.
Comment #92
tstoecklerOK, so those fatals were in fact from the lack of optgroup support in #options. Let's see if this is green.
The reason that is problematic and that - like the issue summary - I think this support should be removed is that optgroups themselves need to be #process-ed to turn themselves into multiple #options. However, selects #process themselves into multiple optgroups at that stage and thus the #process callbacks of the newly created optgroups does not run. This is a shortcoming of Form API but not one that is solved easily. Also optgroups aren't that common so I think it's fine to require a little bit more work.
Tagging this VDC because I realized that Views exposed filters have optgroup support and I'm not quite sure where to adapt the code to account for the new structure. I need some help with that.
Comment #94
tstoecklerWow, it's quite a WTF that
#input => FALSEis ignored forFormElements.Let's see.
Comment #96
tstoecklerFixed Weight render element.
Comment #98
tstoecklerFix form option validation.
Comment #100
tstoecklerUnless I managed to break something else with this, this should be green. If that's the case, the next steps are:
1. Write tests for Select, Optgroup, and Option
2. Clean-up code and remove lots of legacy stuff.
At this point I would suggest to remove the optgroup support in #options in a follow-up (if at all) because that seems like a non-trivial undertaking and the patch will already be big enough without it.
Comment #101
tstoecklerIf this is still green I consider this patch "done", as in ready for some serious reviews.
Removing the "Needs architectural review" tag as this is pretty much inline with what is done with radios/checkboces. Of course it can't hurt ;-)
Comment #102
tim.plunkettSo this is the API change? (Aside from the class moving)
We're losing support for all those other usages?
Comment #103
tstoecklerForgot to mention that I also think in terms of test coverage the added test is sufficient IMO. Here is the list of test cases, taken from the inline comments:
Feel free to suggest additional test cases.
I noticed there were a bunch of
@TODOs which I added in order to clean them up before commit. Did that now. The only one that remains is one that I've long wondered about: Why select elements use#valueinternally instead of#default_value:So that needs to be considered before commit. It might be that we want to leave it that way and clean it up later, then we can just convert the
@TODOinto a@todo.Oh, also I should mention that I removed all support for putting objects into
#options. That seems utterly pointless to me at this point.Comment #104
tstoecklerAhh X-post:
Re #102: Yes, that is an API change. We drop support for passing objects that happen to have a
optionmember variable into#options. Consequently, that support is also dropped fromOptGroup::flattenOptions().Comment #107
andypostComment #108
tstoecklerThe retaining of
#optionsis now consistent with checkboxes and radios and in general less error-prone.Let's see.
Comment #109
tstoecklerForgot to mention this: In fixing
FormTestI realized it duplicates a lot of the new SelectTest. Will have to see how to proceed. I do find it rather weird to test *every* form element in one single test, but perhaps that should be left to a follow-up? OTOH I wrote aDrupalKernelTestandFormTestis aWebTestso I would prefer to remove the duplicated parts fromFormTestinstead. Thoughts?Comment #110
tstoecklerSo I looked into
FormTestand in fact there's no duplication.FormTesttests the form submission of select elements (among other things) andSelectTestjust tests the rendering. The former could also be moved to aKernelTestBasein theory, but that's not for this issue.So this just adapts the test method name.
I also revamped the issue summary.
I would like some feedback first before writing a change notice.
Comment #113
tstoecklerHere we go.
Removed the remaining @TODO. It's not at all related to this issue (it just bugged when I was refactoring the code) and I can't be bothered to open an issue right now.
Comment #115
tstoecklerLet's see if this is green.
Comment #116
joelpittetPutting this on our radar for BADCamp to review.
Comment #117
dawehnerProblem/Motivation
Beta phase evaluation
Afaik we should try to remove the BC breaks if possible ...
So we replaced a simple function call with a
drupal_render_children... did anyone did some benchmarks whether this scales for a complex form?Do we really need to run those for every option? This could result in a performance problems for select fields with a lot of options.
This is to be honest somehow a great DX improvement.
Comment #118
tstoecklerThanks for the review, this was very, very helpful!
So it seems that is fine? Again, feel free to correct me here.
Will now try to do some micro-benchmarks to be able to respond to 2. and 3. Thanks for bringing that up, this is really important and something I would have overlooked.
Comment #119
tstoecklerWow, you were spot on. The current pach is a massive regression. Attached patch creates a form with 100 select elements with 100 options each.
In 8.0.x rendering it takes ~0.25 seconds. With the patch it takes ~4.65 seconds. Clearly this is not acceptable.
I will dig into this, when I find some time.
Comment #120
tstoecklerOh, forgot to attach the test-patch.
Comment #121
yesct commented#2501481: form_select_options() is a theme function in disguise and should not use SafeMarkup::set is duplicating some of this. And that is part of the #2280965: [meta] Remove every SafeMarkup::set() call critical. Maybe we should... use some of this in that issue, or come back to this and try and get this in first.
If we want to try and get this in, since it is a normal task, we should add a beta eval to make sure it is allowed now, and document why.
Comment #122
joelpittetThe option and option group really need to go inside the select template, loading a file for each option is a bit crazy IMO.
The #2501481: form_select_options() is a theme function in disguise and should not use SafeMarkup::set looks like the right direction. Just need to get that last failure knocked out.
Comment #123
star-szr#117 (on phone, no Dreditor) has at least part of a beta evaluation. Haven't had a chance to look at the patch here yet.
Comment #124
stefan.r commentedComment #125
stefan.r commentedI don't know how close this issue is, but @catch mentioned today this would be a nice issue to solve the ugliness of point 1 in https://www.drupal.org/node/2564451
Comment #126
andypostlet's do that in options template so group names will be rendered at the same context as options
Comment #127
lokapujyaShould this continue from #115, or is a rewrite?
Comment #131
xem8vfdh commentedThank you VERY much @ sun for the suggestion in #63. Its times like these when I wish we could 'like' comments (and also properly reference/link users).
Comment #132
lind101 commentedJust a quick note about submitted values for checkboxes using the suggestion in #63. Disabled options default values don't get passed through to submit or validation handlers.
If an option is set to selected as part of a default value and then set as disabled, it's value is un-selectd (0) when the form is submitted, meaning it could be very easy to accidentally unset selected options when saving the form data of disabled fields.
I might be missing something simple, but I couldn't get it to work so I had to write a custom value callback to get around it, something like:
Comment #135
edurenye commentedJust rerolled.
Comment #137
edurenye commentedComment #138
andypostComment #147
eduardo morales albertiAny update on it?
Comment #148
bnjmnmThere's not much incentive to engage in clandestine efforts to address an issue, you can safely assume that what you see here is the current state of things. It's possible an individual has been working on this in secret, but it would be up to that individual to document this in the issue.
Interest in working on this seemed to fade ~4 years ago, and seems unlikely its on anyone's radar anymore. Progress could be resumed if anyone was interested in doing so.
Comment #150
damienmckennaAttempted reroll for 10.1.x and 11.x
Comment #151
damienmckennaForgot a bit.
Comment #152
smustgrave commentedWould request if this could be turned into an MR 42KB is pretty large file and MRs would be easier to review. Moving to NW for CC failure.