Pour ce tutoriel, il est nécessaire d'avoir une base de données (a priori MySQL, mais peu importe le SGBDR). Dans cette base de données, nous avons une table qui liste des catégories hiérarchisées, sans limite de niveau. Concrètement, nous n'aurons que 2 listes, donc 2 niveaux, mais la table n'impose pas de limite théorique.
Je pars du principe, dans ce tutoriel, que nous utilisons une classe pour gérer la connexion à la base de données. Une classe du genre mysqli ou PDO. Mais cela reste facilement adaptable pour l'extension "classique" mysql (qui devient de plus en plus obsolète).
Nous aurons donc des méthodes compliquées que je ne détaillerai pas ici, comme $db -> query() ou encore $db -> fetch()...
Je pars du postulat que la connexion à la base de données se fait dans un fichier connexion_db.php que je ne détaille pas, puisqu'il varie d'un SGBDR à l'autre et d'une extension à l'autre (mysql, mysqli, PDO, voire même de packages comme PEAR::DB, etc)
Voici le code SQL permettant la création de la table, ainsi que de quoi la remplir un peu pour les exemples :
--
-- Structure de la table `categories`
--
CREATE TABLE IF NOT EXISTS `categories` (
`cat_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cat_parent_id` int(10) unsigned NOT NULL DEFAULT '0',
`cat_title` varchar(255) NOT NULL,
PRIMARY KEY (`cat_id`),
KEY `cat_parent_id` (`cat_parent_id`)
) ENGINE= MyISAM DEFAULT CHARSET=latin1;
--
-- Contenu de la table `categories`
--
INSERT INTO `categories` (`cat_id`, `cat_parent_id`, `cat_title`) VALUES
(1, 0, 'Musique'),
(2, 0, 'Films'),
(3, 0, 'Livres'),
(4, 1, 'Rock'),
(5, 1, 'Classique'),
(6, 1, 'Jazz'),
(7, 1, 'Pop'),
(8, 2, 'Horreur'),
(9, 2, 'Policier'),
(10, 2, 'Biopic'),
(11, 2, 'Documentaire'),
(12, 3, 'Biographie'),
(13, 3, 'Essai'),
(14, 3, 'Romantique');
Deuxième assertion pour ce tutoriel : nous utiliserons jQuery. Pourquoi ? D'abord parce que je ne suis pas développeur Javascript et que gérer un objet XmlHTTPRequest manuellement est le genre de chose dont je me dispense bien volontier. Ensuite parce que ça allège le code considérablement et que si vous souhaitez vraiment écrire tout le JS à la main, c'est que vous avez le niveau pour vous dispenser de ce tuto... (et toc :p )
Il est donc nécessaire d'ajouter sur votre page HTML le code de jquery, sinon le script JS que je donne dans la troisième partie ne fonctionnera pas ! Ca ressemble à une ligne comme ça :
<script type="text/javascript" src="/js/jquery-1.2.3.min.js" temp_src="/js/jquery-1.2.3.min.js"></script>
Ceci étant posé, commençons par les explications sur le fonctionnement de ce que nous allons mettre en place.
Nous avons un script qui génère notre formulaire. Peu importe que l'on utilise ou pas un moteur de template, un framework, le principe restera toujours le même : du (X)HTML dont une partie générée dynamiquement par PHP.
Nous aurons besoin d'un script PHP qui sera chargé de générer le contenu de la deuxième liste (uniquement celle-ci et de manière exclusive, c'est à dire que du code qui se place entre les balises <select> et </select>).
Il nous faudra également un script Javascript qui chargera le HTML généré par le précédent script et le chargera au bon endroit dans notre document.
1. Le script qui génère la deuxième liste : genere_liste.php
Hé oui, aussi surprenant que cela puisse paraître, on va commencer par celui-là, parce que ce script sera utilisé par les deux autres.
Ce script recevra en paramètre une variable cat_id qui est l'identifiant de la catégorie parente des éléments que nous souhaitons afficher. Si on sélectionne, dans la première liste, "Musique", on devra afficher dans la seconde liste Rock, Classique, Jazz et Pop. L'identifiant de la catégorie parente (Musique) est 1, c'est cette valeur que l'on va traiter.
Cet argument sera, a priori, passé en argument via une requête HTTP de type GET, donc, sera disponible dans la variable $_GET['cat_id']. Mais nous allons également prévoir le cas où il n'est pas défini et lui attribuer une valeur par défaut (1 : catégorie Musique). Si on affiche un formulaire de modification et qu'il faut sélectionner un autre élément de la liste que le premier, on prendra soin d'adapter le script en fonction (je ne le fais pas ici, car c'est un autre problème).
Pour la suite, nous admettrons que ce script se trouve au même niveau que celui qui génère le code HTML, c'est à dire à la racine du répertoire de publication web. Adaptez si vous souhaitez le ranger ailleurs. Attention : ce script doit IMPERATIVEMENT être accessible depuis le web, donc être dans ou sous le répertoire de publication web. Sinon, les requêtes faites par Javascript ne fonctionneront pas.
Voici à quoi ressemble ce script :
<?php
# Connexion à la base de données
require('connexion_db.php');
# On prévoit que le script puisse être inclus (il le sera...) et que l'identifiant de la catégorie puisse être déjà défini
if (!isset($cat_id)) {
# On récupère l'id de la catégorie parente, et on le protège : on ne veut qu'un entier
$cat_id = isset($_GET['cat_id']) ? intval($_GET['cat_id']) : 1;
}
# Ecrivons notre requête SQL :
$sql = "SELECT cat_id, cat_title FROM categories WHERE cat_parent_id=$cat_id ORDER BY cat_title DESC";
if (FALSE !($result $db -> query($sql))) {
while (FALSE !($row $result -> fetch())) {
echo '<option value="'.$row['cat_id'].'">'.$row['cat_title'].'</option>'."\n";
}
}
?>
Notre script va gentiment ecrire le code HTML des options de la liste. En cas d'erreur, il n'affichera simplement rien. Libre à vous de gérer le comportement du script en cas d'erreur, par exemple en déclenchant une erreur avec trigger_error() ou en levant une exception en PHP5.
2. Le script du formulaire
Je vous laisse le soin de mettre votre page en forme, je ne m'intéresserai ici qu'au code qui concerne directement les deux liste déroulantes. Code que voici :
<select id ="liste1"><?php $cat_id = 0; include('genere_liste.php'); ?></select>
<select id="liste2"><?php $cat_id = 1; include('genere_liste.php'); ?></select>
Comme vous pouvez le constater, nous utilisons deux fois le même script. Nous pouvons le faire car les données proviennent de la même table et sont hiérarchisées. Veillez à adapter en fonction de vos besoins (notamment, la première liste peut tout à fait être statique ou générée à partir d'un autre script d'après les données d'une autre table, etc).
Lors de l'inclusion, le contexte d'exécution du script inclus est le même que celui qui fait l'inclusion ; c'est à dire que la variable $cat_id que l'on défini dans le script du formulaire est accessible. C'est pour cela que nous avons pris soin dans le script genere_liste.php de ne définir $cat_id avec la variable $_GET['cat_id'] que si elle ne l'est pas déjà. Lorsque le script sera appelé directement par Javascript, $cat_id ne sera pas défini, on utilisera alors $_GET['cat_id'].
Appelez ce fichier comme vous voulez, ça ne me regarde pas ^^
3. Le script Javascript
Comme je le disais en introduction, nous utiliserons jQuery pour nous faciliter la vie.
Voici le script à placer n'importe où sur la page (tant que ça reste conforme au doctype du document, évidemment) :
<script type ="text/javascript">
$('document').ready(function() {
$('#liste1').change(function() {
$('#liste2').load('/genere_liste.php?cat_id='+this.value);
});
});
</script>
C'est tout. Explications :
$('document').ready(function() { : la fonction a exécuter quand jQuery aura détecté que le fichier est intégralement chargé.
$('#liste1') : l'élément du DOM dont l'id est liste1, c'est à dire notre première liste déroulante
.change : assigne la fonction qui suit à l'évènement onchange de l'élément en question, donc de notre première liste déroulante
.load() : la fonction de jQuery qui va charger le document appelé en argument. Cette fonction, étant appliquée à l'élément liste2, va remplacer ce qui se trouve à l'intérieur de cet élément. Comme il s'agit d'une liste, cela correspond à ce qui se trouve entre <select.... > et </select>
this.value : A cet endroit du script JS, le contexte d'exécution est l'évènement onchange de l'élément liste1. this se rapporte donc à l'élément liste1, et this.value est la valeur de l'option sélectionnée.
Conclusion
C'est tout... C'est terminé.
Maintenant, quand vous sélectionnez une option de la première liste, la seconde se met à jour automatiquement.
Evidemment, ça ne doit pas vous avancer à grand chose de n'avoir qu'une liste qui se met à jour... Le principe est exactement le même si vous souhaitez afficher tous les objets qui appartiennent à la catégorie sélectionnée dans la deuxième liste : il suffit de charger le résultat d'un script dans un élément
qui contient la liste des objets, exactement sur le même principe que ce que nous venons de voir ici.
Si vous souhaitez ajouter une animation pendant le chargement, ce n'est pas de mon ressort :). Consultez la documentation de jQuery, parce que vous aurez besoin de contrôler mieux le processus de chargement, avec les évènements Ajax de jQuery
--
Neige, vraiment complètement blasé
N'hésitez pas à lire la doc