When using integer options for select and radio form fields, the states system fails for dependent form fields operating with integer values.

For example:

<?php
define
('OPTION_1', 1);
define('OPTION_2', 2);
function
example_form(&$form, $form_state) {
 
$form['select'] = array(
   
'#type' => 'select',
   
'#options' => array(
     
OPTION_1 => 'Option 1',
     
OPTION_2 => 'Option 2',
    ),
  );
 
$form['dependent_field'] = array(
   
'#type' => 'text',
   
'#states' => array(
     
'visible' => array(
       
':input[select]' => array('value' => OPTION_1)
      ),
    ),
  );
}
?>

Fails because $(':input[select]').val() == '1' not 1, and the states system checks to make sure the values are the same type. The way around it is to type cast the dependent_field state value as a string:

<?php
  $form
['dependent_field'] = array(
   
'#type' => 'text',
   
'#states' => array(
     
'visible' => array(
       
':input[select]' => array('value' => (string) OPTION_1)
      ),
    ),
  );
?>

but is there a better way to approach this? It's not exactly intuitive to make the value a string.

Files: 
CommentFileSizeAuthor
#18 drupal-879580-18-fix_states_integer_values.patch847 bytesanon
PASSED: [[SimpleTest]]: [MySQL] 40,758 pass(es).
[ View ]
#8 drupal-879580-8-fix_states_integer_values.patch755 bytesarithmetric
PASSED: [[SimpleTest]]: [MySQL] 33,635 pass(es).
[ View ]
#5 drupal-879580-5-fix_states_integer_values.patch475 bytesarithmetric
PASSED: [[SimpleTest]]: [MySQL] 33,573 pass(es).
[ View ]

Comments

Probably not - this bug is most likely caused by PHP integer to JSON conversion (i.e., when #states get converted into Drupal.settings).

Subscribe

Version:7.x-dev» 8.x-dev
Status:Active» Needs review
StatusFileSize
new475 bytes
PASSED: [[SimpleTest]]: [MySQL] 33,573 pass(es).
[ View ]

Attached is a patch against the 8.x branch to resolve this issue by altering the value comparison code in states.js.

With this patch, if the reference value (from the #states array) is numeric but the value from jQuery is a string, then the reference variable is cast as a string before the strict comparison in compare().

Status:Needs review» Reviewed & tested by the community

Looks clean and solves the problem for me. Thank you arithmetric.

Status:Reviewed & tested by the community» Needs review

Looks good. Wondering whether we could capture this non-obvious edge-case in an inline comment, to prevent people from interpreting this data type casting from number to string as a bug, and clarify what the casting is actually fixing, in case someone wants to rewrite/revamp this code at some point in the future.

StatusFileSize
new755 bytes
PASSED: [[SimpleTest]]: [MySQL] 33,635 pass(es).
[ View ]

@sun: Thanks for the feedback. I've updated the patch to include a comment on why the type casting should happen in this case.

Status:Needs review» Reviewed & tested by the community

Thanks!

Will this also be fixed for D7? The patch applies and works for 7.x.

Issue tags:+needs backport to D7

Changing to the "official" form of the backport tag.

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

Committed to 8.x, moving to 7.x for webchick.

Status:Reviewed & tested by the community» Fixed

Committed and pushed to 7.x. Thanks!

Status:Fixed» Closed (fixed)
Issue tags:-needs backport to D7

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

Issue summary:View changes
Status:Closed (fixed)» Needs work

This still doesn't work in IE 10+ in D7.

define('OPTION_1', 1);
define('OPTION_2', 2);
  $form['select'] = array(
    '#type' => 'select',
    '#options' => array(
      OPTION_1 => 'Option 1',
      OPTION_2 => 'Option 2',
    ),
  );
  $form['dependent_field'] = array(
    '#type' => 'textfield',
    '#states' => array(
      'visible' => array(
        'select' => array('value' => OPTION_1)
      ),
    ),
  );

It works in firefox and chrome tho.

Seems like an IE issue.
https://groups.google.com/forum/#!topic/coffeescript/lIgad5BWWEk

if (reference.constructor.name in states.Dependent.comparisons) {
In IE, the constructor.name is nonstandard, and it is not suported by IE.

That make the solution provided by #8 to not work at all in IE. In the article I linked to, are a nasty hack to fix this,but I', note sure of that should go into core.

Status:Needs work» Needs review
StatusFileSize
new847 bytes
PASSED: [[SimpleTest]]: [MySQL] 40,758 pass(es).
[ View ]

Submitted patch for Drupal 7.

I'm still unfamiliar width Drupal 8 and I don'y know how to make the test code in that version.

Thanks @anon. This was patched in Drupal 8 and Drupal 7, so please open a new issue instead for the current bug and upload your patch there. Also, to test Drupal 8 and see if the bug exists there, you can try simplytest.me http://simplytest.me/project/drupal/8.x

Status:Needs review» Closed (fixed)

Restoring status -- you can add a link to the new issue in the comments here so others find it. :)