Liste déroulante liée en AJAX

Attention, depuis PHP 5.5.0, certaines extensions SQL sans doute utilisées dans ce tutoriel peuvent être obsolètes et seront supprimées dans le futur, vous devez donc adapter les codes! Exemples ici.
Nous allons voir dans ce tutoriel comment créer une liste déroulante dynamique en AJAX liée à une autre. Cette méthode permet donc d'afficher une simple liste déroulante sans rechargement de la page. Vous pouvez voir l'exemple de ce tutoriel ici : Exemple d'une liste lié en AJAX.

Etape 1 : création de la base de données

Pour cet exemple, on va créer une base de données qui va contenir 2 tables énumérants les régions et départements de France.
--
-- Structure de la table `departements`
--

CREATE TABLE IF NOT EXISTS `departements` (
  `num_departement` varchar(3) COLLATE latin1_general_ci NOT NULL,
  `num_region` varchar(3) COLLATE latin1_general_ci NOT NULL,
  `nom` char(32) COLLATE latin1_general_ci NOT NULL,
  PRIMARY KEY (`num_departement`),
  KEY `FK_DEPARTEMENT_REGION` (`num_region`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

--
-- Contenu de la table `departements`
--

INSERT INTO `departements` (`num_departement`, `num_region`, `nom`) VALUES
('1', '22', 'Ain'),
('2', '20', 'Aisne'),
('3', '3', 'Allier'),
('4', '18', 'Alpes de haute provence'),
('5', '18', 'Hautes alpes'),
('6', '18', 'Alpes maritimes'),
('7', '22', 'Ardèche'),
('8', '8', 'Ardennes'),
('9', '16', 'Ariège'),
('10', '8', 'Aube'),
('11', '13', 'Aude'),
('12', '16', 'Aveyron'),
('13', '18', 'Bouches du rhône'),
('14', '4', 'Calvados'),
('15', '3', 'Cantal'),
('16', '21', 'Charente'),
('17', '21', 'Charente maritime'),
('18', '7', 'Cher'),
('19', '14', 'Corrèze'),
('21', '5', 'Côte d''or'),
('22', '6', 'Côtes d''Armor'),
('23', '14', 'Creuse'),
('24', '2', 'Dordogne'),
('25', '10', 'Doubs'),
('26', '22', 'Drôme'),
('27', '11', 'Eure'),
('28', '7', 'Eure et Loir'),
('29', '6', 'Finistère'),
('30', '13', 'Gard'),
('31', '16', 'Haute garonne'),
('32', '16', 'Gers'),
('33', '2', 'Gironde'),
('34', '13', 'Hérault'),
('35', '6', 'Ile et Vilaine'),
('36', '7', 'Indre'),
('37', '7', 'Indre et Loire'),
('38', '22', 'Isère'),
('39', '10', 'Jura'),
('40', '2', 'Landes'),
('41', '7', 'Loir et Cher'),
('42', '22', 'Loire'),
('43', '3', 'Haute loire'),
('44', '19', 'Loire Atlantique'),
('45', '7', 'Loiret'),
('46', '16', 'Lot'),
('47', '2', 'Lot et Garonne'),
('48', '13', 'Lozère'),
('49', '19', 'Maine et Loire'),
('50', '4', 'Manche'),
('51', '8', 'Marne'),
('52', '8', 'Haute Marne'),
('53', '19', 'Mayenne'),
('54', '15', 'Meurthe et Moselle'),
('55', '15', 'Meuse'),
('56', '6', 'Morbihan'),
('57', '15', 'Moselle'),
('58', '5', 'Nièvre'),
('59', '17', 'Nord'),
('60', '20', 'Oise'),
('61', '4', 'Orne'),
('62', '17', 'Pas de Calais'),
('63', '3', 'Puy de Dôme'),
('64', '2', 'Pyrénées Atlantiques'),
('65', '16', 'Hautes Pyrénées'),
('66', '13', 'Pyrénées Orientales'),
('67', '1', 'Bas Rhin'),
('68', '1', 'Haut Rhin'),
('69', '22', 'Rhône'),
('70', '10', 'Haute Saône'),
('71', '5', 'Saône et Loire'),
('72', '19', 'Sarthe'),
('73', '22', 'Savoie'),
('74', '22', 'Haute Savoie'),
('75', '12', 'Paris'),
('76', '11', 'Seine Maritime'),
('77', '12', 'Seine et Marne'),
('78', '12', 'Yvelines'),
('79', '21', 'Deux Sèvres'),
('80', '20', 'Somme'),
('81', '16', 'Tarn'),
('82', '16', 'Tarn et Garonne'),
('83', '18', 'Var'),
('84', '18', 'Vaucluse'),
('85', '19', 'Vendée'),
('86', '21', 'Vienne'),
('87', '14', 'Haute Vienne'),
('88', '15', 'Vosge'),
('89', '5', 'Yonne'),
('90', '10', 'Territoire de Belfort'),
('91', '12', 'Essonne'),
('92', '12', 'Haut de seine'),
('93', '12', 'Seine Saint Denis'),
('94', '12', 'Val de Marne'),
('95', '12', 'Val d''Oise'),
('2a', '9', 'Corse du Sud'),
('2b', '9', 'Haute Corse'),
('971', '23', 'Guadeloupe'),
('972', '23', 'Martinique'),
('973', '23', 'Guyane'),
('974', '23', 'La Réunion');

-- --------------------------------------------------------

--
-- Structure de la table `regions`
--

CREATE TABLE IF NOT EXISTS `regions` (
  `num_region` varchar(2) COLLATE latin1_general_ci NOT NULL,
  `nom` varchar(255) COLLATE latin1_general_ci NOT NULL,
  PRIMARY KEY (`num_region`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

--
-- Contenu de la table `regions`
--

INSERT INTO `regions` (`num_region`, `nom`) VALUES
('1', 'Alsace'),
('2', 'Aquitaine'),
('3', 'Auvergne'),
('4', 'Basse Normandie'),
('5', 'Bourgogne'),
('6', 'Bretagne'),
('7', 'Centre'),
('8', 'Champagne Ardenne'),
('9', 'Corse'),
('10', 'Franche Comte'),
('11', 'Haute Normandie'),
('12', 'Ile de France'),
('13', 'Languedoc Roussillon'),
('14', 'Limousin'),
('15', 'Lorraine'),
('16', 'Midi-Pyrénées'),
('17', 'Nord Pas de Calais'),
('18', 'Provence Alpes Côte d''Azur'),
('19', 'Pays de la Loire'),
('20', 'Picardie'),
('21', 'Poitou Charente'),
('22', 'Rhone Alpes'),
('23', 'Départements d''outre-mer');
Etape 2 : mise en place du design.

Histoire que ce ne soit pas trop moche, on créer un fichier "style.css" contenant les class suivantes :
body{
background:#98B6BE;
}
#centre {
background:white;
position : absolute;
left : 50%;
top : 50%;
width : 500px;
height : 300px;
margin-top : -150px;
margin-left: -250px;
padding:5px;
color:#000;
}
h1{
color: #0AF;
text-align: center;
}
label {
text-align: right;
width: 150px;
padding-right: 10px;
margin-bottom: 10px;
font-weight:bold;
display: block;
float: left;
}
select{
width: 250px;
}
br {
clear: left;
}
input[type=submit],input[type=reset]{
width: 70px;
margin-left:5px;
}
#erreur{
background: #C00;
color: white;
padding:2px;
margin:2px;
border-radius:5px 5px 5px 5px;
-webkit-border-radius:5px 5px 5px 5px;
-moz-border-radius:5px 5px 5px 5px;
}
#info{
background :#0AF;
color:white;
margin:2px;
padding:2px;
border-radius:5px 5px 5px 5px;
-webkit-border-radius:5px 5px 5px 5px;
-moz-border-radius:5px 5px 5px 5px;
}
#reponse{
background :#F60;
color:white;
margin:2px;
padding:2px;
border-radius:5px 5px 5px 5px;
-webkit-border-radius:5px 5px 5px 5px;
-moz-border-radius:5px 5px 5px 5px;
}
Etape 3 : création du formulaire

