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
}
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

hass’s picture

Priority: Normal » Critical

Marking 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.

$form_state['clicked_button']
A full copy of the button element that was clicked to submit the form. This is more reliable than the old $form_values['op'] name, and also carries any additional information that was placed in the button element's form definition.

merlinofchaos’s picture

You 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.

hass’s picture

But 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?

hass’s picture

I tried to add an additional layout value:

$form[$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>',
        '#layout' => $id,
      );

But the posted result does not contain the correct value, too.

["#layout"]=> string(12) "twocol_75_25"

hass’s picture

I tried both IE6 and Firefox 2.0.

i found this in form.inc:

// When image buttons are clicked, browsers do NOT pass the form element
// value in $_POST. Instead they pass an integer representing the
// coordinates of the click on the button image. This means that image
// buttons MUST have unique $form['#name'] values, but the details of
// their $_POST data should be ignored.

but this requirement is fulfilled. See the following HTML:

<form action="/drupal6/index.php?q=admin/build/panels/add"  accept-charset="UTF-8" method="post" id="panels-add-page-form">
<div><fieldset><legend>Layouts</legend><div class="description">Choose a layout for your new page from the list below.</div><div class="layout-link"><input type="image" name="fourcol_25_25_25_25" value="fourcol_25_25_25_25" id="edit-fourcol-25-25-25-25"  class="form-submit" src="/drupal6/sites/all/modules/panels/layouts/fourcol_25_25_25_25.png" alt="Layout 4 Spalten mit 25/25/25/25 Teilung" title="Layout 4 Spalten mit 25/25/25/25 Teilung" />
<div>4 Spalten mit 25/25/25/25 Teilung</div></div><div class="layout-link"><input type="image" name="threecol_33_33_33" value="threecol_33_33_33" id="edit-threecol-33-33-33"  class="form-submit" src="/drupal6/sites/all/modules/panels/layouts/threecol_33_33_33.png" alt="Layout 3 Spalten mit 33/33/33 Teilung" title="Layout 3 Spalten mit 33/33/33 Teilung" />
<div>3 Spalten mit 33/33/33 Teilung</div></div><div class="layout-link"><input type="image" name="twocol_25_75" value="twocol_25_75" id="edit-twocol-25-75"  class="form-submit" src="/drupal6/sites/all/modules/panels/layouts/twocol_25_75.png" alt="Layout 2 Spalten mit 25/75 Teilung" title="Layout 2 Spalten mit 25/75 Teilung" />
<div>2 Spalten mit 25/75 Teilung</div></div><div class="layout-link"><input type="image" name="twocol_33_66" value="twocol_33_66" id="edit-twocol-33-66"  class="form-submit" src="/drupal6/sites/all/modules/panels/layouts/twocol_33_66.png" alt="Layout 2 Spalten mit 33/66 Teilung" title="Layout 2 Spalten mit 33/66 Teilung" />
<div>2 Spalten mit 33/66 Teilung</div></div><div class="layout-link"><input type="image" name="twocol_38_62" value="twocol_38_62" id="edit-twocol-38-62"  class="form-submit" src="/drupal6/sites/all/modules/panels/layouts/twocol_38_62.png" alt="Layout 2 Spalten mit 38/62 Teilung" title="Layout 2 Spalten mit 38/62 Teilung" />
<div>2 Spalten mit 38/62 Teilung</div></div><div class="layout-link"><input type="image" name="twocol_50_50" value="twocol_50_50" id="edit-twocol-50-50"  class="form-submit" src="/drupal6/sites/all/modules/panels/layouts/twocol_50_50.png" alt="Layout 2 Spalten mit 50/50 Teilung" title="Layout 2 Spalten mit 50/50 Teilung" />

