Bienvenue, Invité
Nom d'utilisateur : Mot de passe : Se souvenir de moi

SUJET : Menus déroulants en cascade

Menus déroulants en cascade il y a 1 an 10 mois #81560

  • waielbi
  • Portrait de waielbi
  • Hors ligne
  • Fresh Lemon
  • Messages : 10
  • Karma: 0
Je suis nouveau sur le forum, j'ai un problème que je n'arrive pas à résoudre seul :
j'ai besoin de mettre en place des menus en cascade, j'ai trouvé cet exemple pour m'expliquer :

question 1 - menu déroulant - Choisir sa région
question 2 - menu déroulant - Choisir son département les entrées dépendent du choix 1
question 3 - menu déroulant - Choisir sa commune les entrées dépendent du choix 2

pour des données finales dans mon fichier csv |Region|Département|Commune|

J'ai bien pensé à créer des questions 'départements' qui sont affichées en fonctions des choix de régions mais, le travail est énorme et en plus les résultats vont s'éparpiller sur de nombreuses colonnes dans mon fichier csv final, aucun intérêt

Quand à créer un menu déroulant avec des catégories, beaucoup trop long...

Bref je ne vois pas d'issue... Comment faites-vous ?
Dernière édition: il y a 1 an 10 mois par waielbi.
L'administrateur a désactivé l'accès en écriture pour le public.

Re: Menus déroulants en cascade il y a 1 an 10 mois #81579

  • Nickko
  • Portrait de Nickko
  • En ligne
  • LimeSurvey Team
  • Messages : 1926
  • Remerciements reçus 216
  • Karma: 43
Moi, je demanderais de taper le code du département dans un champ numérique.
Pour la commune, là aussi je demanderais de la saisir à la main.

sinon, j'imagine bien des trucs à grand coup de Javascript mais je ne sais pas trop comment les appliquer alors je n'en parlerais pas sauf si tu me dis que tu es un crack du JS et que tu n'as pas peur de passer quelques heures sur la question.

A mon avis, ça prendra autant sinon plus de temps que ce que tu qualifie déjà de travail énorme, du coup, je me dis que ça t'intéresse pas non plus.
Nickko
Ergonome / Usability expert
L'administrateur a désactivé l'accès en écriture pour le public.

Re: Menus déroulants en cascade il y a 1 an 10 mois #81598

  • Ben_V
  • Portrait de Ben_V
  • Hors ligne
  • Platinum Lime
  • Messages : 933
  • Remerciements reçus 193
  • Karma: 62
J'ai déjà vu des enquêtes réalisées à l'aide de LS avec des listes dynamiques pour tous les pays du monde + régions + villes... Alors il n'y a rien d'impossible!

Ici s'arrêtent les bonnes nouvelles car pour celà il faut impérativement rajouter du code php et de l'ajax (pas le produit-vaisselle) en plus d'avoir des tables externes avec les villes, départements, etc...

C'est plutôt lourd, mais possible, celà dépend de ton niveau.
Sinon:
- la solution de Nickko est bonne et accessible à tous
- tu peux trouver sur le forum quelqu'un qui pourra t'implémenter la fonction en tant que service pro.

Tu peux te renseigner aussi via ton moteur de recherche préféré
=>"listes déroulantes dynamiques en AJAX"
Ben/
Benoît

