6

When I'm using #states to set the visibility of a form field I'm checking an input element for its value. Is there then any way to grab the selected value the moment it's selected?

In the working sample below I'm displaying some markup when a select list's value != '_none'. It works good so far. But how do I get the markup to display the value I selected?

Background is: it's a node reference select list and I'm trying to maybe load some fields from the selected node as preview inside the markup. The moment I'm writing this I think it's a stupid idea. I'm in Ajax with #states, right? And there might be no way to call node_load() or anything the like, right?

/**
 * Implements hook_form_alter().
 */
function MY_MODULE_form_alter(&$form, &$form_state, $form_id) {

  if ($form_id == 'MY_FORM') {

    $form['my_container'] = [
      '#type'   => 'container',
      '#states' => [
        'visible' => [
          ':input[name="my_field_name[und]"]' => ['!value' => '_none'],
        ],
      ],
    ];

    $form['my_container']['markup'] = [
      '#type'   => 'markup',
      '#markup' => /* selected value here */ ,
    ];
  }
}
  • 2
    This should be easily achievable using the Ajax framework. You can still show/hide the item using #states but the preview part should work using #ajax – Beebee Feb 17 '15 at 17:22
5

Drupal #states is nothing more than the page containing JS data, and states.js reading them and adding necessary JS events to hide/show/etc fields. At the moment, there is no #states based method to get the selected value.

Note that it's perfectly OK to add #states to elements that are passed through Ajax. The beauty is that, whenever something containing #states is rendered, Drupal pipes these JS data along with the Ajax response. Since behaviours are run everytime after an Ajax response, states.js can update its visibility rules even for Ajax-changed elements.

I think your solution would be to use #ajax to do this. Your [#ajax]['callback'] will contain just-selected values in $form_state['input'], so you can use them.

2

Thanks @AyeshK and @Beebee for pointing me in the right direction. Here is how I finally got hold of the selected value and displayed it via an ['#ajax']['callback'] I attached to the node_reference select list. From there on it's quite simple to modify the markup to more advanced needs like displaying a preview of a node or a field.

In the end you might want to add a second wrapper with the same ID to hold the default value when editing an existing node.

/**
 * Implements hook_form_alter().
 */
function MY_MODULE_form_alter(&$form, &$form_state, $form_id) {

    if ($form_id == 'MY_FORM') {

        // add an Ajax callback to the select list and define a wrapper the action should happen in
        $form['field_node_reference'][LANGUAGE_NONE]['#ajax']['callback'] = '_MY_MODULE_ajax_callback';
        $form['field_node_reference'][LANGUAGE_NONE]['#ajax']['wrapper'] = 'MY-ID';

        // create a wrapper
        $form['MY_WRAPPER'] = array(
            '#type' => 'markup',
            '#prefix' => '<div id="MY-ID">',
            '#suffix' => '</div>',
            '#weight' => 3,
            );

        // do some magic
        if (isset($form_state['values']['field_node_reference'][LANGUAGE_NONE][0]['nid']) && $form_state['values']['field_node_reference'][LANGUAGE_NONE][0]['nid'] != '') {

            $nid = $form_state['values']['field_node_reference'][LANGUAGE_NONE][0]['nid'];
            $form['MY_WRAPPER']['#markup'] = t('You selected node number: @nid', array('@nid' => $nid));
        }
    }
}

function _MY_MODULE_ajax_callback(&$form, &$form_state) {
    // return the wrapper
    return $form['MY_WRAPPER'];
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.