Dans une page "index.php", nous allons créer un simple formulaire basé sur une liste qui va faire appel à une fonction AJAX :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Language" content="fr" />
<title>Exemple d'une liste liée en AJAX</title>
<meta name="Description" content="Exemple d'une liste liée en AJAX." />
<link rel="stylesheet" type="text/css" href="style.css" />
<script type="text/javascript" src="fonctions.js"></script>
</head>
 
<body>
 
<div id="centre">
 
<h1>Exemple d'une liste liée en AJAX</h1>
 
<form method="post" name="liste">
<label>Régions : </label>
<select name="region" id="region" onchange="Departements(this.value);">
<option value="vide">- - - Choisissez une région - - -</option>
<?php
//Variable de connexions BDD
$nom_du_serveur ="***";
$nom_de_la_base ="***";
$nom_utilisateur ="***";
$passe ="***";
 
//Connexion à la base de données
mysql_connect("$nom_du_serveur","$nom_utilisateur","$passe");
//Vérification d'accès à la base de données
mysql_select_db("$nom_de_la_base")  or die ('Erreur :'.mysql_error());
 
//On sélectionne toutes les régions
$selectregion = mysql_query("SELECT num_region,nom FROM regions ORDER BY nom") or die (mysql_error());
while($donnees = mysql_fetch_array($selectregion))
{
    echo '<option value="'.$donnees['num_region'].'"';
    if(isset($_POST["region"]) && $_POST["region"]==$donnees['num_region']){echo " selected";}
    echo '>'.$donnees['nom'].'</option>';
}
?>
</select><br/>
 
