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
i'm working on the upgrade of panels 1.x module to D6 and i'm hanging on one problem that looks like a bug in form api... i tried to use "image_button" to select the panels (add panel step 1).
The following code is how the image button is created.
$form['layout'][$id] = array(
'#type' => 'image_button',
'#title' => t('Layout @title', array('@title' => $layout['title'])),
'#default_value' => $id,
'#src' => $file,
'#prefix' => '<div class="layout-link">',
'#suffix' => '<div>'. $layout['title'] .'</div></div>',
i tried to grab the clicked image with $form_state['clicked_button']['#value']
, but this returns the last form value and not the image_button clicked. Is there something wrong or is this a bug? If not a bug - how can i get the value of the clicked image_button?
function panels_add_page_form_submit($form, &$form_state) {
print '<pre>'; var_dump($form_state); print '</pre>';
exit;
}
This is the dump from $form_state in submit state:
array(5) {
["storage"]=>
NULL
["submitted"]=>
bool(true)
["values"]=>
array(12) {
["fourcol_25_25_25_25"]=>
bool(true)
["threecol_33_33_33"]=>
string(17) "threecol_33_33_33"
["twocol_25_75"]=>
string(12) "twocol_25_75"
["twocol_33_66"]=>
string(12) "twocol_33_66"
["twocol_38_62"]=>
string(12) "twocol_38_62"
["twocol_50_50"]=>
string(12) "twocol_50_50"
["twocol_62_38"]=>
string(12) "twocol_62_38"
["twocol_66_33"]=>
string(12) "twocol_66_33"
["twocol_75_25"]=>
string(12) "twocol_75_25"
["form_build_id"]=>
string(37) "form-d881d6db64209236f4f49a271734bcae"
["form_token"]=>
string(32) "add97c15fe7c7f749af8385bab5c6ed4"
["form_id"]=>
string(20) "panels_add_page_form"
}
["clicked_button"]=>
array(25) {
["#type"]=>
string(12) "image_button"
["#title"]=>
string(34) "Layout 2 Spalten mit 75/25 Teilung"
["#default_value"]=>
string(12) "twocol_75_25"
["#src"]=>
string(49) "sites/all/modules/panels/layouts/twocol_75_25.png"
["#prefix"]=>
string(25) "
" ["#suffix"]=> string(44) "
2 Spalten mit 75/25 Teilung
"
["#post"]=>
array(6) {
["fourcol_25_25_25_25_x"]=>
string(2) "19"
["fourcol_25_25_25_25_y"]=>
string(2) "50"
["fourcol_25_25_25_25"]=>
string(19) "fourcol_25_25_25_25"
["form_build_id"]=>
string(37) "form-71c346e145f18c36f651f72b5cd76095"
["form_token"]=>
string(32) "add97c15fe7c7f749af8385bab5c6ed4"
["form_id"]=>
string(20) "panels_add_page_form"
}
["#programmed"]=>
bool(false)
["#tree"]=>
bool(false)
["#parents"]=>
array(1) {
[0]=>
string(12) "twocol_75_25"
}
["#array_parents"]=>
array(2) {
[0]=>
string(6) "layout"
[1]=>
string(12) "twocol_75_25"
}
["#weight"]=>
float(0.008)
["#processed"]=>
bool(false)
["#description"]=>
NULL
["#attributes"]=>
array(0) {
}
["#required"]=>
bool(false)
["#input"]=>
bool(true)
["#button_type"]=>
string(6) "submit"
["#executes_submit_callback"]=>
bool(true)
["#process"]=>
array(1) {
[0]=>
string(16) "form_expand_ahah"
}
["#return_value"]=>
bool(true)
["#has_garbage_value"]=>
bool(true)
["#name"]=>
string(12) "twocol_75_25"
["#id"]=>
string(17) "edit-twocol-75-25"
["#value"]=>
string(12) "twocol_75_25"
}
["redirect"]=>
NULL
}
Comment | File | Size | Author |
---|---|---|---|
#31 | test_form.module.txt | 1.41 KB | Pasqualle |
#24 | form-default-garbage-value.patch | 723 bytes | hass |
#17 | patch.patch | 690 bytes | webernet |
#11 | form-default-garbage-value.patch | 847 bytes | merlinofchaos |
Comments
Comment #1
hass CreditAttribution: hass commentedMarking critical.
In http://drupal.org/node/144132 the example shows this is correct and i know it is broken. The $form_state['clicked_button'] array does not contain a copy of the clicked button.
Comment #2
merlinofchaos CreditAttribution: merlinofchaos commentedYou can't reliably get the value of an image button. But you don't need to; instead you can get the actual form element info of the image button, and you can store something in there to get you whatever value you need. That's actually better, though obviously it'll require some code rework.
Comment #3
hass CreditAttribution: hass commentedBut the docs says i get A full copy of the button element that was clicked to submit the form and if this is the case - i'm fine. Why is this not possible to reliably get the value of an image button?
Comment #4
hass CreditAttribution: hass commentedI tried to add an additional
layout
value:But the posted result does not contain the correct value, too.
["#layout"]=> string(12) "twocol_75_25"
Comment #5
hass CreditAttribution: hass commentedI tried both IE6 and Firefox 2.0.
i found this in form.inc:
but this requirement is fulfilled. See the following HTML:
Comment #6
hass CreditAttribution: hass commentedI'm not sure what the below part of
_form_button_was_clicked
is for. I have read the following and haven't understood this in the depth it might need and how i can reproduce this, but if i set this to FALSE or simply remove the complete block - the clicked_button values are correct for my image button list... i hope someone from the form gurus will jump in and bring some light on it.See the correct array now. Aside the #parent values looking changed by this, too. Not sure what must be inside, but it looks much better.
Comment #7
Gábor HojtsyHass, I am trying to understand what is going on here, but from the dump you have above in the report, you have:
So
empty($form['#has_garbage_value']) && isset($form['#value']) && $form['#value'] !== ''
should be TRUE, and then _form_button_was_clicked() will return TRUE. But this goes through all #input types (from form_builder() to _form_builder_handle_input_element() and then to _form_button_was_clicked(). So you get the last button as a result.Looks like $form_state['values'] is only === TRUE for the button clicked, for the others, it is a string, so the button is rightly identified. It is just not properly put into clicked_button.
Comment #8
merlinofchaos CreditAttribution: merlinofchaos commentedYou have a #default_value
If you have a #default_value and no value is received in $_POST, that #default_value is moved to #value. That makes it appear that the button was clicked.
Remove the #default_value.
Comment #9
Gábor HojtsyLooks like this is by-design. Reopen if merlinofchaos' tip did not solve the problem.
Comment #10
merlinofchaos CreditAttribution: merlinofchaos commentedComment #11
merlinofchaos CreditAttribution: merlinofchaos commentedWhoops, that wasn't supposed to happen.
Try this patch. It prevents #default_value propagation if #has_garbage_value is set.
Comment #12
hass CreditAttribution: hass commented@merlinofchaos: could you clarify how i should give a button a value - if not with #default_value? Should i use #value as replacement? If i do not add anything i will end up with no value!?
What value should a image_button return if not having a value to post? See the following example:
Thank you for your patch - i give it try patch in ~3 hours...
PS: "minor" prio looks strange to me until i do not understand how this could work.
Comment #13
merlinofchaos CreditAttribution: merlinofchaos commentedIt's not safe to give image buttons values because of IE. That said, the patch I presented *should* prevent unexpected propagation of the default value to the value. But even without the patch, omit the default_value and, as I suggested very early on, use something like '#layout' to get the value out of clicked button.
To explain what is happening:
The process that checks whether or not the button is clicked is testing to see if a value was returned for the button. However, because you have a #default_value, a #value is being set even though there is no value in $_POST.
Therefore, the form thinks all buttons were clicked, thus you see the last button.
Now, the patch supplied prevents #value from getting set to #default_value if #has_garbage_value is set. I'm actually not completely sure that's the right way of doing that, but I'm not sure it's the wrong way either.
Comment #14
Gábor Hojtsyhass: why do you need a value at all? If it is pressed, it will be your clicked_button, if not, then not. What purpose would whatever value serve?
Comment #15
merlinofchaos CreditAttribution: merlinofchaos commentedBTW my patch exists less to fix hass' problem than it does to prevent broken behavior when #default_value is used together with image buttons. I think it's safe to say that more than one user will set #default_value on an image button to try and get a value out there, and then be confused as to why that button (or worse, some other button *also* with #default_value set) is always showing up as clicked.
Comment #16
hass CreditAttribution: hass commentedParse error: syntax error, unexpected ')', expecting ']' in includes\form.inc on line 964
Comment #17
webernet CreditAttribution: webernet commentedComment #18
hass CreditAttribution: hass commentedLooks like without #default_value and #layout added i get the correct result. The docs at http://api.drupal.org/api/file/developer/topics/forms_api_reference.html.... should be extended about "#return_value" or other possible custom values... that would help others, too. It's more the missing documentation that produced this confusion on the end of the day.
Comment #19
hass CreditAttribution: hass commentedSorry... setting back status. Aside - patch worked for me with #default_value defined.
Comment #20
Pasquallemaybe this is related http://drupal.org/node/209574
the last patch is missing one parenthesis, and does not solved my problem..
Comment #21
hass CreditAttribution: hass commentedFor sure, i tried with this code as an example in panels and helped me to find this bug. But as we found above it's a module bug, too.
Comment #22
hass CreditAttribution: hass commentedPatch worked for me.
Aside i'd like to remind someone having permission to fix the docs as described in #18
Comment #23
Gábor HojtsyHass, #17 still looks like having a parse error, so I doubt you tested the patch.
Comment #24
hass CreditAttribution: hass commentedDamn! You are right... sorry for the inconvenience. I've tested long time ago with http://drupal.org/node/206955#comment-683417 and added the missing
]
myself. Patch attached is an update of #11.Comment #25
Gábor HojtsyThanks, committed with this added documentation:
Comment #26
Anonymous (not verified) CreditAttribution: Anonymous commentedAutomatically closed -- issue fixed for two weeks with no activity.
Comment #27
phiz118 CreditAttribution: phiz118 commentedIt looks like this is still a bug in 6.2 if a #value attribute is filled in.
Here is some test code to generate the error, if you remove the #value attribute under the image button everything works:
test_form.info
name = Update Test Form
description = Module for Updating the Test Form
core = 6.x
test_form.module
Comment #28
hass CreditAttribution: hass commentedThis issue is solved. See the examples.
Comment #29
phiz118 CreditAttribution: phiz118 commentedearnie told me that this was supposed to be fixed in 6.2, but as you can see from my example it is not fixed. I'm referring to the #value attribute, not the #default_value attribute in this example, but the bug is the same. If you don't use the #value attribute, everything works as expected, but if you supply a #value then it fails. Obviously, this isn't a big bug, but it's very confusing to try and debug.
Comment #30
hass CreditAttribution: hass commentedThe above patch have been committed before final D6. But i have no more used the feature except the panels 6.x-1.x port.
Comment #31
Pasqualleconfirmed. when putting garbage into #value the image_button handling fails..
simplified test attached
Comment #32
cquezel CreditAttribution: cquezel commentedThis is similar to http://drupal.org/node/359529 you might want to set it as a duplicate entry
Comment #33
Damien Tournoud CreditAttribution: Damien Tournoud commentedMarked #359529: _form_button_was_clicked returns the wrong value as a duplicate.
Comment #34
Sid_M CreditAttribution: Sid_M commentedHaving just fought with this for a while, and not having found clear documentation, I'm adding what seem like the key points for using multiple image_buttons in a form:
1) Do give each image_button a unique #name (unlike regular buttons, you can't have several image_buttons all named op).
2) Don't give an image_button a #default_value.
3) Don't give an image_button a #value
4) Do give each image_button a #return_value. This is the same as what you would assign to #value if IE6 problems hadn't forced Drupal to implement some unusual element handling. If you don't assign this, it will default to true.
5) Do use $form_state['clicked_button']['#value'] to find the #value of, well, the clicked image_button. This field will contain the value of #return_value for the clicked image_button.
Comment #35
vodde83 CreditAttribution: vodde83 commentedI had to create a table, with at the end of each row, 3 buttons. Each button changed the status of the item either to approved, disapproved, or on hold.
After reading this post, I did this. Don't know if it's really the way to go, but it works :)
3 buttons per row, each with a unique name, and as return_value the action name + the record id.
I then did this in the submit :
And now I can do the $action, based on the $record I got.
Comment #36
cquezel CreditAttribution: cquezel commentedvodde83,
this is similar to what I did but notice that #name is not a publicly available property. Also note that #return_value is not documented for image_button.
heine (http://drupal.org/user/17943) suggested I use the tree property when dealing with arrays. I did this successfully. Your explode logic is an analogy to an enhancement I suggested where tree named button names should be parsed by Drupal
See my issue http://drupal.org/node/362249
Comment #37
advseb CreditAttribution: advseb commented@#34: In my case it is enough to just multiple image buttons as follows:
If I add #value, clicked_button always returns the last button in the form.
Comment #38
jcfiala CreditAttribution: jcfiala commentedI'm not sure what the expected status of this is at the moment, but I tried converting the two buttons on the cart form for ubercart over to image_buttons, and no matter what I did, it kept saying the clicked_button was the second one (checkout). I tried setting them to using different #submit arrays, and even still it would only call the #submit functions for the checkout button.
Comment #39
dazweeja CreditAttribution: dazweeja commentedThe information in #34 works perfectly.
If this issue is not going to be patched, at the very least it would be nice to see a rewording of the documentation of image_button in then Forms API Reference to contain the information in #34 (and an example).
Comment #40
ari-meetai CreditAttribution: ari-meetai commentedusing #name worked here. Thank you.
Comment #41
Jztinfinity CreditAttribution: Jztinfinity commentedI had exactly the same issue with the ubercart buttons, and I tried following #34 but it didn't work - then I realized the issue is that you need to enforce those "do not's" from #34 - in my case the "do not set a #value for an image button". What I mean is, when altering a form, just because you don't set the "#value" field, doesn't mean it isn't already set. Thus in my case, I had to run unset($form['field_name']['#value']) on each of the image button fields.
All of these operations are of course counter-intuitive and really should be fixed.
Comment #42
marcvangendI just ran into this problem in Drupal 7. The points in #34 were a great help. I only needed to set #return_value instead of #value. It seems like D7 automatically gives different names to different image buttons.
If this is going to be improved/fixed, we need to do it in 8.x-dev first and then backport to earlier versions.
Comment #43
Agileware CreditAttribution: Agileware commentedThanks again for #34.
Subscribing.
Comment #44
aandrei CreditAttribution: aandrei commentedThe issue still persists in Drupal 7 if image buttons are used through AJAX calls. I isolated the problem in function _form_button_was_clicked in file form.inc/2031 where the elseif is true for all image buttons that carry a value. I believe if this code is used (in line 2045):
instead of:
then the issue will be fixed.
Comment #45
David_Rothstein CreditAttribution: David_Rothstein commentedI think the remaining work here is covered by other issues (both of which already have patches):
#873070: When an image button appears after another button in a form, the wrong triggering element and #submit handlers are detected
#1452894: Elements with #has_garbage_value and #value are always set as a triggering element
So, tentatively moving this back to Drupal 6 and closing.