goo.gl/Bw5iM => Recherche GG dans le forum français (remplacer "exemple" dans la barre de recherche)
goo.gl/WX8PH => GG search for english forum (Replace "example" in the search bar)
goo.gl/IxiGu => Búsqueda en el foro en español (Cambiar "ejemplo" en la barra de...
L'administrateur a désactivé l'accès en écriture pour le public.

Re: Menus déroulants en cascade il y a 1 an 10 mois #81602

  • waielbi
  • Portrait de waielbi
  • Hors ligne
  • Fresh Lemon
  • Messages : 10
  • Karma: 0
@ Nickklo et Ben
Je ne suis pas un crack en js même si ça ne me fait pas peur. D'ailleurs la solution que j'utilisais avant était maison (www.lien-hyeres.com/fel/form.php -> form école&cinéma) et construite autour de js et php mais je n'ai jamais fini mon système qui est un peu buggy et je n'ai pas réussi à cascader plus deux select et... je n'ai pas le temps de m'y remettre.

Je vais donc adopter ta proposition de code :
mes écoles ont toutes un code unique, alors si je fais manger une liste avec à chaque ligne : code(uai)-circonscription-ville-école comment puis-je récupérer la bonne ligne si je demande le code uai de l'école dans un champ texte court ?

J'ai besoin des trois champs école/commune/circo car je vais devoir faire des tris et exporter pourles trois types de partenaires. Si je laisse ces champs en texte libres (déjà fait il y a quelques années), c'est le bintz car je ne peux plus rien trier à cause des variations orthographiques et je passe des heures à corriger la collecte ligne/ligne
L'administrateur a désactivé l'accès en écriture pour le public.

Re: Menus déroulants en cascade il y a 1 an 10 mois #81617

  • DenisChenu
  • Portrait de DenisChenu
  • En ligne
  • Moderator Lime
  • Messages : 5837
  • Remerciements reçus 712
  • Karma: 221
Salut,

Par expérience la meilleure méthode reste:
- Utilisation d'une question multitexte.
- Gestion des "sélecteurs" par autocomplete de jqueryui avec une source externe en script PHP.

C'est du code, cela demande du boulot.

Denis
Dernière édition: il y a 1 an 10 mois par DenisChenu.
L'administrateur a désactivé l'accès en écriture pour le public.
Cet utilisateur a été remercié pour son message par: waielbi

Re: Menus déroulants en cascade il y a 1 an 10 mois #81663

  • waielbi
  • Portrait de waielbi
  • Hors ligne
  • Fresh Lemon
  • Messages : 10
  • Karma: 0
@ Denis
C'est bien cette solution. Je viens d'essayer en local avec une liste de 500 lignes, ça marche bien.
Bonne idée, merci !
L'administrateur a désactivé l'accès en écriture pour le public.

Re: Menus déroulants en cascade il y a 1 an 10 mois #81683

  • DenisChenu
  • Portrait de DenisChenu
  • En ligne
  • Moderator Lime
  • Messages : 5837
  • Remerciements reçus 712
  • Karma: 221
Salut,

Sinon, pour donner des idées, un script pour codepostal -> ville

function CommuneInsee(questionId,srcRegionqID,destQuestionId){
  if (typeof questionId == "undefined") {return false;}
  if (typeof destQuestionId == "undefined") {destQuestionId=questionId;}
 
  $(document).ready(function(){
  // Première chose à faire: masquer les lignes, on le fait avant le reste. Bof
    OtherLineId = new Array();
    $('#question'+questionId+' li').each(function(){
        thisid = $(this).attr('id');
        //$("#log").append(thisid.slice(-5).substr(0,3)+"-");
        if (thisid.slice(-5).substr(0,3)=="AUT"){OtherLineId.push(thisid);}
        if (thisid.slice(-5)!="CODPO" && thisid.slice(-5)!="VILLE" ){$(this).hide();}
     });
    //On cherche les identifiants des input de type text
    // Pour les classer : CODPO: code postal, LIBEL : libellé
    // AUTxx : Autres si non dans la liste
    // Les autres sont sencé recevoir les informations
 
    inputCodPo="NULL";
    inputLibel="NULL";
    var srcCodePo ="";
    $('#question'+questionId+' input:text').each(function(){
        thisid = $(this).attr('id');
        if (thisid.slice(-5)=="CODPO"){inputCodPo = thisid;}
        if (thisid.slice(-5)=="VILLE"){inputLibel = thisid;}
        if (thisid.slice(-5)=="RETOU"){inputRetou = thisid;}
        //if (thisid.slice(-5).substr(0,2)=="AUT"){OtherId.push(thisid);}
     });
     $("#"+inputLibel).attr('disabled','disabled');
    nomId = $('#question'+questionId+' input:text').filter(':first').attr('id');
    longId= nomId.length - 5;
    nomId= nomId.substr(0, longId);
 
    $("#"+inputCodPo).focusout(function(){
        if($(this).val().length==5){
            $("#"+inputLibel).attr("disabled","");
            $("#question"+questionId+" .question-text .communeerror").remove();
            $("#"+inputLibel).focus();
            $("#"+inputLibel).autocomplete("search", "");
        }else{
            $("#"+inputLibel).attr("disabled","disabled");
            $("#question"+questionId+" .question-text .communeerror").remove();
            htmlErrorCP ="<div class='communeerror codepo error'>Vous devez saisir le code postal sur 5 caractères</div>";
            $("#question"+questionId+" .question-text").append(htmlErrorCP);
            $("#"+inputCodPo).focus();
        }
    });
    $("#"+inputLibel).autocomplete({
 
        source:function(request, response) {
            $.ajax({
              url: jsonsource,
                   dataType: "json",
              data: {
                term : request.term,
                parametres : 'libel',
                questionid : questionId,
                codepost : $('#'+inputCodPo).val()
              },
              success: function(data) {
                response(data);
              }
            });
      },
        minLength: 0,
        autoFocus: true,
        select: function( event, ui ) {
            // Boucle sur les retours: le code sous question doit correspondre au nom de la colonne
              $.each(ui.item, function(key, value) {
                $("#"+nomId+key).val(value);
              });
              if (ui.item.RETOU=="ERROR"){
                for(var i=0; i < OtherLineId.length; i++){
                    $("#"+OtherLineId[i]).show();}
              }else{
                for(var i=0; i < OtherLineId.length; i++){
                    $("#"+OtherLineId[i]).hide();
                    $("#"+OtherLineId[i]+" input.text").val()=="";
                    }
              }
            //$("#"+inputCodPo).val( ui.item.codpo );
        }
    });
    // FOrce la sélection, thanks to scottgonzalez  // https://github.com/scottgonzalez/jquery-ui-extensions/blob/master/autocomplete/jquery.ui.autocomplete.autoSelect.js
    $("#"+inputLibel).live("blur", function(event) {
        var autocomplete = $(this).data("autocomplete");
        var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex($(this).val()) + "$", "i");
        var myInput = $(this);
        autocomplete.widget().children(".ui-menu-item").each(function() {
            //Check if each autocomplete item is a case-insensitive match on the input
            var item = $(this).data("item.autocomplete");
            if (matcher.test(item.label || item.value || item)) {
                //There was a match, lets stop checking
                autocomplete.selectedItem = item;
                return;
            }
        });
        //if there was a match trigger the select event on that match
        //I would recommend matching the label to the input in the select event
        if (autocomplete.selectedItem) {
            autocomplete._trigger("select", event, {
                item: autocomplete.selectedItem
            });
        //there was no match, clear the input
        } else {
            $(this).val('');
        }
    });
 
  // Traitement des erreurs
$('#movenextbtn').click(function() {
    htmlError = "";
    txtError ="";
    if($("#"+inputCodPo).val().length !=5){
        txtError ="Vous devez saisir le code postal sur 5 caractères";
        htmlError ="<div class='communeerror codepo error'>Vous devez saisir le code postal sur 5 caractères</div>";
    }
    if(htmlError == "" && $("#"+inputLibel).val().length==0){
        txtError ="Vous devez entrer une ville valide";
        htmlError ="<div class='communeerror ville error'>Vous devez entrer une ville valide</div>";
    }
    if(htmlError == "" && $("#"+inputRetou).val() =="ERROR"){
        for(var i=0; i < OtherLineId.length; i++){
            $("#"+OtherLineId[i]).show();
            if($("#"+OtherLineId[i]+" input.text").val().length==0){
                txtError ="Vous devez précisez votre ville";
                htmlError ="<div class='communeerror ville error'>Vous devez précisez votre ville</div>";
            }
        }
    }
     if (htmlError.length>0){
        alert(txtError);
        $("#question"+questionId+" .question-text .communeerror").remove();
        $("#question"+questionId+" .question-text").append(htmlError);
        return false;
     }
});
  // Traitement du retour
    if($("#"+inputCodPo).val().length ==5){
        $("#"+inputLibel).attr('disabled','');
    }
 
    if($("#"+inputRetou).val() =="ERROR"){
        for(var i=0; i < OtherLineId.length; i++){
            $("#"+OtherLineId[i]).show();}
      }
 
  });
 
}
Avec le script PHP:
<?php
/*
Commune Insee en ajax for LimeSurvey 
(c) 2012 Denis Chenu (http://shnoulle.net) for http://www.sondages.pro
This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.1
*/
 