<!-- Dans ce bloc sera affiché la liste des départements -->
<div id="blocDepartements">
<?php
/*Pour garder la sélection de la seconde liste, on l'inclue directement dans la page lors de la validation du formulaire*/
if(isset($_POST['region'])){
//on créer une variable utilisé dans la page "traitement.php"
$include = 1;
//on inclue la page
include('traitement.php');
}
?>
</div>
<!-- Fin du bloc des départements -->
 
<label>Valider : </label>
<input type="submit" name="Valider" value="Valider"/>
<input type="reset" name="Effacer" value="Effacer"/>
</form>
 
</div>
 
</body>
</html>
Résumons un peut cette page "index.php".

On fait donc appel au fichier CSS ainsi qu'à un fichier Javascript nommé "fonctions.js" qui va contenir les fonctions AJAX.
La balise "select" de la liste contient l'appel à une fonction nommé "Departements()" qui va transmettre la valeur de l'option grâce à l'argument "this.value" passé en paramètre lors de la sélection "onchange".
Pour construire les options de la liste, on effectue une requête SQL.
La liste liée sera affiché dans le div "blocDepartements" via la fonction AJAX "Departements()".

Pour garder en mémoire l'option de la liste liée, je n'ai pas trouvé mieux que de l'inclure directement dans la page...si vous avez mieux, n'hésitez pas à utiliser le système de commentaires ;).
N'oubliez pas de remplir les variables de connexions avec vos données.

Histoire d'avoir un formulaire complet, on va ajouter un petit traitement en cas d'erreurs puis on va afficher le résultat de celui-ci. Sous la balise "</form>", on ajoute :
<?php
//Le formulaire a été posté
if(isset($_POST["Valider"])){
//Régions  vide
    if(isset($_POST["region"]) && $_POST["region"] == 'vide'){
        echo '<div id="erreur">Veuillez sélectionner une région!</div>';
    }
//Départements vide
    else if(isset($_POST["departement"]) && $_POST["departement"] == 'vide'){
        echo '<div id="erreur">Veuillez sélectionner un département!</div>';
    }
//Tout est ok
    else{
        //On va chercher le nom de la région sélectionné
        $affichetregions = mysql_query("SELECT nom FROM regions WHERE num_region='".mysql_real_escape_string($_POST["region"])."'") or die (mysql_error());
        $donneesregions = mysql_fetch_assoc($affichetregions);
 
        //On va chercher le nom du département sélectionné
        $affichedepartements = mysql_query("SELECT nom FROM departements WHERE num_departement='".mysql_real_escape_string($_POST["departement"])."'") or die (mysql_error());
        $donneesdepartements = mysql_fetch_assoc($affichedepartements);
 
        //On affiche le résultat
        echo '<div id="info">Vous avez sélectionné la région '.$donneesregions['nom'].' et le département '.$donneesdepartements['nom'].'</div>';
    }
}
?>
Etape 4 : création des fonctions.

Je vous rassure tout de suite, ça ne pas être bien compliqué . Dans un fichier nommé "fonctions.js", on commence par écrire la fonction d'instance :
//Fonction d'Instance
function objet_XMLHttpRequest()
{
    var xhr = null;
 
    if (window.XMLHttpRequest || window.ActiveXObject){
        if(window.ActiveXObject){
            try{
                xhr = new ActiveXObject("Msxml2.XMLHTTP");
            }
            catch(e){
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            }
        }
        else{
            xhr = new XMLHttpRequest();
        }
    }
    else{
        alert("Votre navigateur ne supporte pas l'objet XMLHTTPRequest...");
        return null;
    }
    return xhr;
}
Puis on créer la fonction "Departements()" qui va prendre en paramètre le numéro de l'option sélectionné. Cette fonction va donc envoyer au fichier "traitement.php" le numéro de la région et la réponse obtenue sera affiché dans le div "blocDepartements".
//Fonction permettant d'envoyer les données
function Departements(id)
{
    //On déclare un objet
    var objet1 = objet_XMLHttpRequest();
 
    //On défini ce qu'on va faire quand on aura la réponse
    objet1.onreadystatechange = function(){
        //On ne fait quelque chose que si on a tout reçu et que le serveur est ok
        if(objet1.readyState == 4 && objet1.status == 200){
            //On envoie la réponse dans le div "blocDepartements"
            document.getElementById('blocDepartements').innerHTML = objet1.responseText;
        }
        //côté ajax ça merde
        else{
            //on contrôle le statut. Si 404, le fichier ouvert par "open" n'existe pas
            if(objet1.status == 404){
                alert('Erreur ' +objet1.status + '! Le fichier php semble être absent...');
            }
        }
    }
    //Ouverture : méthode, fichier, mode (true=asynchrone | false=synchrone)
    objet1.open("POST", "traitement.php" , true);
    objet1.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    //envoie
    objet1.send("region=" + id);
}
Alors, ce n'était pas trop compliqué?

Etape 5 : traitement des données

Pour cette dernière étape, nous allons créer une page nommé "traitement.php" qui va nous permettre de créer la seconde liste déroulante. Le résultat sera récupéré via l'objet "objet1.responseText" de la fonction "Departements()" pour être affiché dans le div" blocDepartements".
<?php
//Numéro de la région
if(isset($_POST["region"]) && $_POST["region"] != 'vide'){
/*Si la variable $include n'existe pas c'est que le numéro de la région passe par AJAX. On a donc besoin d'avoir une connexion avec la base de données.*/
/*Quand on poste le formulaire, cette page est inclue directement dans le div "blocDepartements", donc la connexion est inutile.*/
/*Si on inlcue cette page au moment de la validation, c'est uniquement pour garder la sélection "selected" de la liste.*/
if(!isset($include)){
//On indique le Content-Type utilisé
header('Content-Type: text/html; charset="iso-8859-1"');
 
//Variable de connexion BDD
$nom_du_serveur ="***";
$nom_de_la_base ="***";
$nom_utilisateur ="***";
$passe ="***";
 
//Connexion à la base de données
mysql_connect("$nom_du_serveur","$nom_utilisateur","$passe");
//Vérification d'accès à la base de données
mysql_select_db("$nom_de_la_base") or die ('Erreur :'.mysql_error());
echo '<div id="reponse">La variable $_POST["region"] provient d\'AJAX.</div>';
}
else{
echo '<div id="reponse">La variable $_POST["region"] provient de l\'include.</div>';
}
?>
 
<label>Départements : </label>
<select name="departement" id="departement">
<option value="vide">- - - Choisissez un département - - -</option>
<?php
//On sélectionne les départements en fonction du numéro de la région
$selectdepartement = mysql_query("SELECT num_departement,nom FROM departements WHERE num_region=".mysql_real_escape_string($_POST["region"])." ORDER BY nom") or die (mysql_error());
//On boucle
while($donnees = mysql_fetch_assoc($selectdepartement))
{
echo '<option value="'.$donnees['num_departement'].'"';
if(isset($_POST["departement"]) && $_POST["departement"]==$donnees['num_departement']){ echo " selected"; }
echo '>'.$donnees['nom'].'</option>';
}
?>
</select><br/>
<?php } ?>
Explications :

Lors de la validation du formulaire, la seconde liste disparaît tout comme la sélection faite sur celle-ci, ce qui est plutôt ennuyant...d'ou la "parade" d'inclure ce fichier! Comme cette page utilise une connexion à la base de données et qu'elle est inclue dans la page "index.php" au moment de la validation, on utilise la variable "$include" créer dans la page "index.php" pour utiliser ou pas la connexion de ce fichier ... je sens que ce n'est pas très claire ...?

Si la page "traitement.php" est appelé par la fonction AJAX, on utilise la connexion faite dans ce fichier pour se connecter à la BD et créer la liste associée.
Si la page "traitement.php" est appelé par l'include du fichier "index.php" (lors de la validation), on se retrouve avec 2 connexions, celle du fichier "index.php" et celle du fichier "traitement.php", ce qui est inutile!
On utilise donc la variable "$include" pour supprimer la connexion du fichier "traitement.php" lors de son inclusion dans le fichier "index.php".
Voir/déposer un commentaire (1) | Signaler un problème