forEach est compatible avec IE 9+, for ... of n'est compatible avec aucune version d'IE (tu peux regarder sur ces 2 liens : https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/forEach, https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Instructions/for...of )

Edit : pour forEach, c'est surement la syntaxe de l'arrow function qui bloque avec IE ->

text.forEach(function(element) {
    // code
});

Ce code devrait être valide
Modifié par Wazazaby (09 Aug 2020 - 16:35)
MERCI.

L'élément clé de ton code est :

element.parentNode.parentNode.querySelector('input[type=radio]').id;


Autrement j'essaye de produire un code compatible IE, ce qui d’ailleurs est peut-être idiot.

tex.forEach(element => n'est pas compatible IE à ma connaissance.
for (const element of tex) je ne sais pas, je vais essayer.

avec cette boucle on est sûr que cela fonctionne avec IE.

const tex = document.querySelectorAll ('table.compcab input[type=text]');

if (tex.length > 0)
{
for (let i = 0; i < tex.length; i++)
{	
tex[i].addEventListener('click', function ()
{
const idRadio = this.parentNode.parentNode.querySelector('input[type=radio]').id;
document.getElementById (idRadio).checked=true;
}
);
}
}
Salut,

Voilà deux solutions qui marchent (si le but est bien de checker le bouton radio relié à l'input texte) :


const tex = document.querySelectorAll('input[type="text"]');

// Avec forEach
tex.forEach(element => {
    element.addEventListener('click', () => {
        const idRadio = element.parentNode.parentNode.querySelector('input[type=radio]').id;
        document.getElementById(idRadio).checked = true;
    });
});

// Avec for ... of
for (const element of tex) {
    element.addEventListener('click', () => {
        const idRadio = element.parentNode.parentNode.querySelector('input[type=radio]').id;
        document.getElementById(idRadio).checked = true;
    });
}


Je préfère utiliser forEach ou for ... of car ça donne un code plus lisible. Mais après chacun ses goûts Smiley langue
Modifié par Wazazaby (09 Aug 2020 - 15:41)
Bonjour,

C’est aussi mon avis que cela ne vient pas du code. En effet, dans la barre d’adresse du navigateur l’URL est toujours correcte :

.... page_membre/page.php?page=histoire&Ouvrirh2=1&ancre=promotion


Je vous rejoins sur le fait que l'ancre soit positionnée au chargement de la page, mais avant que le script n'ouvre tous les chapitres.
Il faudrait donc introduire un retard entre l’ouverture des chapitres et le positionnement de l’ancre.
Vous précisez que cela pourrait se faire en positionnant l’ancre via un code, sachant que le nom de l’ancre peut être transmis via l’URL.

Avez-vous une idée de ce code.

Merci
Cordialement
Patrick MARA
Salut,

Dans l'appel de l'ajax, tu passes en paramètre le nom 'Libelle', alors que dans le PHP, tu récupères $_POST['article']. Ta variable $article est donc vide et ta requête ne trouve rien.

Comme tu ne traites pas le cas où l'article n'est pas trouvé, $informations[0] n'existe pas. Par ailleurs, tu initialises $informations comme une chaîne, mais tu l'utilises comme un tableau. Il vaudrait mieux l'initialiser comme un tableau dans ce cas :
$informations = [];


Seul le premier résultat t'intéresse, donc ce n'est pas la peine de faire une boucle pour récupérer tous les résutlats. Puisque le libellé est censé être unique, la requête ne retourne de toutes façons que 0 ou 1 résultat. Tu peux donc tester si un résultat est trouvé et le récupérer directement sans faire de boucle.
Je pensais plus à une page de test sur un serveur pour tester le comportement, parce que le problème ne vient probablement pas du code. Une autre piste de réflexion, il est possible que l'ancre soit positionnée au chargement de la page, mais avant que le script n'ouvre tous les chapitres. Ce qui expliquerait le caractère aléatoire, en fonction du temps d'exécution du script. Une solution serait de positionner l'ancre via un code, plutôt que de laisser le navigateur s'en occuper.
Bonsoir. Normal, l'état n'est pas sauvegardé sur la nouvelle page. Il faut soit passer par javascript et sauvegarder l'état de l'onglet actif via un cookies ou localStorage, soit sauvegarder l'état côté serveur.

Pour ce faire vous mettez une classe sur l'onglet actif.

Édit : grillé !
Modifié par Olivier C (08 Aug 2020 - 22:10)
bonjour, ce template utilise la class current_page_item pour appliquer ce style justement pour la page en cours. Attribuer cette class n'est pas le job de CSS mais éventuellement de JavaScript ou ton langage coté serveur/hébergement . ( ...trés souvent PhP ).

:visited, ne s'applique qu'au lien effectivement déjà ouvert par le navigateur. Les options de style sont trés limitées : https://developer.mozilla.org/fr/docs/Web/CSS/:visited

<edit> j'ai mis le lien à jour directement sur le template , bien que le fond de la question ne dépende pas d'un template(ou lien promotionnel)</edit>
Modifié par gcyrillus (08 Aug 2020 - 22:11)
Bonjour,

Merci pour votre réponse.
Mes pages se terminent par un espace vide afin de bien positionner sur l'ancre.
Il m'est difficile de donner la page mais celle ci n'est qu'une succession de <h2> et <section> avec des id et contenus différents.

<p class="ouvrir-tout" ><a id="ouvrir" title="Déplier tout" href="#"><img src="../image/fleche_bas.png" class="ligne" alt=""></a>&nbsp;&nbsp;<a id="fermer" title="Replier tout" href="#"><img src="../image/fleche_haut.png" class="ligne" alt=""></a> 
  &nbsp;....</p>

<h2 id="projet" class="trigger"><a href="#"><img src="../image/fleche_bas.png" class="ligne" alt="">&nbsp;&nbsp;<img src="../image/fleche_haut.png" class="ligne" alt="">&nbsp;Le projet / La création / Le début</a>
</h2>
<section class="toggle_container"> 
<?php include("histoire/00_Projet/projet_histoire_genre.inc.php");?>
</section>
 
<h2 id="homme" class="trigger"> <a href="#"><img src="../image/fleche_bas.png" class="ligne" alt="">&nbsp;&nbsp;<img src="../image/fleche_haut.png" class="ligne" alt="">&nbsp;Les Hommes</a
</h2>
<section class="toggle_container"> 
<?php include("histoire/00_Hommes/hommes_histoire_genre.inc.php");?>
</section>

..............


Cordialement
Patrick MARA
Salut,

Ton réflexe de vouloir factoriser ton code est une très bonne chose ! Smiley smile Cependant, il existe des techniques simples et efficaces qui permettent d'éviter les répétitions tout en clarifiant le code. Dans ta solution, tu évites effectivement les répétitions, mais ton code reste en un seul bloc. Découper son code permet de le rendre plus clair et plus simple. Cela empêche également d'ajouter des bugs lors de changements futurs. Chaque partie étant indépendante, cela limite les effets de bord.

La première chose à faire lorsque l'on veut factoriser son code est de le découper en fonctions :

function addButton(id, text, action) {
  const button = document.createElement('button')
  button.id = id
  button.innerHTML = text
  button.setAttribute('onclick', action)
  document.body.appendChild(button)
}

function addColorButton(id, text, action) {
  const button = document.createElement('input')
  button.setAttribute('type', 'color')
  button.id = id
  button.innerHTML = text
  button.setAttribute('onclick', action)
  document.body.appendChild(button)
}

function editerPage() {
  addButton('titre', 'Titre de l\'onglet de la page', 'titre()')
  addButton('h1', 'Titre h1 de la page', 'h1()')
  addButton('p', 'Paragraphe de la page', 'p()')
  addColorButton('input', 'Changer la couleur du titre h1', 'couleurH1()')
}

editerPage()

Ensuite on voit ce qu'on peut regrouper :

function addAttributes(element, id, text, action) {
  element.id = id
  element.innerHTML = text
  element.setAttribute('onclick', action)
  document.body.appendChild(element)
}

function addButton(id, text, action) {
  const button = document.createElement('button')
  addAttributes(button, id, text, action)
}

function addColorButton(id, text, action) {
  const button = document.createElement('input')
  button.setAttribute('type', 'color')
  addAttributes(button, id, text, action)
}

Idéalement, une fonction devrait avoir un minimum d'arguments pour rester facilement compréhensible. On peut donc regrouper la liste d'attributs dans une classe :


class AttributeList {
  constructor(id, text, action) {
    this.id = id
    this.text = text
    this.action = action
  }
}

function addAttributes(element, attributes) {
  element.id = attributes.id
  element.innerHTML = attributes.text
  element.setAttribute('onclick', attributes.action)
  document.body.appendChild(element)
}

function addButton(attributes) {
  const button = document.createElement('button')
  addAttributes(button, attributes)
}

function addColorButton(attributes) {
  const button = document.createElement('input')
  button.setAttribute('type', 'color')
  addAttributes(button, attributes)
}

function editerPage() {
  addButton(new AttributeList('titre', 'Titre de l\'onglet de la page', 'titre()'))
  addButton(new AttributeList('h1', 'Titre h1 de la page', 'h1()'))
  addButton(new AttributeList('p', 'Paragraphe de la page', 'p()'))
  addColorButton(new AttributeList('input', 'Changer la couleur du titre h1', 'couleurH1()'))
}

editerPage()

On peut séparer les données des fonctions et utiliser une boucle pour éviter de répéter l'appel à addButton :

function editerPage() {
  const elements = {
    buttons: [
      new AttributeList('titre', 'Titre de l\'onglet de la page', 'titre()'),
      new AttributeList('h1', 'Titre h1 de la page', 'h1()'),
      new AttributeList('p', 'Paragraphe de la page', 'p()')
    ],
    colorButtons: [
      new AttributeList('input', 'Changer la couleur du titre h1', 'couleurH1()')
    ]
  }
  
  elements.buttons.forEach(attributes => addButton(attributes))
  elements.colorButtons.forEach(attributes => addColorButton(attributes))
}

Enfin, on peut regrouper les fonctions dans des classes afin d'avoir un code plus facilement corrigeable et évolutif :


class AttributeList {
  constructor(id, text, action) {
    this.id = id
    this.text = text
    this.action = action
  }
}

class Element {
  constructor(attributes) {
    this.element = this.createElement()
    this.addAttributes(attributes)
    document.body.appendChild(this.element)
  }
  
  addAttributes(attributes) {
    this.element.id = attributes.id
    this.element.innerHTML = attributes.text
    this.element.setAttribute('onclick', attributes.action)
  }
}

class Button extends Element {
  createElement() {
    return document.createElement('button')
  }
}

class ColorButton extends Element {
  createElement() {
    const button = document.createElement('input')
    button.setAttribute('type', 'color')
    return button
  }
}


function createButtons(buttons) {
  buttons.forEach(attributes => new Button(attributes))
}

function createColorButtons(buttons) {
  buttons.forEach(attributes => new ColorButton(attributes))
}

function editerPage() {
  const elements = {
    buttons: [
      new AttributeList('titre', 'Titre de l\'onglet de la page', 'titre()'),
      new AttributeList('h1', 'Titre h1 de la page', 'h1()'),
      new AttributeList('p', 'Paragraphe de la page', 'p()')
    ],
    colorButtons: [
      new AttributeList('input', 'Changer la couleur du titre h1', 'couleurH1()')
    ]
  }
  
  createButtons(elements.buttons)
  createColorButtons(elements.colorButtons)
}

editerPage()

Bonjour,

Des pages de mon site sont constituées de chapitres qui se déplient et se replient par click sur son titre.
Chapitre replié :
Les promotions
Chapitre déplié :
Les promotions
L'acier du futur
Livret promotionnel pour le recrutement
Crédit documentaire : René PIERRET / Mise en ligne 27/02/2020
Recherche Maizieres 2015
Crédit documentaire : Patrick MARA / Mise en ligne 22/11/2019
L'Acier en perspectives, La R&D donne du relief à l'Acier (livret publié en 2001)
Mise en ligne 08/11/2018

Le code HTML

<h2 id="promotion" class="trigger"> <a href="#"><img src="../image/fleche_bas.png" class="ligne" alt="">&nbsp;&nbsp;<img src="../image/fleche_haut.png" class="ligne" alt="">&nbsp;Les 
  promotions</a></h2>
<section class="toggle_container"> 
<?php include("histoire/00_Promotions/promotions_histoire_genre.inc.php");?>
</section>


Le code HTML qui permet de déplier et replier tous les chapitres de la page

<p class="ouvrir-tout" ><a id="ouvrir" title="Déplier tout" href="#"><img src="../image/fleche_bas.png" class="ligne" alt=""></a>&nbsp;&nbsp;<a id="fermer" title="Replier tout" href="#"><img src="../image/fleche_haut.png" class="ligne" alt=""></a> 
  &nbsp;....</p>


Le Javascript qui commande le déploiement et le repliement

var Ouvrirh2='<?php if(isset($_GET['Ouvrirh2'])){echo $_GET['Ouvrirh2'];}?>';

$(document).ready(function(){
    var $contenu = $('.toggle_container');
    $contenu.hide();
 
    $('h2.trigger').click(function(){
     $(this).toggleClass('active').next().slideToggle('slow');	
        return false;
    });

   $('#ouvrir').click(function() {
       $contenu.show('slow');
      return false;
    });

	if (Ouvrirh2 == 1) {
		 $('#ouvrir')[0].click(function(){
		   $contenu.show('slow');
		   return false;	
	});	         
	}
	
    $('#fermer').click(function() {
        $contenu.hide('slow');
        return false;
    });
			
});


Les pages appelées par les liens contenus dans un chapitre comportent un lien de retour vers la page appelante de cette forme :

..../page_membre/page.php?page=histoire&Ouvrirh2=1#promotion


Ouvrirh2 est une variable transmise par l’URL, et promotion est le nom de l’ancre contenu dans un attribut id de la page appelante.

<h2 id="promotion" class="trigger"> <a href="#"><img ……..


La variable Ouvrirh2 est récupérée dans le script :

var Ouvrirh2='<?php if(isset($_GET['Ouvrirh2'])){echo $_GET['Ouvrirh2'];}?>';


Si elle est égale à 1 :

if (Ouvrirh2 == 1) {
		 $('#ouvrir')[0].click(function(){
		   $contenu.show('slow');
		   return false;	
	});


Cela déclenche le déploiement de tous les chapitres de la page, ceci fonctionne parfaitement bien.

Par contre le retour vers l’ancre désignée ne fonctionne pas toujours, il est même aléatoire.

Je ne comprends pas et je suis depuis un certain temps sur ce problème.

Merci pour votre aide dans la recherche d'une solution.

Cordialement
Patrick MARA
Finalement j'ai fait comme ça:

function editerPage() {
    let div = document.createElement('div');
    div.id = 'div';
    document.body.appendChild(div);
    var bouton = document.createElement('button');
    bouton.innerHTML = 'Valider';
    bouton.setAttribute('onclick', 'editerElement()');
    let attributes = {
        type: ['input', 'input', 'input', 'input'],
        id: ['Titre', 'H1', 'CouleurH1', 'P'],
        placeholder: ['Titre de l\'onglet de la page', 'Titre h1 de la page', 'Changer la couleur du titre h1', 'Paragraphe de la page'],
        click: ['titre()', 'h1()', 'couleurH1()', 'p()'],
        class: ['col-6', 'col-6', 'col-2', 'col-6']
    };
    for (let i = 0; i < 4; i++ ){
        var divElement = document.createElement('div');
        // div.classList.add('div' + attributes.id);
        // var bouton = document.createElement('button');
        // bouton.innerHTML = 'Valider';
        // bouton.setAttribute('onclick', attributes.click);
        var element = document.createElement(attributes.type[i]);
        element.id = 'input' + attributes.id[i];
        element.setAttribute('placeholder', attributes.placeholder[i]);
        element.classList.add(attributes.class[i]);
        if ('inputCouleurH1' === 'input' + attributes.id[i]) {
            element.setAttribute('type', 'color');
            var label = document.createElement('label');
            label.classList.add('col-4');
            label.innerHTML = 'Changer la couleur du h1';
            divElement.appendChild(label);
        }
        div.appendChild(divElement);
        // divElement.appendChild(bouton);
        divElement.appendChild(element);
    }
    divElement.appendChild(bouton);
    document.getElementById('customCheck1').setAttribute('onclick', 'editerPageOff()')
}
Et l'eau,



@vzytoi :

technique 1:
insère une closure dans ta boucle Smiley cligne Tu garderas/captureras le contexte....

technique 2:
Si tu as beaucoup d'écouteurs attachés au même comportement, ce n'est pas la meilleur solution. Dans ce cas, la var évènements est plus approprié.

technique 3:
array.from ....
el.forEach ....

technique 4 :
array.from
for ... of ...
Modifié par niuxe (08 Aug 2020 - 13:31)
Bonjour,

<tr>
<td><input type="radio" name="super" value="COMTFV006SM-D" id="ACOMTFV006SM-D"  /></td>
<td>6 fibres, OS2 (9 / 125), Str. serr&eacute;e &gt;&gt; <input type="text" size="4" name="unit[COMTFV006SM-D]" id="UCOMTFV006SM-D" /> m</td>
</tr>


J'ai essayé cela :

const tex = document.querySelectorAll ('input[type="text"]');

for (let i = 0; i < tex.length; i++)
{	
tex[i].addEventListener('click', function ()
{
const id_radio = this.parentNode.parentNode.children.children.id;
document.getElementById (id_radio).checked=true;
}
);

}


Ne marche pas.

Voyez-vous où est l'erreur ?
Modifié par boteha_2 (09 Aug 2020 - 14:28)
Bonjour,

A vue de nez, la seule variable non-initialisée que je vois est celle-ci :
printf("Échec de la connexion : %s\n", $mysqli->connect_error);

qui devrait être ré-écrit comme suit :
printf("Échec de la connexion : %s\n", $db->connect_error);


Par ailleurs, attention danger Smiley nono : il ne faut jamais utiliser l'utilisateur root dans un script PHP, même en développement. Vous prenez des risques inutiles sur vos données.

Enfin, plutôt que de poster des morceaux de fichiers, pouvez-vous poster les fichiers complets car sinon le numéro de ligne indiqué dans votre message d'erreur ne nous sera d'aucune aide pour vous répondre. Smiley cligne

Bien à vous,
Modifié par Bouchon (07 Aug 2020 - 15:52)
Bonjour, je cherche depuis quelque jour un moyen de faire un formulaire de devis en php.

Dans les grandes lignes, tous mes articles sont stockés sur un BDD (libelle, prix, TVA, stock ...)
Et j'aimerais sur mon formulaire qu'une fois que la personne a choisis un article dans un menu déroulant toutes les autres informations s'affichent dans les inputs.

J'ai essayé avec Ajax, mais je suis débutant et je n'ai pas réussi.

Je vous montre mon code :

La parti html du formulaire :


 <td>
                                            <select name="article" id="article">
                                            <option value="">--Choisissez un article--</option>';
                                            <?php
                                                 $bdd = new PDO ('mysql:host=localhost;dbname=airfixation;charset=utf8', 'root', '');
                                                $articles = $bdd->query("SELECT * FROM t_article ORDER BY id");                                            
                                            foreach ($articles as $article):
                                            echo '<option value="'.$article['Libelle'].'">'.$article['Libelle'].'</option>';
                                            endforeach;
                                            ?>
                                            </select>                                            
                                        </td>
                                        <td>
                                            <input type="text" name="article" class="ajax">
                                        </td>
                                        <td>
                                            <input type="text" name="article" class="ajax">
                                        </td>
                                        <td>
                                            <input type="text" name="article" class="ajax">
                                        </td>
                                        <td>
                                            <input type="text" name="article" class="ajax">
                                        </td>


La parti PHP :

<?php

$article= $_POST['article'];
$informations = "";

$db = new mysqli('localhost', 'root', '', 'airfixation');
if ($db->connect_errno) {
    printf("Échec de la connexion : %s\n", $mysqli->connect_error);
    exit();
}

if ($result = $db->query("SELECT * FROM `t_article` WHERE `Libelle` = '$article'")) {
    
    while ($row = $result->fetch_array(MYSQLI_BOTH)) 
	{
        
        $informations[] = $row;
        
	}
    $result->close();
}
else
{
	printf("Message d'erreur : %s\n", $db->error);
}

$informations = $informations[0];

echo json_encode($informations);
?>


La parti JS


$(document).ready(function() {
                $('select#article').change(function() {
		var value = $(this).val();
                var i = 0;
		$.ajax({
		url: "traitement.php",
		type: "POST",    
        dataType: "JSON",
        data: {Libelle : value},

		success:function(data)
		{

                        $('input').each(function(){
		                 $(this).val(data[i])
				  i++;
			});
		}
	});

});
});


et lors du test de la parti PHP j'ai une erreur comme quoi " Chaîne non initialisée offset: 0 dans C: \ wamp64 \ www \ airfixation \ commercial \ traitement.php à la ligne 28"

En espérant que vous pourrez m'aider.
Modifié par Tilep (07 Aug 2020 - 15:31)
Ben justement la requête est la pour te sélectionner ce dont tu a besoin, ni plus, ni moin.
J'imagine que tu peut manipuler tes données en remplaçant 'nom' par le nom de la personne dont tu veut afficher les informations.
Etape 1 tu récupère la bonne personne en base via la requête.
Etape 2 tu manipule les données reçu pour récupérer ce qu'il te faut.
Mais pour que data te renvoi uniquement les informations de la personne concernée et non pas toute les personnes il faut que tu rajoute un WHERE dans ta requête je pense.
genre WHERE nom = 'ici tu peut dynamiser en mettant la donnée qui est mise dans ta barre de recherche'.
Modifié par Knhfr (07 Aug 2020 - 17:34)
25 Dernières réponses