Autocomplete Path für eigenes Field (mit Drupal 7.39)

veröffentlicht von gngn am Fr., 16.10.2015 - 14:40

Schnell mal ein node field durch ein Autocomplete aufpeppen - kein Problem. Dachte ich, hatte ich doch schon gemacht und die Suchmaschine meines Vetrauens spuckt zu "drupal 7 autocomplete" auch mehr als genug Treffer aus. Im wesentlichen mit hook_menu() einen Pfad setzen und diesen mit hook_form_alter() als #autocomplete_path einstellen. Aber es funktionierte trotzdem einfach nicht...

Die kurze Lösung: seit Drupal 7.39 müssen wir #autocomplete_input setzen bzw. form_process_autocomplete() nutzen.

Ausführlicher: die im Netz zu findenen Lösungen (z.B. 1, 2 oder 3) funktionieren nicht mehr seit Drupal 7.39, das u.a. ein Security Update zu Cross-site Scripting - Ajax system enthält. Seitdem muss zusätzlich zu #autocomplete_path noch #autocomplete_input gesetzt werden. Das geschieht am besten in einer After-build mit der Funktion form_process_autocomplete().

Der Reihe nach - am Beispiel eines Text fields, nennen wir es myfield, das im Content type mycontenttype vorkommt:

  1. Pfad für autocomplete mit hook_menu() setzen:
    function MYMODULE_menu() {
      $items['some/path'] = array(
        'title' => 'My Autocomplete',
        'page callback' => 'mymodule_my_autocomplete',
        'type' => MENU_CALLBACK
      );
      return $items;
    }
  2. Die eigentliche Autocomplete-Funktion erstellen (die eben als page callback eingestellt wurde):
    function mymodule_my_autocomplete($string) {
      // Treffer zu $string setzen
      // z.B. die ersten 10 Nodes deren Titel mit $string beginnen
      $results = array();                                                         
      $result = db_query_range(
        'SELECT nid, title FROM {node} WHERE title LIKE :s ORDER BY title',
        0, 10, array(':s' => $string . '%')
      );
      while ($node = db_fetch_object($result)) {                                
        $key = t('@title [nid @nid]',
          array('@title' => $node->title, '@nid' => $node->nid)
        );
        $results[$key] = $node->title;
      }
    
      // Return the result to the form in json
      drupal_json_output($return);
    }
    Die Funktion liefert also zu einer Eingabe ein JSON-Array mit den in der Auswahl anzuzeigenden Werten als values und den im Endeffekt zu setzenden Werten als keys.
  3. After-build Funktion für den content-Type einstellen:
    function mymodule_form_alter(&$form, &$form_state, $form_id) {
      if ($form_id == 'mycontenttype_node_form') {
        $form['#after_build'][] = 'mymodule_myafter_build';
      }
    }
  4. After-build Funktion erstellen und dort das Autocomplete eintragen:
    function _mymodule_myafter_build($form, &$form_state) {
      $form['field_myfield'][LANGUAGE_NONE][0]['value']['#autocomplete_path'] = 'some/path';
      $form['field_myfield'][LANGUAGE_NONE][0]['value'] = form_process_autocomplete(
        $form['field_myfield'][LANGUAGE_NONE][0]['value']
      );
    }
    Dabei wird zunächst #autocomplete_path auf den oben im hook_menu() eingetragenen Pfad gesetzt (hier 'some/path'). Vor Drupal 7.39 war damit alles erledigt (und wir hätten es auch direkt im hook_form_alter() setzen können).
    Ab Drupal 7.39 wird zur Sicherheit noch #autocomplete_input benötigt. Das setzen wir meines Wissens nach am besten mit dem Aufruf von form_process_autocomplete(). Da form_process_autocomplete() ein gesetztes "#id" erfordert, rufen wir es erst via after_build auf.

Das war's ;)

Neuen Kommentar hinzufügen