/* Inclusion LS pour configuration et reprise de code */
require_once(dirname(__FILE__).'/../../../classes/core/startup.php');
require_once(dirname(__FILE__).'/../../../config-defaults.php');
require_once(dirname(__FILE__).'/../../../common.php');
 
// Compute the Session name
// Session name is based:
// * on this specific limesurvey installation (Value SessionName in DB)
// * on the surveyid (from Get or Post param). If no surveyid is given we are on the public surveys portal
$scid=returnglobal('scid');
 
 
 
if(isset($_GET['parametres'])){
	$parametres = trim(strip_tags($_GET['parametres']));
	$testparame = trim(strip_tags($_GET['parametres']));
	$parametres=explode ( "-" , $parametres );
	if(isset($parametres[0])){$type=$parametres[0];}else{$type="libel";}
}else{
	$type="libel";
}
if(isset($_GET['term'])){
	$term = stripAccents(trim(strip_tags($_GET['term'])));
}else{
	//exit;
}
if(isset($_GET['codepost'])){
	$codepost = trim(strip_tags($_GET['codepost']));
}else{
	$codepost="";
}
if(isset($_GET['questionid'])){
	$questionid = intval($_GET['questionid']);
	$testsql="SELECT sid FROM {$dbprefix}questions WHERE qid ='{$questionid}'";
	$testresult = db_execute_assoc($testsql,'',true);
    if($testresult){
        $testrow= $testresult->FetchRow();
        $surveyid= $testrow['sid'];
    }else{
        exit;
    }
    $usquery = "SELECT stg_value FROM ".db_table_name("settings_global")." where stg_name='SessionName'";
    $usresult = db_execute_assoc($usquery,'',true);          //Checked
    if ($usresult)
    {
        $usrow = $usresult->FetchRow();
        $stg_SessionName=$usrow['stg_value'];
        if ($surveyid)
        {
            @session_name($stg_SessionName.'-runtime-'.$surveyid);
        }
        else
        {
            @session_name($stg_SessionName.'-runtime-publicportal');
        }
    }
    else
    {
        session_name("LimeSurveyRuntime-$surveyid");
    }
if (!isset($_SESSION) || empty($_SESSION)) @session_start();
    //if (!isset($_SESSION['s_lang'])) exit;
}else{
	exit;
}
// Get the field name
$fields = array();
$query ="DESCRIBE insee_commune";
$result = db_execute_assoc($query);
while($row = $result->FetchRow()){
     $fields[] =$row['Field'];
     }
 
 
 
if($type=="codpo"){
 
    $query="SELECT * FROM insee_commune ";
    if (strlen($term)>0){
	//    $query .= "AND ( NOMCO LIBELLE LIKE '%{$term}%' OR POSTAL LIKE '{$term}%' ) ";
	    $query .= " WHERE POSTAL LIKE '{$term}%' ";
    }
    $query.="ORDER BY TAICO DESC, NOMCO ASC LIMIT 30";
    $result = db_execute_assoc($query) or die ("$nsquery<br />".htmlspecialchars($connect->ErrorMsg()));
    $jsontable = array();
    while ($row = $result->FetchRow())
    {
        $jsonline = '"label": "'.$row['POSTAL'].'" , "desc": "'.$row['POSTAL'].' ('.$row['NOMCO'].')" , "codpo": "'.$row['POSTAL'].'" , "nomco": "'.$row['NOMCO'].'"';
        foreach ($fields as $field){
            $jsonline.=' , "'.$field.'": "'.$row[$field].'"';
        }
	    $jsontable[] = '{'.$jsonline.'}';
    }
 
    $json='['.implode(",",$jsontable).']';
 
    header('Cache-Control: no-cache, must-revalidate');
    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
    header('Content-type: application/json');
    echo $json;
}
if($type!="codpo"){
    $query="SELECT * FROM insee_commune WHERE 1 ";
    if (strlen($term)>0){
        $term= urldecode ($term);
	    $query .= " AND ( LCASE(LIBEL)  LIKE LCASE('%{$term}%') OR POSTAL LIKE '{$term}%' ) ";
    }
    if  (strlen($codepost)>1){
        $departement=substr($codepost,0,5);
	    $query .= "AND ( POSTAL LIKE '{$departement}%' ) ";
    }
    $query.="ORDER BY TAICO DESC, NOMCO ASC LIMIT 30";
    $result = db_execute_assoc($query) or die ("$nsquery<br />".htmlspecialchars($connect->ErrorMsg()));
    //echo $query;
    $jsontable = array();
    while ($row = $result->FetchRow())
    {
        $jsonline = '"label": "'.$row['NOMCO'].'" , "desc": "'.$row['NOMCO'].' ('.$row['POSTAL'].')" , "codpo": "'.$row['POSTAL'].'" , "nomco": "'.$row['NOMCO'].'"';
            $jsonline.=' , "RETOU": "OK"';
        foreach ($fields as $field){
            $jsonline.=' , "'.$field.'": "'.$row[$field].'"';
        }
	    $jsontable[] = '{'.$jsonline.'}';
    }
    // Ajout du pas dans la liste
        $jsonline = '"label": "Ma ville n\'est pas dans la liste" , "desc": "Absent de la liste" , "codpo": "00000" , "nomco": "ABSENT"';
            $jsonline.=' , "RETOU": "ERROR"';
        foreach ($fields as $field){
                $jsonline.=' , "'.$field.'": ""';
        }
	    $jsontable[] = '{'.$jsonline.'}';
    $json='['.implode(",",$jsontable).']';
 
    header('Cache-Control: no-cache, must-revalidate');
    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
    header('Content-type: application/json');
    echo $json;
}
 
