Créer un champ texte avec auto-complétion en utilisant la form Api

Créer un champ texte avec auto-complétion en utilisant la form Api

11 Apr 2011 |  Drupal

Voici un petit bout de code et quelques explications afin de créer un champ texte avec auto-complétion pour vos formulaire en utilisant la form api de Drupal.

Dans l’exemple suivant nous allons créer un formulaire avec un champ texte qui permettra de sélectionner un noeud parmi tous les contenus publiés sur le site. Pour pimenter l’exercice on permettra à notre utilisateur de saisir plusieurs valeurs, comme il est possible de faire dans un champ tag de taxonomie.

Étape 1 : Création de la fonction de récupération de informations

La première chose à faire consiste à créer une fonction de callback afin de récupérer les titres des nodes en base de données que l’on renverra par la suite au format json.

/*
* Callback de récupération des titres des noeuds.
*/
function mymodule_autocomplete_node_title($key = '') {
  $ret = array();

  // L'utilisateur insère une liste de tag séparés par des virgules et
  // on ne traite que le dernier tag.
  $keys = drupal_explode_tags($key);

  // Récuperation du dernier tag en cour de saisie par l'utilisateur.
  $last_string = trim(array_pop($keys));

  if (!empty($last_string)) {
    $sql = "SELECT DISTINCT (n.nid), n.title
           FROM {node} n
           WHERE status = 1
           AND UPPER(n.title) LIKE UPPER('%%%s%%')
           ORDER BY n.title ASC";

    $query = db_query_range($sql, $last_string, 0, 10);

    // Récupération des valeurs saisies précédemment.
    $prefix = !empty($keys) ? implode(', ', $keys) . ', ' : '';

    // Génération de la liste de résultats à renvoyer.
    while ($row = db_fetch_array($query)) {
     $ret[$prefix . $row['nid']] = check_plain($row['title']);
    }

    // Transformation des résultats au format Json, suivi d'un exit pour
    // être sûr que l'on ne renverra rien du thème.
    drupal_json($ret);
    exit();
  }
}

Lorsque vous faites des comparaisons entres des chaînes de caractères pensez à tout mettre en minuscule ou majuscule si vous ne voulez pas prendre en compte la casse, ça vous permettra d’être plus tolérant sur l’orthographe. Il est préférable de limiter le jeu de résultats obtenus, d’une part parce que ça ne nous servirait à rien d’afficher une liste de 400 titres et d’autre part, cela consommerait plus de ressources de base de données. Ainsi pour limiter ma requête j’ai utilisé la fonction db_query_range() au lieu de mettre directement une limite dans ma requête.

Étape 2 : Ajout d’une nouvelle entrée dans le menu

Maintenant que nous avons crée la récupération des titres des noeuds, il nous faut ajouter une entrée de menu pour que les données renvoyées par la fonction soit accessible depuis une url.

/**
* Implementation of hook_menu().
*
* @return An array of menu items.
*/
function mymodule_menu() {
  $items = array();
  // Url de récupération des titres des nodes pour l'auto-complétion.
  $items['mymodule/autocomplete/node_title'] = array(
    'page callback' => 'mymodule_autocomplete_node_title',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK
  );
  return $items;
}

N’oubliez pas qu’après chaque modification du menu il est nécessaire de flusher le cache :) Pour tester si vous obtenez bien des résultats, rendez-vous sur l’url que vous avez créée dans le hook_menu suivi d’un / et d’un caractère pour simuler la frappe d’un utilisateur. Ce qui donne par exemple : mymodule/autocomplete/node_title/a

Étape 3 : Paramétrage du formulaire

La dernière étape, vous l’aurez deviné si vous avez tout suivi, c’est la création du formulaire.

/*
* Formulaire custom de selection de nodes.
*/
function mymodule_listing_nodes_form() {
  $form = array();
  $form['nids'] = array(
    '#type' => 'textfield',
    '#title' => t('Sélectionnez vos contenus'),
    // Il est important de donner l'url de récupération des titres sinon ça ne marche pas...
    '#autocomplete_path' => 'mymodule/autocomplete/node_title',
  );
  return $form;
}

Le secret réside dans le fait de configurer l’option #autocomplete_path du widget textfield en lui paramétrant une url et c’est tout!

Voilà, vous savez maintenant créer des champs textes avec auto-complétion et au final c’était pas bien compliqué! :) Je suis sûr que vous avez déjà tout compris mais bon au cas où et histoire de rentabiliser l’espace disque de mon hébergement voici les sources de cet exemple (une grand première dans l’histoire de ce blog).

Bonus

Petite astuce pendant que l’on parle d’auto-complétion. Certains naviguateurs proposent d’utiliser les réponses que vous avez déjà saisies auparavant comme votre nom, prénom et autres, mais parfois vous ne voulez pas autoriser ça dans vos forms. Et bien pour désactiver ça il vous suffit de définir la complétion du champ à off et le tour est joué.

$form['name'] = array(
  '#type' => 'textfield',
  '#attributes' => array('autocomplete' =>'off'),
);
Julien Dubreuil

Vous avez une idée, un projet web à réaliser ?

Ensemble, mettons en oeuvre sa réussite. Je vous accompagne dans vos projets, depuis l'élaboration du cahier des charges jusqu'à la mise en production. Pour plus d'information n'hésitez pas à me contacter.

Contactez-moi