Drupal: Form API und Ajax

Norman Kämper-Leymann, 20 February 2015
  • Drupal
  • Drupal 7
  • Form API
  • Ajax
  • #ajax
  • callback
  • onchange
  • value

Wie man in Form API per Ajax den gewählten Wert einer Select List onchange ausgeben kann

Heute zeigt euch Berlin-Coding wie man in einem Drupal Formular einen gerade ausgewählten Wert abgreifen und mit Hilfe eines Ajax callbacks gleich wieder ausgeben und darstellen kann. Eine konkrete Verwendungsmöglichkeit wäre die Preview einer Node oder einer Entity direkt neben einer Node Reference/Entity Reference select List.

In einem kleinen custom Module klingt ihr euch per hook_form_alter() oder hook_form_FORM_ID_alter() in die *_node_form eines Inhaltstypen ein. Im zweiten Schritt hängt ihr der entsprechenden select List einen Callback und einen Wrapper an. Der Wrapper ist dazu da, um einen Ort zu definieren, wohin die Ergebnisse dann ausgegeben werden sollen. Der Callback selbst gibt eigentlich nur den Wrapper aus, sobald in der Select Liste ein Wert ausgewählt wurde. Die eigentliche Magic passiert in einer if-Abfrage, die genau dann greift, wenn betreffende Werte aus der Select Liste in den $form_state['values'] auftauchen, und die in diesem Falle das ['#markup'] der bereits erstellen Wrapper befüllt.

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

  if ($form_id == 'product_line_node_form') {

    // add callback and wrapper in the right place
    $form['field_product_image'][LANGUAGE_NONE]['#ajax']['callback'] = '_node_reference_preview_ajax_callback';
    $form['field_product_image'][LANGUAGE_NONE]['#ajax']['wrapper'] = 'node-reference-preview';

    $form['node_reference_preview_wrapper'] = array(
      '#type' => 'markup',
      '#prefix' => '<div id="node-reference-preview">',
      '#suffix' => '</div>',
      '#weight' => 3,
      );

    // second wrapper for default value, markup replaces itself onchange
    $form['node_reference_default_preview_wrapper'] = array(
      '#type' => 'markup',
      '#prefix' => '<div id="node-reference-preview">',
      '#suffix' => '</div>',
      '#weight' => 3,
      );

    // onchange
    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['node_reference_preview_wrapper']['#markup'] = _node_reference_preview_image($nid);
    }

    // default
    if (isset($form['field_node_reference']['und']['#default_value'][0])) {
      $nid = $form['field_node_reference']['und']['#default_value'][0];
      $form['node_reference_default_preview_wrapper']['#markup'] = _node_reference_preview_image($nid);
    }
  }
}

// Ajax callback function
function _node_reference_preview_ajax_callback(&$form, &$form_state) {
  return $form['node_reference_preview_wrapper'];
}

// helper function to render field_image from given $nid
function _node_reference_preview_image($nid) {
  $node = node_load($nid);
  $image = field_get_items('node', $node, 'field_image');
  $output = field_view_value('node', $node, 'field_image', $image[0], array(
    'type' => 'image',
    'settings' => array(
      'image_style' => 'thumbnail',
      ),
    )
  );
  return render($output);
}

Zieht euch unbedingt auch den Artikel von DeckFifty rein. Da gibt’s das ganze nochmal als etwas simpleres Beispiel. Den Code dort kann man sich einfach in sein eigenes Modul kopieren, der funktioniert out-of-the-box als lebendes Beispiel sozusagen.