<div>2 Spalten mit 50/50 Teilung</div></div><div class="layout-link"><input type="image" name="twocol_62_38" value="twocol_62_38" id="edit-twocol-62-38"  class="form-submit" src="/drupal6/sites/all/modules/panels/layouts/twocol_62_38.png" alt="Layout 2 Spalten mit 62/38 Teilung" title="Layout 2 Spalten mit 62/38 Teilung" />
<div>2 Spalten mit 62/38 Teilung</div></div><div class="layout-link"><input type="image" name="twocol_66_33" value="twocol_66_33" id="edit-twocol-66-33"  class="form-submit" src="/drupal6/sites/all/modules/panels/layouts/twocol_66_33.png" alt="Layout 2 Spalten mit 66/33 Teilung" title="Layout 2 Spalten mit 66/33 Teilung" />
<div>2 Spalten mit 66/33 Teilung</div></div><div class="layout-link"><input type="image" name="twocol_75_25" value="twocol_75_25" id="edit-twocol-75-25"  class="form-submit" src="/drupal6/sites/all/modules/panels/layouts/twocol_75_25.png" alt="Layout 2 Spalten mit 75/25 Teilung" title="Layout 2 Spalten mit 75/25 Teilung" />
<div>2 Spalten mit 75/25 Teilung</div></div></fieldset>
<input type="hidden" name="form_build_id" id="form-05800bc16e01241bb800137f6d5a7a36" value="form-05800bc16e01241bb800137f6d5a7a36"  />
<input type="hidden" name="form_token" id="edit-panels-add-page-form-form-token" value="add97c15fe7c7f749af8385bab5c6ed4"  />
<input type="hidden" name="form_id" id="edit-panels-add-page-form" value="panels_add_page_form"  />

</div></form>
hass’s picture

I'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.

  // When image buttons are clicked, browsers do NOT pass the form element
  // value in $_POST. Instead they pass an integer representing the
  // coordinates of the click on the button image. This means that image
  // buttons MUST have unique $form['#name'] values, but the details of
  // their $_POST data should be ignored.
  elseif (!empty($form['#has_garbage_value']) && isset($form['#value']) && $form['#value'] !== '') {
    return TRUE;
  }

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.

