IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

AJAX Discussion :

Question complémentaires par rapport au sujet PHP "Recharger page après exécution code"


Sujet :

AJAX

  1. #1
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut Question complémentaires par rapport au sujet PHP "Recharger page après exécution code"
    Bonjour,
    Le sujet auquel je fais référence dans le titre est résolu sur le fond avec AJAX et grâce aux conseils de ABCIWEB.

    Toutefois, il me reste trois questions:
    1. Pourquoi mon code ne fonctionne pas sans arguments pour la méthode send() en mode post?
    2. ABCIWEB utilise un jeton qui m'intéresse pour protéger ma page AJAX mais je n'arrive pas à le faire fonctionner. Il s'affiche dans le champ 'token' (si le type est 'text') mais n'est pas transmis dans le $_POST. EDIT: J'ai trouvé, il fallait mettre ce jeton en argument du send() ce qui fait que ce point 2 rejoint le point 1 ci-dessus.
    3. Comment transmettre les variables au formulaire sans passer par un argument dans le exit()?


    Voici le code source (ctrl+U) de ma page formulaire:
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    <!DOCTYPE html>
    <html lang="fr">
    	<head>
    		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
     
    		<meta http-equiv="Expires" content="-1" />
    		<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
     
    		<base href="http://racine.local" />
     
    		<link rel="stylesheet" media="all" type="text/css" href="../css/structure.css" />
    		<link rel="stylesheet" media="all" type="text/css" href="../css/screen.css" />
    		<link rel="stylesheet" media="print" type="text/css" href="../css/print.css" />
    	</head>
     
    	<body>
     
    <form method="post" name="tabForm">
    		<input type="hidden" id="id0" name="id" value="3011">
    	<input type="hidden" name="token" value="89e5da68bf3988022f92f40f7e56054ae5d4dd1a2a037167">
    <div class="formFlex">
    		<fieldset><legend>Activités répertoriées</legend>
    			<p class="note">
    				du texte.
    			</p>
    			<fieldset><legend>Zone d'édition&nbsp;: Sélection d'une activité</legend>
    				<label for="naf1">Section</label><select name='naf[1]' id='naf1' required='required'><option value='' label='&lt; ---- &gt;'></option><option value='1'>SECTION A - AGRICULTURE, SYLVICULTURE ET PÊCHE</option><option value='2'>SECTION B - INDUSTRIES EXTRACTIVES</option></select><br>
    				<label for="naf2">Division</label><select name='naf[2]' id='naf2'><option value='' label='&lt; ---- &gt;'></option></select><br>
    				<label for="naf3">Groupe</label><select name='naf[3]' id='naf3'><option value='' label='&lt; ---- &gt;'></option></select><br>
    				<label for="naf4">Activité</label><select name='naf[4]' id='naf4'><option value='' label='&lt; ---- &gt;'></option></select><br>
    			</fieldset>
     
    	</div>
    </form>
     
    <script type="module" src="../js/customerActivitiesHandler.js"></script>
     
    	</body>
    </html>
    Fichier "../js/customerActivitiesHandler.js
    Code JS : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    const
    	nafs	= document.querySelectorAll("[id*='naf']")
    	,root	= window.location.origin
    	;
     
    console.log(nafs);
     
    function handleChange(lastList, idx) {
    	var xhr = new XMLHttpRequest()
    		;
     
    	xhr.onreadystatechange = function(){
    		if (xhr.readyState == 4 && xhr.status == 200){
    			console.log(xhr.responseText);
    			nafs[idx].innerHTML = xhr.responseText;
    		}
    	}
    	xhr.open('POST', root+'/frontend/customerActivityAjax.php', true);
    	xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // necessary for postmode
    	xhr.send(lastList.name+'='+lastList.value);
    	//xhr.send(); // Ne fonctionne pas. Pourquoi?
    }
     
    if (nafs.length){
    	nafs.forEach(function(curNaf, index){
    		curNaf.addEventListener('change', function(e){
    			handleChange(curNaf,index+1);
    		}, false );
    	});
    }
    Et mon fichier Ajax:
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    <?php
     
    require_once('../classes/moimp/OptListSelect.php'); // permet de créer une liste d'options <select>
    require_once('../classes/moimp/OptListOption.php'); // permet de créer une option de liste <option>
    require_once('../config.php');
    require_once('../model/model.php');
     
    if ( empty(session_id()) )
    	session_start();
     
    use OptListSelect\OptListSelect;
    use OptListOption\OptListOption;
     
    var_export($_POST);echo "\r\n\r\n"; // Ne renvoie pas le jeton
    var_export($_SESSION['tokenLists']);echo "\r\n\r\n";
    $token = isset($_POST['token']) ? $_POST['token'] : null;
    var_export($token);
    if(!isset($_SESSION['tokenLists'][$token])) exit('token invalide'); // Voir le mode de sortie, voir pourquoi le jeton n'est pas reconnu.
     
    function doNafList(int $iPrevLevel){
    	$language = $_SESSION['language'];
     
    	$iNewLevel	= $iPrevLevel+1;
    	$iPrevId	= $_POST['naf'][$iPrevLevel];
    	$data		= getNAF($language, $iNewLevel, $iPrevId);
    	$lst		= new OptListSelect("naf[$iNewLevel]", ['id'=>"naf$iNewLevel", 'required'=>'required']);
    	$lst->addOption(new OptListOption('', '', ['label'=>getDBText($language,16)]));
    	if (!empty($data)){
    		foreach($data as $aItem){
    			$lst->addOption(new OptListOption($aItem['id'], $aItem['code'].' - '.$aItem[$language.'_text']));
    		}
    		unset($aItem);
    	}
    	return $lst;
    }
     
    for ($i=1;$i<5;$i++){
    	if (isset($_POST['naf'][$i])){
    		$lstNaf[$i+1] = doNafList($i);
    		exit($lstNaf[$i+1]);
    	}
    }
    var_export($_POST['naf']);

  2. #2
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 380
    Points : 10 410
    Points
    10 410
    Par défaut
    Salut,

    Alors c'est résolu ? J'ai vu dans l'autre sujet que tu avais mis résolu...

    Sinon pour envoyer plusieurs valeurs ciblées dans ton send() le plus simple est de créer un objet formData et d'utiliser la méthode "append" pour rentrer des couples clé, valeur.
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    const
    	nafs	= document.querySelectorAll("[id*='naf']")
    	,root	= window.location.origin
    	,form = document.querySelector("form[name=tabForm]")
    	;
     
    console.log(nafs);
     
    function handleChange(lastList, idx) {
    	var xhr = new XMLHttpRequest();
     
    	xhr.onreadystatechange = function(){
     
    		if (xhr.readyState == 4 && xhr.status == 200){
    			console.log(xhr.responseText);
    			nafs[idx].innerHTML = xhr.responseText;
    		}
    	}
    	xhr.open('POST', root+'/frontend/customerActivityAjax.php', true);
     
    	var data = new FormData();
    	data.append(lastList.name, lastList.value);
    	data.append('token', form.querySelector("input[name=token]").value);
     
    	/*
    	var data = new FormData(form);
    	xhr.send(data);
    	*/
     
    	xhr.send(data);
    }
    ...

    Notes que j'ai créé une constante "form" qui représente ton formulaire. C'est à partir de cette valeur que tu devrais ensuite sélectionner tes champs, ce qui permet de les cibler précisément sans besoin d'avoir recours à des id.

    Notes aussi que j'ai mis en commentaire /*...*/ une méthode qui permet d'envoyer tous les champs du formulaire dans la requête ajax.

    Après sur le principe tu te compliques la vie avec tous tes id. Tu pourrais tout aussi bien faire : <label>Section<select name= .... </select></label> plutôt que d'utiliser des "for" qui imposent d'avoir un id correspondant.

    Aussi tu aurais pu noter tous tes champs select avec la notation tableau "naf[]", cela dit dans ce cas il faudrait faire "data = new FormData(form)" pour envoyer toutes les valeurs des sélect dans la requête ajax et avoir un tableau "naf" indexé automatiquement (qui commencerait à 0), sinon tu ne saurais pas de quel select il s'agit si tu n'en envoie qu'un.

    D'un point de vue général il faut éviter d'avoir des id dans un formulaire, surtout pour un formulaire dynamique car les id doivent être uniques, et en ajoutant des champs à la volée c'est vite fait d'avoir des id dupliqués, de même si on veut dupliquer le formulaire. La bonne méthode est de cibler le formulaire et ensuite de cibler les éléments internes par rapport à cet objet (comme je l'ai fait pour sélectionner le token).

    Enfin bon si ton code fonctionne ce n'est pas la peine de tout changer, mais penses y pour les prochaines fois, tu verras qu'au final c'est beaucoup plus simple sinon ça devient vite un casse tête, sans compter que cela te fait un code plus lourd et moins facilement évolutif.

  3. #3
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Tout d'abord un grand merci pour toutes ces suggestions.

    Citation Envoyé par ABCIWEB Voir le message
    Alors c'est résolu ? J'ai vu dans l'autre sujet que tu avais mis résolu...
    C'est résolu dans le sens où la sélection en cascade fonctionne et où la question n'est plus la même. Mais dans le cas de 4 listes, si je change la valeur d'une liste, seule celle qui la suit est réinitialisée. Les autres conservent leurs options ce qui est gênant pour l'utilisateur dans le cas où il se trompe. C'est d'autant plus gênant que dans la suite du développement, j'envisage d'utiliser le même formulaire pour pouvoir modifier les sélections précédentes.

    Citation Envoyé par ABCIWEB Voir le message
    Sinon pour envoyer plusieurs valeurs ciblées dans ton send() le plus simple est de créer un objet formData et d'utiliser la méthode "append" pour rentrer des couples clé, valeur.
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    const
    	nafs	= document.querySelectorAll("[id*='naf']")
    	,root	= window.location.origin
    	,form = document.querySelector("form[name=tabForm]")
    	;
     
    console.log(nafs);
     
    function handleChange(lastList, idx) {
    	var xhr = new XMLHttpRequest();
     
    	xhr.onreadystatechange = function(){
     
    		if (xhr.readyState == 4 && xhr.status == 200){
    			console.log(xhr.responseText);
    			nafs[idx].innerHTML = xhr.responseText;
    		}
    	}
    	xhr.open('POST', root+'/frontend/customerActivityAjax.php', true);
    	xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // necessary for postmode
     
    	var data = new FormData();
    	data.append(lastList.name, lastList.value);
    	data.append('token', form.querySelector("input[name=token]").value);
     
    	/*
    	var data = new FormData(form);
    	xhr.send(data);
    	*/
     
    	xhr.send(data);
    }
    ...
    Notes que j'ai créé une constante "form" qui représente ton formulaire.
    Notes aussi que j'ai mis en commentaire /*...*/ une méthode qui permet d'envoyer tous les champs du formulaire dans la requête ajax.
    Je te remercie pour cette suggestion que je vais creuser.

    Citation Envoyé par ABCIWEB Voir le message
    C'est à partir de cette valeur que tu devrais ensuite sélectionner tes champs, ce qui permet de les cibler précisément sans besoin d'avoir recours à des id.
    Après sur le principe tu te compliques la vie avec tous tes id. Tu pourrais tout aussi bien faire : <label>Section<select name= .... </select></label> plutôt que d'utiliser des "for" qui imposent d'avoir un id correspondant.
    Je connais cette possibilité, mais je ne l'utilise pas à cause du CSS qui me permet de traiter séparément les étiquettes et les champs pour mieux aligner verticalement les uns et les autres. Je ne vois pas comment obtenir cet alignement avec un champ imbriqué dans un label.

    Citation Envoyé par ABCIWEB Voir le message
    Aussi tu aurais pu noter tous tes champs select avec la notation tableau "naf[]", cela dit dans ce cas il faudrait faire "data = new FormData(form)" pour envoyer toutes les valeurs des sélect dans la requête ajax et avoir un tableau "naf" indexé automatiquement (qui commencerait à 0), sinon tu ne saurais pas de quel select il s'agit si tu n'en envoie qu'un.
    Si tu regardes bien tu verras que c'est ce que j'ai fait.

    Citation Envoyé par ABCIWEB Voir le message
    D'un point de vue général il faut éviter d'avoir des id dans un formulaire, surtout pour un formulaire dynamique car les id doivent être uniques, et en ajoutant des champs à la volée c'est vite fait d'avoir des id dupliqués, de même si on veut dupliquer le formulaire. La bonne méthode est de cibler le formulaire et ensuite de cibler les éléments internes par rapport à cet objet (comme je l'ai fait pour sélectionner le token).
    Compte tenu de ce qui précède, je génère les noms et les id en php comme ceci: id='naf'.$i name='naf[$i]'

    Citation Envoyé par ABCIWEB Voir le message
    Enfin bon si ton code fonctionne ce n'est pas la peine de tout changer, mais penses y pour les prochaines fois, tu verras qu'au final c'est beaucoup plus simple sinon ça devient vite un casse tête, sans compter que cela te fait un code plus lourd et moins facilement évolutif.
    Par rapport à mon sujet au début de cette discussion, il me reste à régler les questions 1 et 3.

  4. #4
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 380
    Points : 10 410
    Points
    10 410
    Par défaut
    Bonjour,

    Le plus simple est que tu testes le code ci-dessous dans une page séparée.

    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    <!DOCTYPE html>
    <html lang="fr">
    	<head>
    		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
     
    		<meta http-equiv="Expires" content="-1" />
    		<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
     
    		<base href="http://racine.local" />
     
    		<link rel="stylesheet" media="all" type="text/css" href="../css/structure.css" />
    		<link rel="stylesheet" media="all" type="text/css" href="../css/screen.css" />
    		<link rel="stylesheet" media="print" type="text/css" href="../css/print.css" />
     
            <style>
                    form[name="tabForm"] .activite p {
                            line-height:30px;
                    }
                    
                    form[name="tabForm"] .activite span {
                            display:inline-block;
                            width:100px;
                    }
                    
                    form[name="tabForm"] .activite select {
                            width:200px;
                    }
                    </style>
    	</head>
     
    	<body>
     
    <form method="post" name="tabForm" >
    		<input type="hidden" id="id0" name="id" value="3011">
    	<input type="hidden" name="token" value="89e5da68bf3988022f92f40f7e56054ae5d4dd1a2a037167">
    <div class="formFlex">
    		<fieldset><legend>Activités répertoriées</legend>
    			<p class="note">
    				du texte.
    			</p>
    			<fieldset class="activite"><legend>Zone d'édition&nbsp;: Sélection d'une activité</legend>
    				<p><label><span>Section</span><select name='naf[]' required='required'><option value='' label='&lt; ---- &gt;'></option><option value='1'>SECTION A - AGRICULTURE, SYLVICULTURE ET PÊCHE</option><option value='2'>SECTION B - INDUSTRIES EXTRACTIVES</option></select></label></p>
    				<p><label><span>Division</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option><option value='1'>SECTION A - AGRICULTURE, SYLVICULTURE ET PÊCHE</option><option value='2'>SECTION B - INDUSTRIES EXTRACTIVES</option></select></label></p>
    				<p><label><span>Groupe</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option><option value='1'>SECTION A - AGRICULTURE, SYLVICULTURE ET PÊCHE</option><option value='2'>SECTION B - INDUSTRIES EXTRACTIVES</option></select></label></p>
    				<p><label><span>Activité</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option><option value='1'>SECTION A - AGRICULTURE, SYLVICULTURE ET PÊCHE</option><option value='2'>SECTION B - INDUSTRIES EXTRACTIVES</option></select></label></p>
    			</fieldset>
     
    	</div>
    </form>
     
     
    <script>
    const
            form = document.querySelector("form[name=tabForm]")
            ,nafs = form.querySelectorAll("select[name='naf[]']")
            ,root   = window.location.origin
            ;
     console.log(nafs);
    function handleChange(lastList, idx) {
            var xhr = new XMLHttpRequest();
     
            xhr.onreadystatechange = function(){
                    
                    if (xhr.readyState == 4 && xhr.status == 200){
                            console.log(xhr.responseText);
                            //nafs[idx].innerHTML = xhr.responseText;
                    }
            }
            xhr.open('POST', root+'/frontend/customerActivityAjax.php', true);              
            
            var data = new FormData(form);
            
            xhr.send(data);
    }
     
    if (nafs.length){
            nafs.forEach(function(curNaf, index){
                    curNaf.addEventListener('change', function(e){
                            handleChange(curNaf,index);
                    }, false );
            });
    }
    </script>
    	</body>
    </html>
    Tu vois qu'on peut faire des alignements facilement même avec des select imbriqués dans les labels. il suffit d'entourer le texte d'un "span" et ensuite de le mettre en display:inline-block et de lui attribuer une largeur, j'ai fait pareil pour les select (qui par défaut sont en display:inline-block), et je me sert des <p> pour un conteneur qui permet d'espacer les lignes en définissant leur hauteur.

    Il n'y a pas besoin d'id pour cibler tes champs, là j'utilise juste une classe "activite", et les span, select, et p sont ciblés par rapport à cet élément pour le css. Et la classe "activité" est elle même ciblée par form[name="tabForm"], ce qui fait qu'il n'y aura aucune ambiguïté possible avec les autre éléments de ta page (même si plus loin ils ont une classe "activite"). Evidemment j'aurais aussi pu utiliser un id="activite" pour faire plus simple, c'était pour te montrer que l'on peut aisément s'en passer si besoin (car il faut faire attention avec les id qui doivent être uniques pour tout le document).

    Tu vois aussi que j'ai utilisé la syntaxe "naf[]" sans indiquer d'index, car pas besoin avec javascript/html/php qui s'entendent très bien ensemble (pour dire que cette syntaxe ne fonctionne pas forcément avec tous les langages serveur, mais tant que tu utilises php c'est ok). Mais attention les index commenceront à 0 (il faudra modifier ton code php en conséquence) et c'est mieux ainsi pour compatibilité avec les tableaux javascript et php.

    Testes ce script dans une page séparée dans un premier temps et dans ta page customerActivityAjax.php fait en première ligne (le temps de tester) exit(var_dump($_POST));. Dans la console du navigateur -> onglet "réseau" et en cliquant sur la requête tu verras dans l'onglet "réponse" un tableau comme il faut, facilement exploitable par php. Ensuite tu pourras supprimer les options des trois derniers select dans le html que j'ai inclues pour le test.

    Ah oui une chose, j'avais repris ton dernier code mais avec FormData il ne faut pas utiliser xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); que j'ai supprimé.

    Concernant tes questions, le send de la requête ajax envoie des données, si tu n'en envoie pas, php ne recevra pas de données. Et concernant le exit côté php, il sert à sortir de la page et quand on lui met une variable en argument, il l'affiche en même temps. Pour afficher quelque chose et ne pas sortir du script fais des echo $valeur; et mets le exit (sans valeur) exit; à la suite de ta boucle (pas à l'intérieur), pour ordonner au script de sortir quand tu as terminé ton affichage.

    Concernant le fonctionnement des selects, faudrait nous montrer le retour de "console.log(xhr.responseText);" car je ne vois pas ton code.

  5. #5
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Citation Envoyé par ABCIWEB Voir le message
    Bonjour,

    Le plus simple est que tu testes le code ci-dessous dans une page séparée.
    ...
    Tu vois qu'on peut faire des alignements facilement même avec des select imbriqués dans les labels. il suffit d'entourer le texte d'un "span" et ensuite de le mettre en display:inline-block et de lui attribuer une largeur, j'ai fait pareil pour les select (qui par défaut sont en display:inline-block), et je me sert des <p> pour un conteneur qui permet d'espacer les lignes en définissant leur hauteur.

    Il n'y a pas besoin d'id pour cibler tes champs, là j'utilise juste une classe "activite", et les span, label, et p sont ciblés par rapport à cet élément pour le css. Et la classe "activité" est elle même ciblée par form[name="tabForm"], ce qui fait qu'il n'y aura aucune ambiguïté possible avec les autre éléments de ta page (même si plus loin ils ont une classe "activite"). Evidemment j'aurais aussi pu utiliser un id="activite" pour faire plus simple, c'était pour te montrer que l'on peut aisément s'en passer si besoin (car il faut faire attention avec les id qui doivent être uniques pour tout le document).
    Ton code marche très bien et répond à une problématique que je ne savais pas résoudre. Par contre il ne fonctionne plus si je remplace la liste par une variable. Dans ce cas dans le rendu, la liste passe en dessous de l'étiquette, comme-ci il y avait un '<br>' après le '</span>'. Je n'arrive pas à comprendre pourquoi.
    Voici ce que donnent le rendu et la console:
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    <label><span>Section</span><select name='naf[1]'><option value=''></option><option value='5'>Texte de l'option</option></select></label><br>
    le contenu de ma variable:
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    <select name='naf[1]'><option value=''></option><option value='5'>Texte de l'option</option></select>
    et le code html du formulaire:
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    <label><span>Section</span><?= $lstNaf[1]; ?></label><br>

  6. #6
    Modérateur
    Avatar de ProgElecT
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2004
    Messages
    6 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Retraité
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Décembre 2004
    Messages : 6 077
    Points : 17 175
    Points
    17 175
    Par défaut
    Salut

    Peut être que la nouvelle balise simplifié <?= n'est pas reconnu par ta version PHP, <?= = <php echo
    Soyez sympa, pensez -y
    Balises[CODE]...[/CODE]
    Balises[CODE=NomDuLangage]...[/CODE] quand vous mettez du code d'un autre langage que celui du forum ou vous postez.
    Balises[C]...[/C] code intégré dans une phrase.
    Balises[C=NomDuLangage]...[/C] code intégré dans une phrase quand vous mettez du code d'un autre langage que celui du forum ou vous postez.
    Le bouton en fin de discussion, quand vous avez obtenu l'aide attendue.
    ......... et pourquoi pas, pour remercier, un pour celui/ceux qui vous ont dépannés.
    👉 → → Ma page perso sur DVP ← ← 👈

  7. #7
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Citation Envoyé par ProgElecT Voir le message
    Peut être que la nouvelle balise simplifié <?= n'est pas reconnu par ta version PHP, <?= = <php echo
    C'est un sujet qui a été plusieurs fois évoqué sur ce forum. Ce raccourci est parfaitement reconnu depuis PHP 5.4.0 et nous en sommes à 8 et sur ce site j'utilise 7.4.0.

  8. #8
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 380
    Points : 10 410
    Points
    10 410
    Par défaut
    Citation Envoyé par moimp Voir le message
    et le code html du formulaire:
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    <label><span>Section</span><?= $lstNaf[1]; ?></label><br>
    Bah si tu vois ça dans ton html (dans la console), c'est manifestement que le code php n'est pas interprété dans ta page. Il sort d'où ce code ? C'est le code php affiché initialement dans ta page de formulaire ou c'est le retour de ta requête Ajax ?

    Si c'est le retour de ta requête ajax, c'est que ton code php n'a pas interprété les variables php, et javascript ne le fera pas à sa place. Consultes le retour de la réponse Ajax, il faut que ton html soit formé, tu ne dois plus voir de traces de php car php ne sera pas interprété en retour de la requête ajax.

    Si c'est le code affiché initialement par php dans ton formulaire, c'est que tu as un problème pour transmettre des variables php dans le formulaire (la vue). Comment fais-tu pour tes autres codes ?

    Au passage, concernant les index de ton tableau "naf", si tu tiens absolument à les indiquer dans le html (mais encore une fois tu n'es pas obligé avec php), commences les index à 0 et non pas à 1, sinon comme déjà dit, ça met le bin's avec javascript et php dont les tableaux sont naturellement indexés à partir de 0. Si tu dois faire une correction par la suite pour afficher 1 plutôt que 0 pour l'utilisateur, ne le fais qu'au dernier moment pour l'affichage utilisateur mais pas avant. Dans le code et les langages de programmation les tableaux numériques commencent avec l'index 0.

  9. #9
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Depuis que j'essaye de suivre tes conseils, ça va de mal en pis. J'ai tout à fait conscience que ça ne vient pas de toi mais de moi. Néanmoins je désespère et je réécris complètement mon code.

    Pour bien partir, j'ai déjà une première question:
    Dans cette ligne <label><span>Section</span><?= $lstNaf[0]; ?></label><br>, j'ai une variable $lstNaf[0] qui contient une balise select complète. Il me semble que dans ce cas, je dois mettre les index de tableaux de ma variable parce que je ne pense pas qu'ils se mettent automatiquement comme l'attribut nom. Est-ce qu'il vaut mieux ne pas les mettre?
    La variable contient par exemple: "<select name='naf[]'><option value='1'>texte option 1</option></select>". Je fais comme ceci parce que mes balises select et option sont construites à partir de classes PHP.

    EDIT: Après réécriture, je désespère complètement .
    Le CSS ne fonctionne pas et le fichier AJAX non plus.
    Pour le CSS, il ne s'agit pas d'un problème de variable comme j'ai pu l'écrire. J'ai transféré le style CSS dans ma feuille de style général et à titre de test, je l'ai aussi laissé dans la page d'entête de mon formulaire. Dans la console, je vois que certains styles sont pris en compte (élément p par exemple) mais pas l'affichage inline-block qui est pourtant par défaut dans mon fichier structure.css, dans mon fichier screen.css et répété dans l'entête head de mon formulaire. Il n'apparaît pas dans la console.
    En ce qui concerne le fichier AJAX, je n'arrive pas à mettre mes listes à jour. Voir le commentaire de la ligne 38.
    Extrait du fichier 'structure.css':
    Code CSS : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    label {
    	display:inline-block;
    	font-size:.8rem; /* Le choix de l'unité est volontaire pour permettre l'extension du champ si l'utilisateur grossi la police. */
    	width:5rem;
    }
    Fichier 'screen.css' (éléments concernés seulement):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    body
    {
    	font-family: Arial, "Times New Roman";
    	background-color:white;
    }
    h1, h2, h3, h4, h5, h6
    {
    	font-family: "Comic Sans MS";
    }
    h5
    {
    	font-size:.9rem;
    }
     
    fieldset {
    	border-color:#eee;
    }
    input[type="submit"]
    {
    	background-color:#bbb;
    }
    input[disabled], input[readonly], textarea[disabled], textarea[readonly] {
    	background-color:#bbb;
    	color:#666;
    	padding-left:3px;
    }
    input[type='checkbox'], input[type='radio']
    {
    	width:auto;
    	margin-right:5px;
    }
    textarea {
    	font-family:Arial;
    }
     
    				form[name="actForm"] .activity p {
    					line-height:30px;
    				}
     
    				form[name="actForm"] .activity span {
    					/*display:inline-block;*/ /* déjà dans structure.css */
    					width:100px;
                    }
     
                    form[name="actForm"] .activity select {
    					width:200px;
    				}
     
    form[name='tabForm']
    {
    	margin-top:-4px;
    	border:1px solid grey;
    	width:65rem;
    }
    .formFlex
    {
    	display:flex;
    	justify-content:start;
    	padding-top:10px;
    	padding:5px;
    	width:auto;
    }
    .formFlex>div, .formFlex>fieldset
    {
    	margin-right:20px;
    }
    .formFlex label
    {
    	width:8rem;
    }
    Rendu initial:
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    <!DOCTYPE html>
    <html lang="fr">
    	<head>
    		<meta charset="utf-8">
    		<!-- <meta http-equiv="Content-Type" content="text/html"> -->
    		<title>Sélection ou modification d'une activité</title>
     
    		<meta http-equiv="Expires" content="-1" />
    		<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
     
    		<link rel="stylesheet" media="all" type="text/css" href="../css/structure.css" />
    		<link rel="stylesheet" media="all" type="text/css" href="../css/screen.css" />
    		<link rel="stylesheet" media="print" type="text/css" href="../css/print.css" />
    		<style>
                                    form[name="actForm"] .activity p {
                                            line-height:30px;
                                    }
     
                                    form[name="actForm"] .activity span {
                                            display:inline-block;
                                            width:100px;
                    }
                    
                    form[name="actForm"] .activity select {
                                            width:200px;
                                    }
                    </style>
    	</head>
     
    	<body>
     
    <form method="post" name="actForm">
    	<input type="hidden" name="id" value="3011">
    	<input type="hidden" name="token" value="357b3843858b3f5766790b8997de7d61d4667d0c3c54fe0f">
    	<div class="formFlex">
    		<fieldset><legend>Activités répertoriées</legend>
    			<p class="note">// ...
    			</p>
    			<fieldset class="activity"><legend>Zone d'édition&nbsp;: Sélection d'une activité</legend>
    				<label><span>Section</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option><option value='1'>SECTION A - AGRICULTURE, SYLVICULTURE ET PÊCHE</option><option value='2'>SECTION B - ...</option></select></label><br>
    				<label><span>Division</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option></select></label><br>
    				<label><span>Groupe</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option></select></label><br>
    				<label><span>Activité</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option></select></label><br>
    			</fieldset>
    		</fieldset>
    	</div>
    </form>
     
    <script type="module" src="../js/customerActivitiesHandler.js"></script>
     
    	</body>
    </html>
    Fichier Ajax:
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    require_once('../classes/moimp/OptListSelect.php');
    require_once('../classes/moimp/OptListOption.php');
    require_once('../config.php');
    require_once('../model/model.php');
     
    if ( empty(session_id()) )
    	session_start();
     
    use OptListSelect\OptListSelect;   // Classe de création de liste d'options
    use OptListOption\OptListOption; // Classe de création d'une option de liste
     
    $token = isset($_POST['token']) ? $_POST['token'] : null;
    if(!isset($_SESSION['tokenLists'][$token]['token'])) exit('token invalide');
     
    function doNafList(int $iPrevLevel){
    	$language = $_SESSION['language'];
     
    	$iNewLevel	= $iPrevLevel+2; // +1 car on collecte le niveau suivant et +1 parce que la numérotation de la bdd démarre à 1
    	$iPrevId	= (int) $_POST['naf'][$iPrevLevel];
    	$data		= getNAF($language, $iNewLevel, $iPrevId);
    	//var_dump($data);
    	$lst		= new OptListSelect('naf[]', ['required'=>'required']);
    	$lst->addOption(new OptListOption('', '', ['label'=>getDBText($language,16)]));
    	if (!empty($data)){
    		foreach($data as $aItem){
    			$lst->addOption(new OptListOption($aItem['id'], $aItem['code'].' - '.$aItem[$language.'_text']));
    		}
    		unset($aItem);
    	}
    	//var_dump($lst);
    	//echo $lst; // Contenu correct: '<select name=naf[]>...</select>'
    	return $lst;
    }
     
    for($i=0;$i<3;$i++){
    	if (isset($_POST['naf'][$i])){
    		$lstNaf[$i] = doNafList($i);
    		echo $lstNaf[$i]; // Le code s'affiche dans la console MAIS la liste ne se met pas à jour dans le formulaire
    	}
    }
    exit;

  10. #10
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 380
    Points : 10 410
    Points
    10 410
    Par défaut
    Citation Envoyé par moimp Voir le message
    Depuis que j'essaye de suivre tes conseils, ça va de mal en pis. J'ai tout à fait conscience que ça ne vient pas de toi mais de moi. Néanmoins je désespère et je réécris complètement mon code.
    Tu n'étais pas obligé de suivre exactement tous mes exemples, tu peux aussi prendre uniquement ce qui t'arrange. Les span autour du texte du label, c'était pour te montrer qu'on pouvait facilement cibler et formater le formulaire sans qu'il soit bardé d'id, de même tu peux continuer d'indexer tes tableaux naf[] même si cela n'est pas nécessaire. La seule chose qu'il fallait retenir c'est que si tu les indexe, c'est mieux de commencer avec d'index 0.

    Pour répondre une dernière fois à ta question, dans le contexte html/javascript/php, le bloc suivant :
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    <select name='naf[]'><option value='1'>texte option 1</option></select>
    <select name='naf[]'><option value='2'>texte option 2</option></select>
    est égal au bloc suivant :
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    <select name='naf[0]'><option value='1'>texte option 1</option></select>
    <select name='naf[1]'><option value='2'>texte option 2</option></select>

    C'est le même principe que pour la construction de tableaux numériques en php. Dans une page php séparée tu peux faire :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $tab[] = 'A';
    $tab[] = 'B';
    $tab[] = 'C';
    var_dump($tab);
    Et tu verras un tableau indexé automatiquement dans l'ordre où les lignes sont écrites. Cela revient au même que de faire:
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $tab[0] = 'A';
    $tab[1] = 'B';
    $tab[2] = 'C';
    var_dump($tab);

    Pour le reste il faut traiter les problèmes séparément et y aller progressivement.
    Dans ton css, je vois des "form[name="actForm"]", mais aussi un form[name='tabForm'], et comme tu as renommé ton formulaire en name="actForm" la cible form[name='tabForm'] ne correspond à rien.

    Aussi dans le code javascript de mon exemple, le formulaire est ciblé avec form = document.querySelector("form[name=tabForm]") donc puisque tu as changé le nom de ton formulaire il faut écrire form = document.querySelector("form[name=actForm]") (si tu as utilisé mon exemple).

    Concernant tes css si tu supprimes ce bloc
    Code css : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    .formFlex label
    {
    	width:8rem;
    }
    et également le "width: 5rem" dans ce bloc
    Code css : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    label {
        display: inline-block;
        font-size: .8rem;
        width: 5rem;
    }

    Alors ta mise en page fonctionne et les labels sont alignés avec les select.

    Et si tu veux que je t'aide pour la mise à jour de tes select au retour de la requête ajax, je t'ai déjà dit que j'avais besoin de voir le retour de cette requête ajax, soit le contenu de console.log(xhr.responseText); (toujours dans le cadre de l'exemple que je t'ai donné plus haut).

  11. #11
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Je connais bien la constitution de tableau avec indexation automatique en PHP mais j'ignorais que cela pouvait aussi se faire en html. Je trouve que c'est judicieux et c'est pourquoi je l'ai adopté ici.

    Pour le reste il faut traiter les problèmes séparément et y aller progressivement.
    Dans ton css, je vois des "form[name="actForm"]", mais aussi un form[name='tabForm'], et comme tu as renommé ton formulaire en name="actForm" la cible form[name='tabForm'] ne correspond à rien.
    C'est tout à fait volontaire. 'tabForm' est utilisé pour un ensemble d'autres formulaires et celui-ci étant atypique, j'ai renommé mon formulaire 'actForm' pour cibler des styles différents. J'ai vérifié qu'il n'y a pas de confusion entre les deux.

    Aussi dans le code javascript de mon exemple, le formulaire est ciblé avec form = document.querySelector("form[name=tabForm]") donc puisque tu as changé le nom de ton formulaire il faut écrire form = document.querySelector("form[name=actForm]") (si tu as utilisé mon exemple).
    Je ne t'ai pas joint le code JavaScript mais la correction avait bien été faite.

    Concernant tes css si tu supprimes ce bloc
    Code css : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    .formFlex label
    {
    	width:8rem;
    }
    et également le "width: 5rem" dans ce bloc
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    label {
        display: inline-block;
        font-size: .8rem;
        width: 5rem;
    }
    C'est effectivement ici qu'il y avait conflit. Il faudra donc que j'ajoute un :not ou que le les différencie avec des noms différents. Je peux peut-être aussi écrire une feuille de style spécifique en remplacement de mes feuilles de styles standard. La dernière solution serait peut-être la meilleure. Le problème CSS devrait donc être résolu.

    Et si tu veux que je t'aide pour la mise à jour de tes select au retour de la requête ajax, je t'ai déjà dit que j'avais besoin de voir le retour de cette requête ajax, soit le contenu de console.log(xhr.responseText); (toujours dans le cadre de l'exemple que je t'ai donné plus haut).
    Voici le résultat après indentation:
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    <!-- Après sélection du premier niveau -->
    <select name='naf[]' required='required'>
    	<option value='' label='&lt; ---- &gt;'></option>
    	<option value='4'>5 - Extraction de houille et de lignite</option>
    	<option value='5'>6 - Extraction d'hydrocarbures</option>
    	<option value='6'>7 - Extraction de minerais métalliques</option>
    	<option value='7'>8 - Autres industries extractives</option>
    	<option value='8'>9 - Services de soutien aux industries extractives</option>
    </select>
    <select name='naf[]' required='required'>
    	<option value='' label='&lt; ---- &gt;'></option>
    </select>
    <select name='naf[]' required='required'>
    	<option value='' label='&lt; ---- &gt;'></option>
    </select>
     
    <!-- Après sélection du second niveau -->
    <select name='naf[]' required='required'>
    	<option value='' label='&lt; ---- &gt;'></option>
    	<option value='4'>5 - Extraction de houille et de lignite</option>
    	<option value='5'>6 - Extraction d'hydrocarbures</option>
    	<option value='6'>7 - Extraction de minerais métalliques</option>
    	<option value='7'>8 - Autres industries extractives</option>
    	<option value='8'>9 - Services de soutien aux industries extractives</option>
    </select>
    <select name='naf[]' required='required'>
    	<option value='' label='&lt; ---- &gt;'></option>
    	<option value='14'>05.1 - Extraction de houille</option>
    	<option value='15'>05.2 - Extraction de lignite</option>
    </select>
    <select name='naf[]' required='required'>
    	<option value='' label='&lt; ---- &gt;'></option>
    </select>
    Pour moi, ces réponses sont correctes. EDIT: mais à la ligne nafs[idx+1].innerHTML = xhr.responseText;, les options s'ajoutent au lieu d'être remplacées.

  12. #12
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 380
    Points : 10 410
    Points
    10 410
    Par défaut
    Citation Envoyé par moimp Voir le message
    C'est effectivement ici qu'il y avait conflit. Il faudra donc que j'ajoute un :not ou que le les différencie avec des noms différents. Je peux peut-être aussi écrire une feuille de style spécifique en remplacement de mes feuilles de styles standard. La dernière solution serait peut-être la meilleure. Le problème CSS devrait donc être résolu.
    Le plus simple est de cibler ces labels avec form[name="actForm"] .activity label { width:auto;}. Pour dire que les éléments ciblés au plus près ont la priorité par rapport aux éléments ciblés de plus loin et à fortiori par rapport aux déclarations globales comme label {...}.

    Pour tes selects en retour de la réponse ajax, débrouilles-toi pour ne renvoyer de préférence que les options correspondantes au select que tu dois renseigner, ce sera plus simple, ou au pire le select avec ses options mais pas tous les sélect.

    Dans ton code php tu peux utiliser "array_filter" sur le tableau "naf" pour supprimer les valeurs qui ne sont pas renseignées, donc ensuite le nombre d'éléments de ton tableau te donnes le numéro d'index du select et des options qu'il faut retourner. En d'autre termes, dans tous les cas tu as un tableau "naf" indexé 0,1,2,3. Si le visiteur sélectionne le troisième select, étant donné que le quatrième select (indexé 3) n'a pas de valeur, après utilisation de "array_filter", le tableau résultant ne contiendra plus que trois éléments (indexé 0,1,2). Et le "count" de ce tableau indiquera "3" c'est à dire le prochain select qu'il faut renseigner et donc les options qu'il faut renvoyer.

    Ensuite je te donnerai un exemple pour insérer ces options dans le select côté javascript. Mais avant il faudrait un retour épuré donc dis moi si tu renvoies uniquement les options (ce serait plus simple) ou un select avec ses options, mais évites absolument tous les selects sinon ça fait des données inutiles et du tri supplémentaire tout aussi inutile à faire côté javascript.

  13. #13
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Merci ABCIWEB pour tes exemples, tes conseils et surtout ta patience.
    Le sujet est presque résolu.
    Il ne me reste plus qu'un problème à résoudre: Lorsque l'utilisateur revient en arrière et modifie une option de niveau supérieur (0 ou 1 par exemple), les listes dépendantes devraient être réinitialisées. J'ai essayé de le faire en ajoutant data.append('changed', idx); après var data = new FormData(form); et en PHP en ajoutant ceci en tête du code AJAX:
    Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function doEmptyList(int $key){
    	$language = $_SESSION['language'];
     
    	$pattern	= "<option value=%s>%s</option>";
    	$html		= "<option value='' label='&gt; --- &lt;'>''</option>";
    	return $html;
    }
    foreach($_POST['naf'] as $key=>$value){
    	var_export($key);
    	if($key > $_POST['changed']){
    		$lstNaf[$key] = doEmptyList($key);
    		echo $lstNaf[$key];
    	}
    }
    Je m'attendais à ce que les listes réinitialisées apparaissent dans console.log(xhr.responseText); mais je retombe dans le problème précédent avec des options vides qui s'accumulent. Faut-il plutôt traiter le problème en JS?

    EDIT: J'ai essayé de traiter ce retour utilisateur en arrière avec les lignes 8 et 20 à 24 mais la liste qui suit la liste modifiée reste vide. Pourquoi? Voici mon code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    const
    	form	= document.querySelector("form[name=actForm]")
    	,nafs	= form.querySelectorAll("select[name='naf[]']")
    	,root	= window.location.origin
    	;
     
    //console.log(nafs);
    console.log(emptyOption); // Créé en PHP, retourne "<option value='' label='&lt; ---- &gt;'></option>"
     
    function handleChange(idx) {
    	var xhr = new XMLHttpRequest();
     
    	xhr.onreadystatechange = function(){
     
    		if (xhr.readyState == 4 && xhr.status == 200 && nafs[idx+1] !== undefined){
    			//console.log(xhr.responseText);
    			//console.log(idx+1);
    			nafs[idx+1].innerHTML = xhr.responseText;
    			//console.log(nafs[idx+1]); // retourne la balise select complète
    			for(let i=idx+2;i<4;i++){
    				//console.log(i);
    				nafs[i].innerHTML = emptyOption;
    				//console.log(nafs[i]); // retourne la balise select complète
    			}
    			// pour test:
    			for(let i=0;i<4;i++){
    				console.log(nafs[i]);
    			}
    		}
    	}
    	xhr.open('POST', root+'/frontend/customerActivityAjax.php', true);
     
    	var data = new FormData(form);
    	data.append('changed', idx);
     
    	xhr.send(data);
    }
     
    if (nafs.length){
    	nafs.forEach(function(curNaf, index){
    		curNaf.addEventListener('change', function(e){
    			handleChange(index);
    		}, false );
    	});
    }

  14. #14
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 380
    Points : 10 410
    Points
    10 410
    Par défaut
    Citation Envoyé par moimp Voir le message
    Merci ABCIWEB pour tes exemples, tes conseils et surtout ta patience.
    Le sujet est presque résolu.
    Il ne me reste plus qu'un problème à résoudre: Lorsque l'utilisateur revient en arrière et modifie une option de niveau supérieur (0 ou 1 par exemple), les listes dépendantes devraient être réinitialisées. J'ai essayé de le faire en ajoutant data.append('changed', idx); après var data = new FormData(form); et en PHP en ajoutant ceci en tête du code AJAX:
    Code PHP : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function doEmptyList(int $key){
    	$language = $_SESSION['language'];
     
    	$pattern	= "<option value=%s>%s</option>";
    	$html		= "<option value='' label='&gt; --- &lt;'>''</option>";
    	return $html;
    }
    foreach($_POST['naf'] as $key=>$value){
    	var_export($key);
    	if($key > $_POST['changed']){
    		$lstNaf[$key] = doEmptyList($key);
    		echo $lstNaf[$key];
    	}
    }
    Bah oui tu renvoies une liste vide. Sur le principe il est pas mal ce code, mais tu devrais t'en servir pour renvoyer des options remplies et non pas vides. D'ailleurs le $pattern (inutilisé pour l'instant) suggère que tu voulais rechercher des valeurs dans un code qui les contient, il faut aller jusqu'au bout de cette idée et toujours renvoyer les options correspondantes au prochain sélect à renseigner. Sauf évidemment pour la dernière qui devrait retourner le résultat de toutes ces sélections si tu veux donner le résultat dans cette même page (ce qui serait logique).

    Pour les retours en arrière, oui, cela se traite en javascript, j'avais donné l'exemple avec jquery ici : à chaque fois que tu cliques sur un select, tu sélectionnes la première option des selects suivants, et tu affectes aux selects suivants la propriété "disable=true". Et au retour de la requête ajax tu affectes au nouveau select renseigné la propriété "disable=false".

    Reste à traduire ça en javascript. Si tu as besoin d'aide pour le mettre en oeuvre, donnes-moi TOUT ton code ajax PHP, et tout ton code javascript pour que j'ai une vision d'ensemble (et également le code du formulaire s'il a changé depuis la dernière fois). Car évidemment le principe d'Ajax, c'est une dépendance stricte entre le html, le code javascript et le code php. Avec une vision parcellaire je risque de donner du code qui ne fonctionnera pas et j'aimerais bien ne pas recommencer mille fois.

    Et on est bien d'accord que dans tous les cas (sauf pour le dernier select qui devrait retourner le résultat final des sélections), je veux (et j'exige ) un retour Ajax avec des options remplies correspondant au sélect à renseigner, et ce serait bien que je puisse voir un échantillon de ce retour ajax.

    C'est pas pour t'embêter, hein, c'est pour travailler dans de bonnes conditions avec les bonnes données, sinon l'histoire peut durer indéfiniment.

  15. #15
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Le code exemple que tu donnes correspond exactement à ce que je veux faire. Son seul inconvénient est que je ne connais pas JQuery et que je préfères utiliser JS pur.
    Je te donne ci-dessous mon code actuel. Ce code fonctionne tant que l'utilisateur ne revient pas en arrière. Il renvoie bien le select suivant (sauf dans le cas d'un retour en arrière)


    Citation Envoyé par ABCIWEB Voir le message
    Sur le principe il est pas mal ce code, mais tu devrais t'en servir pour renvoyer des options remplies et non pas vides. D'ailleurs le $pattern (inutilisé pour l'instant) suggère que tu voulais rechercher des valeurs dans un code qui les contient, il faut aller jusqu'au bout de cette idée et toujours renvoyer les options correspondantes au prochain sélect à renseigner.
    C'est ce qui se passe dans mon code, sauf justement dans le cas d'un retour en arrière.

    Citation Envoyé par ABCIWEB Voir le message
    Pour les retours en arrière, oui, cela se traite en javascript, j'avais donné l'exemple avec jquery ici : à chaque fois que tu cliques sur un select, tu sélectionnes la première option des selects suivants, et tu affectes aux selects suivants la propriété "disable=true". Et au retour de la requête ajax tu affectes au nouveau select renseigné la propriété "disable=false".

    Reste à traduire ça en javascript. Si tu as besoin d'aide pour le mettre en oeuvre, donnes-moi TOUT ton code ajax PHP, et tout ton code javascript pour que j'ai une vision d'ensemble (et également le code du formulaire s'il a changé depuis la dernière fois). Car évidemment le principe d'Ajax, c'est une dépendance stricte entre le html, le code javascript et le code php. Avec une vision parcellaire je risque de donner du code qui ne fonctionnera pas et j'aimerais bien ne pas recommencer mille fois.
    C'est effectivement là que j'ai besoin de ton aide.

    Citation Envoyé par ABCIWEB Voir le message
    Et on est bien d'accord que dans tous les cas (sauf pour le dernier select qui devrait retourner le résultat final des sélections), je veux (et j'exige ) un retour Ajax avec des options remplies correspondant au sélect à renseigner, et ce serait bien que je puisse voir un échantillon de ce retour ajax.
    Je pense que c'est bien le cas si j'ai bien compris ce que tu veux dire.

    Citation Envoyé par ABCIWEB Voir le message
    C'est pas pour t'embêter, hein, c'est pour travailler dans de bonnes conditions avec les bonnes données, sinon l'histoire peut durer indéfiniment.
    Bien évidemment, ce n'est l'intérêt de personne de faire durer.

    Maintenant je te donne les codes et les retours AJAX:

    Code initial de la page:
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    <!DOCTYPE html>
    <html lang="fr">
    	<head>
    		<meta charset="utf-8">
    		<title>Sélection ou modification d'une activité</title>
     
    		<meta http-equiv="Expires" content="-1" />
    		<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
     
    		<link rel="stylesheet" media="all" type="text/css" href="../css/activity.css">
    	</head>
     
    	<body>
     
    <form method="post" name="actForm">
    	<h3 class="formTitle">Sélection progressive d'une activité</h3>
    	<input type="hidden" name="id" value="3011">
    	<input type="hidden" name="token" value="edf97fba5e3bfeb83aa4d46639426568f3093c490304a996">
    	<div class="formFlex">
    		<fieldset><legend>Activités répertoriées</legend>
    			<p class="note">
    				Ici vous pouvez sélectionner des activités selon la nomenclature NAF de l'INSEE (rév. 2) 
    				ce qui peut vous permettre de rechercher les entreprises qui ont la même activité.<br>
    				Ces codes sont indépendants de celui du registre du commerce. Mettez ici les activités qui correpondent
    				le mieux à celles du client en sélectionnant d'abord la section et enfin l'activité.
    			</p>
    			<fieldset class="activity"><legend>Zone d'édition&nbsp;: Sélection d'une activité</legend>
    				<label><span>Section</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option><option value='1'>SECTION A - AGRICULTURE, SYLVICULTURE ET PÊCHE</option><option value='2'>SECTION B - INDUSTRIES EXTRACTIVES</option><option value='3'>SECTION C - INDUSTRIE MANUFACTURIÈRE</option></select></label><br>
    				<label><span>Division</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option></select></label><br> <!-- ajouter disabled après mise au point JS -->
    				<label><span>Groupe</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option></select></label><br> <!-- ajouter disabled après mise au point JS -->
    				<label><span>Activité</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option></select></label><br> <!-- ajouter disabled après mise au point JS -->
    			</fieldset>
    		</fieldset>
    	</div>
    </form>
     
    <script>const emptyOption = "<option value='' label='&lt; ---- &gt;'><\/option>";</script>
    <script type="module" src="../js/customerActivitiesHandler.js"></script>
     
    	</body>
    </html>
    Code JS : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    const
    	form	= document.querySelector("form[name=actForm]")
    	,nafs	= form.querySelectorAll("select[name='naf[]']")
    	,root	= window.location.origin
    	;
     
    console.log(emptyOption); // Créé en PHP, retourne "<option value='' label='&lt; ---- &gt;'></option>"
     
    function handleChange(idx) {
    	var xhr = new XMLHttpRequest();
     
    	xhr.onreadystatechange = function(){
     
    		if (xhr.readyState == 4 && xhr.status == 200 && nafs[idx+1] !== undefined){
    			console.log(xhr.responseText);
    			nafs[idx+1].innerHTML = xhr.responseText;
    		}
    	}
    	xhr.open('POST', root+'/frontend/customerActivityAjax.php', true);
     
    	var data = new FormData(form);
    	//data.append('changed', idx); // inutilisé pour l'instant
     
    	xhr.send(data);
    }
     
    if (nafs.length){
    	nafs.forEach(function(curNaf, index){
    		curNaf.addEventListener('change', function(e){
    			handleChange(index);
     
     
    			for(let i=index+2;i<4;i++){
    				nafs[i].innerHTML = emptyOption;
    				console.log(i);
    			}
    			console.log(nafs);
     
     
    		}, false );
    	});
    }
    Code Ajax:
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    if ( empty(session_id()) )
    	session_start();
     
    $token = isset($_POST['token']) ? $_POST['token'] : null;
    if(!isset($_SESSION['tokenLists'][$token]['token'])) exit('token invalide');
     
    function doOptionsHTML(int $iPrevLevel){
    	$language = $_SESSION['language'];
     
    	$iNewLevel	= $iPrevLevel+2; // +1 car on collecte le niveau suivant et +1 parce que la numérotation de la bdd démarre à 1
    	$iPrevId	= (int) $_POST['naf'][$iPrevLevel];
    	$data		= getNAF($language, $iNewLevel, $iPrevId);
    	$pattern	= "<option value=%s>%s</option>";
    	$html		= "<option value='' label='".getDBText($language,16)."'>''</option>";
    	if (!empty($data)){
    		foreach($data as $aItem){
    			$html .= sprintf($pattern, $aItem['id'], $aItem['code'].' - '.$aItem[$language.'_text']);
    		}
    	}
    	//var_export($html);
    	return $html;
    }
     
    // Code à rationaliser après mise au point du JS et de ce qui précède
    if (!empty($_POST['naf']['3'])){
    	// j'autorise l'enregistrement
    }
    elseif(!empty($_POST['naf'][2])){
    	$lstNaf[2] = doOptionsHTML(2);
    	echo $lstNaf[2];
    }
    elseif(!empty($_POST['naf'][1])){
    	$lstNaf[1] = doOptionsHTML(1);
    	echo $lstNaf[1];
    }
    elseif(!empty($_POST['naf'][0])){
    	$lstNaf[0] = doOptionsHTML(0);
    	echo $lstNaf[0];
    }
    exit;
    Voici les retours Ajax successifs:
    Niveau 1:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <option value='' label='&lt; ---- &gt;'>''</option><option value=4>5 - Extraction de houille et de lignite</option><option value=5>6 - Extraction d'hydrocarbures</option><option value=6>7 - Extraction de minerais métalliques</option><option value=7>8 - Autres industries extractives</option><option value=8>9 - Services de soutien aux industries extractives</option>
    Niveau 2:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <option value='' label='&lt; ---- &gt;'>''</option><option value=14>05.1 - Extraction de houille</option><option value=15>05.2 - Extraction de lignite</option>
    Niveau 3 final:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <option value='' label='&lt; ---- &gt;'>''</option><option value=40>05.10Z - Extraction de houille</option>
    Cette fois-ci, j'espère que c'est la fin.

  16. #16
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 380
    Points : 10 410
    Points
    10 410
    Par défaut
    Bonjour,

    Oui on ne devrait plus être loin du compte :

    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    <body>
     
    <form method="post" name="actForm">
    	<h3 class="formTitle">Sélection progressive d'une activité</h3>
    	<input type="hidden" name="id" value="3011">
    	<input type="hidden" name="token" value="edf97fba5e3bfeb83aa4d46639426568f3093c490304a996">
    	<div class="formFlex">
    		<fieldset><legend>Activités répertoriées</legend>
    			<p class="note">
    				Ici vous pouvez sélectionner des activités selon la nomenclature NAF de l'INSEE (rév. 2) 
    				ce qui peut vous permettre de rechercher les entreprises qui ont la même activité.<br>
    				Ces codes sont indépendants de celui du registre du commerce. Mettez ici les activités qui correpondent
    				le mieux à celles du client en sélectionnant d'abord la section et enfin l'activité.
    			</p>
    			<fieldset class="activity"><legend>Zone d'édition&nbsp;: Sélection d'une activité</legend>
    				<label><span>Section</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option><option value='1'>SECTION A - AGRICULTURE, SYLVICULTURE ET PÊCHE</option><option value='2'>SECTION B - INDUSTRIES EXTRACTIVES</option><option value='3'>SECTION C - INDUSTRIE MANUFACTURIÈRE</option></select></label><br>
    				<label><span>Division</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option></select></label><br> <!-- ajouter disabled après mise au point JS -->
    				<label><span>Groupe</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option></select></label><br> <!-- ajouter disabled après mise au point JS -->
    				<label><span>Activité</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option></select></label><br> <!-- ajouter disabled après mise au point JS -->
    			</fieldset>
    		</fieldset>
    	</div>
    </form>
    <div id="resultat"></div>
     
    <script>
    const
            form    = document.querySelector("form[name=actForm]")
            ,nafs   = form.querySelectorAll("select[name='naf[]']")
            ,root   = window.location.origin
            ,resultat = document.getElementById("resultat")
            ;
     
    //console.log(emptyOption); // Créé en PHP, retourne "<option value='' label='&lt; ---- &gt;'></option>"
     
    function handleChange(idx,cible) {
            var xhr = new XMLHttpRequest();
     
            xhr.onreadystatechange = function(){
     
                    if (xhr.readyState == 4 && xhr.status == 200){
                            //console.log(xhr.responseText);
                            
                            if (cible.tagName == 'SELECT')  { 
                                    cible.disabled = false;
                            }
                            cible.innerHTML = xhr.responseText;
                    }
            }
            xhr.open('POST', root+'/frontend/customerActivityAjax.php', true);
     
            var data = new FormData(form);
            //data.append('changed', idx); // inutilisé pour l'instant
     
            xhr.send(data);
    }
     
    if (nafs.length){
            nafs.forEach(function(curNaf, index){
                    curNaf.addEventListener('change', function(e){
                            
                            // Vide le div des résultats
                            resultat.innerHTML = '';
                                                    
                            var cible
                            ,nextselect;
                            nafs.forEach(function(sel, i){
                                    
                                    // console.log(curNaf.isSameNode(sel));
                                    /* Si le select (sel) contenu dans la liste des sélecteurs correspond au sélecteur utilisé (curNaf),
                                    trouve le prochain sélecteur et si c'est le dernier on change de cible pour afficher le contenu au retour de la requête ajax
                                    */
                                    
                                    nextselect = nafs[i+1];
                                    
                                    if(curNaf.isSameNode(sel)) {
                                            cible = nextselect != undefined ? nextselect : resultat;
                                    }
     
                                    //console.log(cible);
                                    /* Si cible est défini c'est que l'on est (ou que l'on a passé) le select en cours, on selectionne la première option pour les 
                                    sélecteurs suivants pour avoir une valeur vide et on les met en disable sinon on aurait des affichages ou des résultas incohérents 
                                    en cas de sélections successives.
                                    */
                                    if (cible && nextselect != undefined) {
                                            
                                            nextselect.getElementsByTagName('option')[0].selected = 'selected';
                                            nextselect.disabled = true;
                                    }
                            })
                            
                            handleChange(index, cible);
     
                    }, false );
            });
    }
    </script>
    </body>
    Donc j'ai repris exactement le même principe qu'avec l'exemple jQuery. En fait à chaque clic sur un select, je met tous les suivants en disabled en ayant sélectionné leur première option, c'est une astuce qui évite d'avoir à effacer les options existantes en cas de changement du précédent select. Et au retour de la requête ajax je remet le select enabled (disabled = false).

    J'ai rajouté une div de résultat pour afficher quelque chose après le dernier select, dans ton fichier ajax cela suppose quelque chose comme ça :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //...
    if (!empty($_POST['naf']['3'])){
    	// j'autorise l'enregistrement
    	// code quelconque...
     
    	// confirmation en retour ajax
    	$message = 'Vous êtes enregistré avec les options : ' . $_POST['naf'][0] .', ' . $_POST['naf'][1] .', ' . $_POST['naf'][2] .', ' . $_POST['naf'][3];
    	echo htmlspecialchars($message);
     
    }
    //...

    Sinon dans tes retours ajax, ce serait bien que les valeurs des options soient entourées de quote ou de double quote, mieux vaut respecter le standard.

    Chez moi ça fonctionne. Tiens nous au courant quoiqu'il arrive. Et lors de ton dernier message, si tout est résolu n'oublies pas de cliquer sur le bouton "résolu", cela permet aux autres visiteurs de se référer à cette discussion en sachant qu'elle contient une réponse fonctionnelle - d'ailleurs dans le même but, le principe est de mettre aussi des "pouces vert" dans chaque message qui t'a aidé (pour une fois que les systèmes de notation servent à quelque chose, il faut les utiliser).

    A bientôt.

  17. #17
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    J'ai mis des quotes sur les valeurs des options, c'était un oubli.
    Ton code fonctionne à la perfection. Il me reste encore à analyser plus finement ton code JS, à traiter le résultat du formulaire et à modifier quelques noms de variables dans le respect de mes propres conventions de nommage.
    Encore un grand, un très grand merci. Ouf!

  18. #18
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Je rencontre maintenant des difficultés pour la suite et le traitement du formulaire:
    Une erreur en commentaire apparaît parfois dans cette partie de code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    			if (cible && nextselect != undefined) {
    				/*
    				La ligne suivante provoque parfois une erreur lors d'un retour en arrière lorsque toutes les options ont été sélectionnéees.
    				De mémoire l'erreur est "Cannot apply selected on undefined."
    				*/
    				nextselect.getElementsByTagName('option')[0].selected = 'selected';
    				nextselect.disabled = true;
    			}
    Pour le traitement, je ne souhaite pas afficher le résultat mais rendre enabled le bouton d'enregistrement 'save', ajouté en dessous des select et j'ai modifié le code comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    const
    	form	= document.querySelector("form[name=actForm]")
    	,nafs   = form.querySelectorAll("select[name='naf[]']")
    	,root   = window.location.origin
    	//,resultat = document.getElementById("resultat")
    	,btnSave= document.querySelector("[name='save']")
    	;
    // Dans l'écouteur
    			//resultat.innerHTML = '';
    			btnSave.disabled = true;
    			// Suite du code...
    				if(curNaf.isSameNode(sel)) {
    					// ligne suivante remplacée par le code qui suit
    					//cible = nextselect != undefined ? nextselect : resultat;
    					if (nextselect != undefined){
    						cible = nextselect;
    					}
    					else{
    						btnSave.disabled = false;
    					}
    Cette modification bloque le deuxième select après sélection du premier et je ne trouve pas pourquoi.

  19. #19
    Expert éminent sénior

    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2010
    Messages
    5 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2010
    Messages : 5 380
    Points : 10 410
    Points
    10 410
    Par défaut
    Salut,

    Essaies ça :
    Code html : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    <body>
     
    <form method="post" name="actForm">
    	<h3 class="formTitle">Sélection progressive d'une activité</h3>
    	<input type="hidden" name="id" value="3011">
    	<input type="hidden" name="token" value="edf97fba5e3bfeb83aa4d46639426568f3093c490304a996">
    	<div class="formFlex">
    		<fieldset><legend>Activités répertoriées</legend>
    			<p class="note">
    				Ici vous pouvez sélectionner des activités selon la nomenclature NAF de l'INSEE (rév. 2) 
    				ce qui peut vous permettre de rechercher les entreprises qui ont la même activité.<br>
    				Ces codes sont indépendants de celui du registre du commerce. Mettez ici les activités qui correpondent
    				le mieux à celles du client en sélectionnant d'abord la section et enfin l'activité.
    			</p>
    			<fieldset class="activity"><legend>Zone d'édition&nbsp;: Sélection d'une activité</legend>
    				<label><span>Section</span><select name='naf[]'><option value='' label='&lt; ---- &gt;'></option><option value='1'>SECTION A - AGRICULTURE, SYLVICULTURE ET PÊCHE</option><option value='2'>SECTION B - INDUSTRIES EXTRACTIVES</option><option value='3'>SECTION C - INDUSTRIE MANUFACTURIÈRE</option></select></label><br>
    				<label><span>Division</span><select disabled name='naf[]'></select></label><br> <!-- ajouter disabled après mise au point JS -->
    				<label><span>Groupe</span><select disabled name='naf[]'></select></label><br> <!-- ajouter disabled après mise au point JS -->
    				<label><span>Activité</span><select disabled name='naf[]'></select></label><br> <!-- ajouter disabled après mise au point JS -->
    			</fieldset>
    		</fieldset>
            <p style="text-align:center"><input type="button" disabled name="save" value="Save" style="font-size:1.5em;padding:0.1em 1em;border:1px solid #EFEFEF;opacity:0.5;cursor:pointer"></p>
    	</div>
    </form>
     
    <script>
    const
            form    = document.querySelector("form[name=actForm]")
            ,nafs   = form.querySelectorAll("select[name='naf[]']")
            ,nafLength = nafs.length
            ,save = form.querySelector("input[name=save]")
            ,root   = window.location.origin
            ;
     
    //console.log(emptyOption); // Créé en PHP, retourne "<option value='' label='&lt; ---- &gt;'></option>"
     
    function handleChange(cibleselect) {
            var xhr = new XMLHttpRequest();
     
            xhr.onreadystatechange = function(){
     
                    if (xhr.readyState == 4 && xhr.status == 200){
                            //console.log(xhr.responseText);
                            
                            if (cibleselect) { 
                                    cibleselect.disabled = false;
                                    cibleselect.innerHTML = xhr.responseText;
                            }
                            else {
                                    // Réactive le bouton de sauvegarde
                                    save.disabled = false;
                                    save.style.borderColor = '#090';
                                    save.style.opacity = '1';
                            }
                            
                    }
            }
            xhr.open('POST', root+'/frontend/customerActivityAjax.php', true);
     
            var data = new FormData(form);
     
            xhr.send(data);
    }
     
    if (nafLength){
            nafs.forEach(function(curNaf, index){
                    curNaf.addEventListener('change', function(e){
                            
                            // Désactive le bouton de sauvegarde
                            save.disabled = true;
                            save.style.borderColor = '#EFEFEF';
                            save.style.opacity = '0.5';
                                                    
                            var cibleselect
                            ,nextselect
                            ,nextoptions
                            ;
                            nafs.forEach(function(sel, i){
                                    
                                    //console.log(curNaf.isSameNode(sel));
                                    /* Si le select (sel) contenu dans la liste des selecteurs correspond au sélecteur utilisé (curNaf),
                                    trouve le prochain sélecteur et défini cibleselect
                                    */
                                    
                                    nextselect = nafs[i+1];
                                    
                                    if(curNaf.isSameNode(sel) && nextselect != undefined) {cibleselect = nextselect;}
                                    
                                    if (cibleselect && nextselect != undefined) {
                                            nextselect.disabled = true;
                                            nextoptions = nextselect.getElementsByTagName('option');
                                            if(nextoptions.length) {
                                                    nextoptions[0].selected = 'selected';
                                            }
                                    }
                            })
                            
                            if(curNaf.selectedIndex > 0) {
                                    handleChange(cibleselect);
                            }
     
                    }, false );
            });
    }
    </script>
    </body>

    J'ai fait une condition pour déclencher handleChange pour ne pas qu'un click sur une option vide de début de liste déclenche une requête ajax. J'ai aussi ajouté une variable "nextoptions" pour contrôler qu'il existe des options dans le select, d'où le fait que j'ai pu faire le test avec des selects sans option pour l'affichage initial de la page.

    Enfin sur le principe c'est au retour de la requête ajax que l'on doit rendre accessible le bouton save, et non pas dans l'écouteur comme tu le faisait. D'ailleurs tu pourrais renforcer ce contrôle: en admettant que la requête ajax retourne "selectionok" pour le dernier select, tu pourrais faire :

    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
                             if (cibleselect) { 
    				cibleselect.disabled = false;
    				cibleselect.innerHTML = xhr.responseText;
    			}
    			else if  (xhr.responseText == 'selectionok') {
    				// Réactive le bouton de sauvegarde
    				save.disabled = false;
    				save.style.borderColor = '#090';
    				save.style.opacity = '1';
    			}

  20. #20
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Bonjour,
    L'erreur que j'avais signalé ici était la conséquence d'une erreur de syntaxe dans le code Ajax.
    J'ai modifié quelques détails dans ton code mais maintenant tout fonctionne à la perfection. Donc un grand merci! J'ai mis quelques pouces verts sur les réponses qui m'ont le plus aidé.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 0
    Dernier message: 03/12/2020, 01h35
  2. Question math par rapport à la procédure varclus
    Par joyeux_lapin13 dans le forum SAS STAT
    Réponses: 5
    Dernier message: 01/08/2011, 15h18
  3. [MySQL] Actualiser données PHP sans recharger page
    Par herve94400 dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 15/10/2008, 15h44
  4. Recharger page après validation de formulaire par POST
    Par Flynt dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 01/02/2008, 16h33
  5. Réponses: 18
    Dernier message: 08/04/2006, 10h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo