Multi SELECTElement chargées en Ajax suite aux précédents choix
Salut !
Hier soir, j'ai passé un peu de temps à monter une petite fonction assez sympatique... le but est de charger des listes déroulantes en fonctions des choix effectués sur les précédentes !
Ici, nous avons une première liste qui contient des continents, la seconde va charger des pays, la troisième des villes. suite au troisième choix, nous afficherons une GoogleMap sur cette ville ...
Le but n'est pas de présenter un traitement de la BDD, donc les requetes ajax récupérerons les contenus de tables écrites en dur (d'ou le peu de choix :D). Ni de présenter une GoogleMap super Higth Tech, donc, on fera un traitement ultra simplifié de la fonction post multi-choix...
Tout d'abord, notre page : tous se déroule sur un seul fichier php, si la requete est faite en ajax, nous retournerons les résultats et intéromprons notre script, sinon, nous afficherons dans le navigateur la page HTML.
Le php est simplifié au possible ::
<?
/*
* Code réalisé pour PHPFRANCE.COM sur 4code.fr
* objectif : afficher dans un formulaire des listes déroulantes en fonction des choix précédents !
* By NOURS312
*
*/
$listA = array('Europe', 'Asie', 'Ameriques'); // notre première liste contenant nos trois continents
$listB = array( // notre seconde liste contenant les listes à attribuées en fonction du choix de la première
array('france', 'allemagne', 'italie'),
array('chine', 'japon', 'indes'),
array('bresil', 'usa', 'canada')
);
$listC = array( // je vous laisse imaginer le comportement de cette table ^^
array(
array('paris', 'marseille', 'clermont-ferrand'),
array('berlin', 'stuttgart', 'bonn'),
array('rome', 'turin', 'milan')
),
array(
array('shanghai', 'wuchan', 'chongqing'),
array('hiroshima', 'nagasaki', 'tokyo'),
array('hamadabad', 'mumbai', 'kolkata')
),
array(
array('sao paulo', 'rio de janeiro', 'belo horizonte'),
array('new york', 'los angeles', 'washington'),
array('montreal', 'winnipeg', 'calgary')
)
);
/*
* Il est préférable de travailler avec un BDD pour effectuer tout ceci, mais pour notre exemple, ce n'était pas necessaire !...
* et vu que la gestion d'une BDD n'est pas l'objet de ce tutos, je ne vais pas m'étendre sur le sujet :D
*/
if(isSet($_POST['listA'])){ // Si nous avons une requete Ajax contenant la valeur de notre listA (premier <select>
if(isSet($_POST['listB'])) // Si nous avons aussi le choix de notre second <select>
echo json_encode($listC[$_POST['listA']][$_POST['listB']]); // nous affichonx le tableau issu de $listC demandé, encodé sous forme d'un JSON
else
echo json_encode($listB[$_POST['listA']]); // sinon nous affichonx le tableau issu de $listB
die(); // et nous interompons notre script pour ne pas poluer le retour de la requete Ajax !
}
// sinon, nous retournons notre page HTML !!
?>
Comme vous le constatez, nous utilisons les clés de nos précédents choix comme clés des options suivantes !!
Maintenant, voyons la page HTML affichée par deffaut :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="fr">
<head>
<title>Multi Listes déroulantes en Ajax</title>
<script type="text/javascript" src="http://prototypejs.org/assets/2009/8/31/prototype.js"></script>
<script src="http://maps.google.com/maps?file=api&v=2&sensor=true&key=GoogleMapKey" type="text/javascript"></script>
<script type="text/javascript">
// ...
// ici viendra se placer notre JavaScript
// ...
</script>
</head>
<body>
<div>
<p>Alors, ci dessous vous trouverez une Suite de listes déroulantes chacune est chargée en fonction des choix précédents !</p>
<p>Ce script à été réalisé pour répondre à une question, vous trouverez sur <a href="http://4code.fr">4code.fr</a> l'ensemble des scripts php/html/js employés ici<br/>
Je m'excuze par avance si il est réalisé à l'aide de <a href="http://prototypejs.org/download">prototype</a>, mais je souhaitais le monter le plus rapidement possible :D</p>
<p>J'espère que ce sera utile à quelques'uns ;)</p>
<p>Javascriptement Vôtre ! <a href="http://nours312.com">Nours312</a></p>
</div>
<div id="F">
<form action="#">
<!--
nous plaçons nos éléments SELECT dont le premier sachant ce qu'il contient est pré-rempli.
nous ajoutons un attribut onChange="listLoad(this)" en charge d'appeler la fonctionlistLoad
en lui passant en parametre le SELECTElement en question.
Nous aurions put utiliser listLoad.bindAsEventListener(this) (http://prototypejs.org/api/function/bindAsEventListener) pour ensuite utiliser directement this pour pointer vers notre élément
et éviter ainsi l'argument el au sein de notre fonction, mais tant qu'à faire, autant faire simple :D
-->
<select onchange="listLoad(this)" id="listA">
<option selected="selected">Selectionner un pays</option>
<? foreach($listA as $k => $v): ?>
<option value="<?=$k?>"><?=$v?></option>
<? endforeach; ?>
</select>
<select onchange="listLoad(this)" id="listB" disabled="disabled">
</select>
<select onchange="listLoad(this)" id="listC" disabled="disabled">
</select>
</form>
</div>
<!-- ici notre div#map en chage d'afficher notre ville une fois sélectionnée... -->
<div id="map" style="width:500px;height:500px"></div>
<!-- un peu de pub ^^ -->
<div style="text-align:center;margin:auto;">
</div>
<div style="text-align:center;margin:auto;">
D'autres idées de codes <a href="http://4code.fr/" title="plateforme de script et tutos Web">par ici</a> ;) @+
</div>
<!-- et le script de google analytics ;) -->
</html>
Rien de bien compliqué, un peu de texte, un formulaire (pas necessaire en soit, mais c'est plus joli ^^) et nos trois SELECTElements
La partie JavaScript est la plus importante :
/**
* les variables map et geocoder sont utilisées par notre fonction valid ... acun interet pour le code qui nous interesse !
*/
var map = null;
var geocoder = null;
function listLoad(el){ // el est notre liste déroulante déclenchant notre evenement
switch(el.id){ // nous utilisons sont id pour retrouver les actions à effectuer
case 'listA' : // listA est notre première liste
$('map').innerHTML = ''; // nous vidons notre div#map car nous ne savons pas qu'elle ville va etre demandée à ce niveau du formulaire
$('listB').disable(); // nous desactivons les listes B et C
$('listC').disable();
$('listB').options.length=0; //Nous vidons les listes B et C pour effecer les anciennes options
$('listC').options.length=0;
var c = listLoading.bind($('listB')); // c est notre fonction de callBack appelée suite au chargement Ajax de notre bdd
// ici nous utilisons un bind(element) pour que dans cette fonction, nous puissions utiliser this pointant sur l' "élément" en question
// voir : http://prototypejs.org/api/function/bind pour plus de détails
new Ajax.Request(document.location.href, //la class Ajax de prototype va effectuer une requete XMLHTTPRequest
// ici, en utilisant l'url de la page en cours d'affichage en par deffaut en methode POST
// plus de détails : http://prototypejs.org/api/ajax
{
parameters : {listA:$F(el)}, // parametres envoyés lors de la requete (pour récupérer : $_POST['listA'] )
onComplete : c // nous demandons le lancement de notre fonction de callBack c lorsque la requete est terminée (status 200)
});
break;
case 'listB' : // si notre select est le second ('listB'), nous effectuons ls memes opérations que pour le premier,
// mis à part que nous désactivons et vidons seulement le troisième <select> et que nous envoyons plus de parametres dans notre Ajax
$('map').innerHTML = '';
$('listC').disable();
$('listC').options.length=0;
var c = listLoading.bind($('listC'));
new Ajax.Request(document.location.href, {parameters : {listB:$F(el), listA:$F('listA')}, onComplete : c}); // $F(idFormElement) retourne la value de notre élément ... petite astuces Prototype => http://prototypejs.org/api/utility/dollar-f
break;
case 'listC' : // si notre choix porte sur le troisième <select>, nous lançons notre opération de traitement, nous pourrions faire d'autre choix, mais ce n'est aps le but ici
valid($F(el), el.options[el.options.selectedIndex].text); //Nous envoyons à notre fonction valid() la valeur de notre troisieme choix et pour nos besoins le contenu texte de cette option...
break;
}
}
/**
* Fonction listLoading() appelée suite à la réalisation avec succés de notre requete ajax !
* prend en parametre l'objet xhr retourné par la requete.
* et rapellons que nous avons bindé la fonction avec l'objet à manipuler (le second ou troisième select) donc nous utiliserons
* le mot clés this qui pointera directement sur l'élément en question ...
*/
function listLoading(xhr){
this.options[0] = new Option('Selectionnez'); // nous ajoutons un choix contenant l'information 'selectionner' ainsi l'utilisateur comprendra rapidement qu'il peut intervenir sur ce choix.
this.enable(); // nous rendons actif notre élément => http://prototypejs.org/api/form/element/enable
var j = xhr.responseText.evalJSON(); // nous transformons la réponse reçue de type <string> en objet si celle-ci est bien de la forme d'un JSON
j.each(function(v, k){ // each est une fonction qui permet de parcourir notre objet en passant à notre fonction callBack les arguments value et key
this.options[this.options.length] = new Option(v, k); // nous remplissons notre élément <select> avec les éléments de notre tableau
}.bind(this)); // Atention, pour utiliser this au sein de cette fonction, il ne faut pas oublier de la binder !!
}
/**
* Fonction valid() en charge d'effectuer les opérations demandées suite au dernier choix réalisé par l'utilisateur
* ici, nous affichons la ville demandée dnas une Google Map .... mais vous povez trés bien faire ce que vous souhaitez ^^
*/
var valid = function(value, city){
if (GBrowserIsCompatible()) {
map = new GMap2($('map')); // attribution à la variable map d'une GoogleMap située dans l'élément#map (ici notre div) ...
map.setMapType(G_HYBRID_MAP); // nous définissons le stype de carte (vue satelite avec tracés des routes)
map.setCenter(new GLatLng(44.557855,4.749012), 10); //nous plaçons le centre par deffaut (montelimar 26)
map.addControl(new GSmallZoomControl3D()); // nous ajoutons la barre de control des zoom
geocoder = new GClientGeocoder(); // nous initialisons la variablegeocoder avec un objet GClientGeocoder en charge de récupérer les coordonées d'une ville, rue, ou autres adresse
if (geocoder) {
geocoder.getLatLng( // cette fonction récupère les coordonées et va lancer la fonction contenue en second argument une fois la requete effectuée.
city,
function(point) { // fonction de callBack
if (!point) {
alert(city + " not found"); // si l'adresse n'est pas trouvée nous retournons une alerte
} else { // sinon, nous allons déplacer notre carte et afficher notre trouvaille :D
map.setCenter(point, 13); // nous réinitialisons notre map sur ce nouveau point
var marker = new GMarker(point); // créons un marker et le plaçons sur ce point
map.addOverlay(marker); // plaçons le marker sur la map
marker.openInfoWindowHtml(city.capitalize()); // et ouvrons une infobulle contenant le nom de notre ville
// dont le premier caractère est en majuscule => http://prototypejs.org/api/string/capitalize
}
}
);
}
}
}
Et voilà !... vous avez tout ce qu'il vous faut pour vous amuser autant que moi !! :D
N'oubliez pas de télécharger le script prototypes et d'étudier son fonctionnement
Vous pouvez visualiser le fonctionnement de ce script ici !
Et nous laisser vos commentaire en dessous !... @Bientôt ! & BonCode ;)