array(5) {
  ["storage"]=>
  NULL
  ["submitted"]=>
  bool(true)
  ["values"]=>
  array(9) {
    ["threecol_25_50_25"]=>
    string(17) "threecol_25_50_25"
    ["threecol_25_50_25_stacked"]=>
    string(25) "threecol_25_50_25_stacked"
    ["threecol_33_34_33"]=>
    string(17) "threecol_33_34_33"
    ["threecol_33_34_33_stacked"]=>
    bool(true)
    ["twocol"]=>
    string(6) "twocol"
    ["twocol_stacked"]=>
    string(14) "twocol_stacked"
    ["form_build_id"]=>
    string(37) "form-2cfca3fa9626ca544e000dad270b590d"
    ["form_token"]=>
    string(32) "add97c15fe7c7f749af8385bab5c6ed4"
    ["form_id"]=>
    string(20) "panels_add_page_form"
  }
  ["clicked_button"]=>
  array(26) {
    ["#type"]=>
    string(12) "image_button"
    ["#title"]=>
    string(36) "Layout Three column 33/34/33 stacked"
    ["#default_value"]=>
    string(25) "threecol_33_34_33_stacked"
    ["#src"]=>
    string(62) "sites/all/modules/panels/layouts/threecol_33_34_33_stacked.png"
    ["#prefix"]=>
    string(25) "
" ["#suffix"]=> string(46) "
Three column 33/34/33 stacked
"
    ["#post"]=>
    array(6) {
      ["threecol_33_34_33_stacked_x"]=>
      string(2) "36"
      ["threecol_33_34_33_stacked_y"]=>
      string(2) "48"
      ["threecol_33_34_33_stacked"]=>
      string(25) "threecol_33_34_33_stacked"
      ["form_build_id"]=>
      string(37) "form-74a181c5f46c3446285108d158820e57"
      ["form_token"]=>
      string(32) "add97c15fe7c7f749af8385bab5c6ed4"
      ["form_id"]=>
      string(20) "panels_add_page_form"
    }
    ["#programmed"]=>
    bool(false)
    ["#tree"]=>
    bool(false)
    ["#parents"]=>
    array(1) {
      [0]=>
      string(25) "threecol_33_34_33_stacked"
    }
    ["#array_parents"]=>
    array(2) {
      [0]=>
      string(6) "layout"
      [1]=>
      string(25) "threecol_33_34_33_stacked"
    }
    ["#weight"]=>
    float(0.003)
    ["#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(25) "threecol_33_34_33_stacked"
    ["#id"]=>
    string(30) "edit-threecol-33-34-33-stacked"
    ["#value"]=>
    bool(true)
    ["#needs_validation"]=>
    bool(true)
  }
  ["redirect"]=>
  NULL
}
Gábor Hojtsy’s picture

Hass, I am trying to understand what is going on here, but from the dump you have above in the report, you have:

    ["#has_garbage_value"]=> bool(true)
    ["#value"]=> string(12) "twocol_75_25"

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.

merlinofchaos’s picture

You 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.

Gábor Hojtsy’s picture

Priority: Critical » Normal
Status: Active » Closed (works as designed)

Looks like this is by-design. Reopen if merlinofchaos' tip did not solve the problem.

merlinofchaos’s picture

Priority: Normal » Critical
Status: Closed (works as designed) » Active
merlinofchaos’s picture

Priority: Critical » Minor
Status: Active » Needs review
FileSize
847 bytes

Whoops, that wasn't supposed to happen.

Try this patch. It prevents #default_value propagation if #has_garbage_value is set.

hass’s picture

@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:

$form[$id] = array(
        '#type' => 'image_button',
        '#title' => t('Layout @title', array('@title' => $layout['title'])),
        '#src' => $file,
        '#prefix' => '<div class="layout-link">',
        '#suffix' => '<div>'. $layout['title'] .'</div></div>',
      );

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.

merlinofchaos’s picture

It'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.

Gábor Hojtsy’s picture

hass: 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?

merlinofchaos’s picture

BTW 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.

hass’s picture

Status: Needs review » Needs work

Parse error: syntax error, unexpected ')', expecting ']' in includes\form.inc on line 964

webernet’s picture

Status: Needs work » Needs review
FileSize
690 bytes
hass’s picture

Status: Needs review » Needs work

Looks 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.

hass’s picture

Status: Needs work » Needs review

Sorry... setting back status. Aside - patch worked for me with #default_value defined.

Pasqualle’s picture

maybe this is related http://drupal.org/node/209574
the last patch is missing one parenthesis, and does not solved my problem..

hass’s picture

For 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.

hass’s picture

Status: Needs review » Reviewed & tested by the community

Patch worked for me.

Aside i'd like to remind someone having permission to fix the docs as described in #18

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Needs work

Hass, #17 still looks like having a parse error, so I doubt you tested the patch.

hass’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
723 bytes

Damn! 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.

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Fixed

Thanks, committed with this added documentation:

      // Avoid image buttons (which come with garbage value), so we only get value
      // for the button actually clicked.
Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.

phiz118’s picture

Status: Closed (fixed) » Postponed (maintainer needs more info)

It 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

function test_form_menu() {
  $items['test_form/my_test'] = array(
    'title' => t('Test Form'),
    'page callback' => 'gen_test_form',
    'access arguments' => array('access test_gen'),
    'description' => t('Test Form'),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

function gen_test_form() {
  $content = drupal_get_form('test_form');
  return $content;
  
}
   
function test_form($form_state) {
  // Access log settings:
  $form['#theme'] = 'test_form_setup';
  $rows_per_page = 50;
	$header = array(
		array('data' => t('Delete'))
	);
  
	for ( $counter = 0; $counter <= 5; $counter++) {
	    $form['delete'][$counter] = array(
			//'#type' => 'submit',
			'#type' => 'image_button',
			'#value' => 'Submit',
			'#src' => 'sites/default/files/images/delete.png',
			'#name' => 'delete'.$counter,
			'#submit' => array('test_form__delete_submit'),
		);
   }
   
   $form['header'] = array(
	    '#type' => 'value',
	    '#value' => $header
	  );
  
  return $form;
}

function test_form__delete_submit($form, &$form_state)
{
	drupal_set_message($form_state['clicked_button']['#name']." Button pressed");
}

function theme_test_form_setup(

$form) {
	$rows = array();
	foreach (element_children($form['delete']) as $key) {
	    $row = array();
	    $row['data'][0] = drupal_render($form['delete'][$key]);
	    $rows[] = $row;
	}
	
	$output = theme('table', $form['header']['#value'], $rows);
	$output .= drupal_render($form);
	return $output;
}

function test_form_theme()
{
	return array(
		'test_form_setup' => array(
			'arguments' => array('form' => NULL),
			),
	);
}
hass’s picture

Status: Postponed (maintainer needs more info) » Closed (fixed)

This issue is solved. See the examples.

phiz118’s picture

Version: 6.x-dev » 6.2
Status: Closed (fixed) » Postponed (maintainer needs more info)

earnie 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.

hass’s picture

The above patch have been committed before final D6. But i have no more used the feature except the panels 6.x-1.x port.

Pasqualle’s picture

Version: 6.2 » 6.x-dev
Priority: Minor » Normal
Status: Postponed (maintainer needs more info) » Active
FileSize
1.41 KB

confirmed. when putting garbage into #value the image_button handling fails..

simplified test attached

cquezel’s picture

This is similar to http://drupal.org/node/359529 you might want to set it as a duplicate entry

Damien Tournoud’s picture

Sid_M’s picture

Having 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.

vodde83’s picture

I 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 :)

        $form['approve'][$records->id] = array(
          '#name' => 'approve_' . $records->id,
          '#type' => 'image_button',
          '#submit' => array('sales_overview_status_submit'),
          '#src' => path_to_theme() . '/images/approve.gif',
          '#attributes' => array('class' => 'approve'),
          '#return_value' => 'approve_' . $records->id,
        );
        $form['disapprove'][$records->id] = array(
          '#name' => 'disapprove_' . $records->id,        
          '#type' => 'image_button',
          '#submit' => array('sales_overview_status_submit'),
          '#src' => path_to_theme() . '/images/disapprove.gif',
          '#attributes' => array('class' => 'disapprove'), 
          '#return_value' => 'disapprove_' . $records->id,                                       
        );
        $form['onhold'][$records->id] = array(
          '#name' => 'onhold_' . $records->id,        
          '#type' => 'image_button',
          '#submit' => array('sales_overview_status_submit'),
          '#src' => path_to_theme() . '/images/onhold.gif', 
          '#attributes' => array('class' => 'onhold'), 
          '#return_value' => 'onhold_' . $records->id,                           
        ); 

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 :

function sales_overview_status_submit($form_id, $form_values) {

    $button = $form_values['clicked_button']['#value'];
    $values = explode('_',$button);
    
    list($action, $record) = $values;
    
    drupal_set_message($action . ' - ' . $record);    
}

And now I can do the $action, based on the $record I got.

cquezel’s picture

vodde83,
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

advseb’s picture

@#34: In my case it is enough to just multiple image buttons as follows:

  $form['button1'] = array(
    '#type' => 'image_button',
    '#src' => 'url/button1.gif',
  );

  $form['button2'] = array(
    '#type' => 'image_button',
    '#src' => 'url/button2.gif',
  );

If I add #value, clicked_button always returns the last button in the form.

jcfiala’s picture

I'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.

dazweeja’s picture

The 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).

ari-meetai’s picture

using #name worked here. Thank you.

Jztinfinity’s picture

I 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.

marcvangend’s picture

Version: 6.x-dev » 8.x-dev

I 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.

Agileware’s picture

Thanks again for #34.

Subscribing.

aandrei’s picture

The 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):

  elseif (!empty($element['#has_garbage_value']) && isset($element['#value']) && $element['#value'] !== '') {
	if (!empty($form_state['input']['_triggering_element_name']) && $element['#name'] == $form_state['input']['_triggering_element_name']) {
		return TRUE;
	}
  }

instead of:

  elseif (!empty($element['#has_garbage_value']) && isset($element['#value']) && $element['#value'] !== '') {
	return TRUE;
  }

then the issue will be fixed.

David_Rothstein’s picture

Version: 8.x-dev » 6.x-dev
Status: Active » Fixed

I 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.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.