function stripAccents($string){
	//return strtr($string,'ÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ _\'','aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY---');
	//return strtr($string,'àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ _','aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY--');
		return str_replace(
			array(
				'à', 'â', 'ä', 'á', 'ã', 'å',
				'î', 'ï', 'ì', 'í', 
				'ô', 'ö', 'ò', 'ó', 'õ', 'ø', 
				'ù', 'û', 'ü', 'ú', 
				'é', 'è', 'ê', 'ë', 
				'ç', 'ÿ', 'ñ',
				'À', 'Â', 'Ä', 'Á', 'Ã', 'Å',
				'Î', 'Ï', 'Ì', 'Í', 
				'Ô', 'Ö', 'Ò', 'Ó', 'Õ', 'Ø', 
				'Ù', 'Û', 'Ü', 'Ú', 
				'É', 'È', 'Ê', 'Ë', 
				'Ç', 'Ÿ', 'Ñ', 
				' ', '_', "'", 
			),
			array(
				'a', 'a', 'a', 'a', 'a', 'a', 
				'i', 'i', 'i', 'i', 
				'o', 'o', 'o', 'o', 'o', 'o', 
				'u', 'u', 'u', 'u', 
				'e', 'e', 'e', 'e', 
				'c', 'y', 'n', 
				'A', 'A', 'A', 'A', 'A', 'A', 
				'I', 'I', 'I', 'I', 
				'O', 'O', 'O', 'O', 'O', 'O', 
				'U', 'U', 'U', 'U', 
				'E', 'E', 'E', 'E', 
				'C', 'Y', 'N', 
				'-', '-', "-", 
			),$string);
}
 
Le script à besoin de nettoyage pour être diffusé
Dernière édition: il y a 8 mois 2 semaines par DenisChenu.
L'administrateur a désactivé l'accès en écriture pour le public.

Re: Menus déroulants en cascade il y a 1 an 10 mois #81702

  • waielbi
  • Portrait de waielbi
  • Hors ligne
  • Fresh Lemon
  • Messages : 10
  • Karma: 0
Comme c'était très pressé, j'ai fait avec ton script js autocomplete. Ça marche bien.

Pour ton dernier post, il me manque des billes. Je comprends que c'est articulé autour de js-json-php-mysql mais je ne suis pas assez pointu en js pour voir l'articulation js -> php, à quel moment "appelles"-tu ton script php depuis le script js ?
L'administrateur a désactivé l'accès en écriture pour le public.

Re: Menus déroulants en cascade il y a 1 an 10 mois #81703

  • DenisChenu
  • Portrait de DenisChenu
  • En ligne
  • Moderator Lime
  • Messages : 5837
  • Remerciements reçus 712
  • Karma: 221
C'est dans les fonctions d'autocomplete:
$("#"+inputLibel).autocomplete({
 
        source:function(request, response) {
            $.ajax({
              url: jsonsource,
                   dataType: "json",
              data: {
                term : request.term,
                parametres : 'libel',
                questionid : questionId,
                codepost : $('#'+inputCodPo).val()
              },
              success: function(data) {
                response(data);
              }
            });
      },

Sinon, je suis joignable professionnellement par mail: Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser.

Le lien est donné dans le modèle par jsonsource,
var jsonsource : {TEMPLATEURL}ville.php

Ca permet d'avoir le script par modèle pour faire des trabsferts facile.



Denis
Dernière édition: il y a 1 an 10 mois par DenisChenu. Raison: jsonsource
L'administrateur a désactivé l'accès en écriture pour le public.
Modérateurs: Nickko
Temps de génération de la page : 0.357 secondes
Donation Image