Pages :
Bonjour, le titre n'est pas très explicite Smiley murf

J'ai deux div (section), dans une div j'ai une liste a puce et sur le deuxième div vide, je voudrait que quand on clique sur cerise (par exemple) que dans le second div apparaisse un titre et une description comme ceci :
<h2>La cerise :</h2>
<p>La cerise est le fruit comestible du cerisier, il s'agit d'un fruit charnu à noyau de forme sphérique, généralement de couleur rouge.</p>

Puis quand je clique sur Fraise, le code s'efface et laisse place à celui de la fraise.
Comment je peux faire, merci.

PS: j'ai le code sur codepen https://codepen.io/ricem/pen/qBzZKRr
Modifié par ricem (21 Jul 2024 - 10:10)
Bonjour,

IL y a plusieurs familles de solutions possibles:

Soit tu inclus toutes les descriptions directement dans le code, et le clic sur un élément ne fait qu'afficher la description choisie et masquer les autres.
Typiquement, en jouant avec la valeur de CSS display en JavaScript.
L'avantage, c'est que c'est simple, mais c'est difficilement envisageable si tu as beaucoup d'éléments.

Soit le clic déclenche le chargement d'un fragment de page et va l'afficher dans la zone voulue.
Pour ça, il faut te renseigner sur XMLHttpRequest ou l'API fetch, et ensuite c'est de la manipulation du DOM.
C'est clairement la solution la plus compliquée...

Sinon troisième solution, tu le fais à l'ancienne, et tu gères la description à afficher avec par exemple un paramètre GET, p.ex. mapage.php?fruit=ffraise, mapage.php?fruit=framboise, etc.
L'avantage est que c'est très très simple, que tu n'as pas besoin de JavaScript, et que c'est beaucoup plus simple pour indexer ton contenu par les moteurs de recherche.


Par contre je pense que ce sujet devrait être déplacé dans débutant, car c'est une question de comment faire assez générale, et non pas vraiment une question de sémantique ou de langage HTML pointue.
Modérateur
QuentinC a écrit :


Sinon troisième solution, tu le fais à l'ancienne, et tu gères la description à afficher avec par exemple un paramètre GET, p.ex. mapage.php?fruit=ffraise, mapage.php?fruit=framboise, etc.
L'avantage est que c'est très très simple, que tu n'as pas besoin de JavaScript, et que c'est beaucoup plus simple pour indexer ton contenu par les moteurs de recherche.


tu n'es pas obligé de passer par une querystring dans ce cas. Autant appeler une page : fraise.html ou cerise.html ou etc.

@ricem :

ton code html n'est pas valide. Tu ne peux pas avoir un élément <a> en tant qu'enfant direct d'un <ul>

Ce code est faux :

<ul>
    <a href=""><li>item 1</li></a>
    <a href=""><li>item 2</li></a>
    <a href=""><li>item 3</li></a>
</ul>


Alors que ce code est juste :

<ul>
    <li><a href="">item 1</a></li>
    <li><a href="">item 2</a></li>
    <li><a href="">item 3</a></li>
</ul>


La question que je me pose est : J'ai compris ce que tu souhaites faire. Mais avec quelle technique/technologie veux-tu le faire (JS/PHP/Python/Ruby/etc.) ?


edit
En faisant simple, tu peux tout à fait imaginer ce genre de techniques :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <main>
        <aside>
            <nav>
                <ul>
                    <li><a href="#cerise">cerise</a></li>
                    <li><a href="#fraise">fraise</a></li>
                    <li><a href="#orange">orange</a></li>
                </ul>
            </nav>
        </aside>
        <section>
            <div id="cerise">cerise </div>
            <div id="fraise">fraise </div>
            <div id="orange">orange </div>
        </section>
    </main>
</body>
</html>



body{
    font-family: sans-serif;
    margin: 0;
    padding: 0;
}

main{
    max-width: 600px;
    margin: 0 auto;
    display: grid;
    grid-template-columns: repeat(12, 1fr);
}

aside{
    grid-column: 1 / 4;
}

section{
    grid-column: 5 / 12;
    height: 200px;
    overflow: hidden; /* auto ? */
}

section div{
    height: 200px;
}


N'oublie pas qu'il y a :
- l'élément <dl> qui selon moi se prête à ce genre de situation
- l'élément <details> qui est une autre possibilité
Modifié par niuxe (21 Jul 2024 - 13:15)
Salut,
Moi aussi je partirais comme Niuxe (la fin de son dernier commentaire), avec des éléments details/summary, éventuellement dl. Dans tous les cas un système d'onglets ou d'accordéon.
Re, du coup j'ai essayé en créant une API mais rien ne fonctionne (d'ailleurs, j'ai créé un nouveau sujet => https://forum.alsacreations.com/topic-5-91082-1-Afficher-la-reponse-json.html)
sinon, en quoi consiste la 3éme solution, j'ai pas trop compris aurais tu un exemple ?
merci.

Edit : Je ne connaissais pas ces techniques ni ces éléments...ça peut être intéressant je vais approfondir (me renseigner) Double merci.
Modifié par ricem (21 Jul 2024 - 19:11)
a écrit :
tu n'es pas obligé de passer par une querystring dans ce cas. Autant appeler une page : fraise.html ou cerise.html ou etc.


Effectivement, c'est même encore plus simple. Pourquoi faire simple quand on peut faire compliqué !
Modérateur
Bonsoir,

Personnellement , j'ai penser de suite à une liste de définition. et à grid qui permet facilement de faire des boites à onglet sans positionement et à coup de tabindex Smiley smile J'y ai ajouté des attributs role, mais je ne suis pas certains qu'il soient tous utiles car pas de display:none ni de js impliqués, les balises dt et dd sont dans le flux et dans leur usage habituel. @quentinC saura dire et taper sur les doigts du mauvais élève Smiley cligne

En raccourcie, voici l'idée: https://codepen.io/gc-nomade/pen/zYVqQRK
Modifié par gcyrillus (21 Jul 2024 - 21:34)
Bonsoir gcyrillus, très joli le résultat, c'est dommage que je ne m'y connaisse pas trop en "grid" hormis quelque notion de mise en page pour passer de 3 à 2 et une colonne en "media queries", je mettais arrêté un peu plus sur le "flexbox"...

niuxe, j'ai compris un peu le principe de ton code ça fonctionne un peu comme les ancres sur un espace plus restreint du coups il ne peut pas afficher les 3 div...on va dire que c'est un peu du bidouillage Smiley confused mais ça fonctionne.

parcontre, j'aimerais un peu plus de précision sur la 3éme technique "l'appel des pages"..merci.
Modifié par ricem (21 Jul 2024 - 22:13)
Modérateur
rebonsoir,

Pour l'appel des pages avec get, c'est à faire dans un fichier php en verifiant si il y a une requete $_GET et choisir l'une ou l'autre des infos de fruits stocké dans ton json.

En gros cela donnerait quelque chose comme ceci :
<?php
	// chargement du json
	$fruits= json_decode(file_get_contents('fruits.json'), true);
	// premier enregistrement à montrer par défaut
		$title= $fruits[0]['titre'];
		$content = $fruits[0]['description'];	
		
	// y a t-il une requete pertinente ?
	if(isset($_GET['fruit'])) {	
                                // si l'on ne trouve rien
				$title= 'Ce fruit est absent de la base de donnée';
				$content = 'Il n\'y a aucune description à afficher';
		// maintenant on cherche
		foreach ($fruits as $subKey => $subArray) {
			if( $subArray['titre'] == trim($_GET['fruit'])) {
				$title=$subArray['titre'];
				$content = $subArray['description'];
				break;// on s'arrete des qu'on trouve
			} 
		}
	}
?><!DOCTYPE html>
<html lang="fr">	
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
		<title>Fruits rouges - <?= $title ?></title>
		<style>
			nav {display:flex;gap:1em;}
		</style>
	</head>
	<body>
		<h1>Les fruits rouges</h1>
		<main>
			<nav>
				<?php
				// affichage des liens vers les données trouvées
					$i = 0;
					while ($i < count($fruits)) {
						$fruit=$fruits[$i]['titre'];
						echo '<a href="?fruit='.$fruit.'">'.$fruit.'</a>';
						$i++;
					}
				?>		
			</nav>			
			<section>
				<h2><?= $title ?></h2>
				<?= $content ?>
			</section>
		</main>
		<footer><p>Hmm des fruits rouges</p></footer>
	</body>
</html>

partant de ton fichier fruit.json
[
    {
        "titre": "Cerise",
        "description": "La cerise est le fruit comestible du cerisier, il s'agit d'un fruit charnu à noyau de forme sphérique, généralement de couleur rouge."
         
    },
 
    {
        "titre": "Fraise",
        "description": "La fraise est un petit fruit rouge issu des fraisiers, espèces de plantes herbacées appartenant au genre Fragaria"
    },
 
    {
        "titre": "Framboise",
        "description": "La framboise est un fruit rouge issu du framboisier, un arbrisseau de la famille des rosacées.."
         
    },
 
    {
        "titre": "Mûre",
        "description": "La mûre est un fruit comestible de la ronce commune, buisson épineux très envahissant du genre Rubus, de la famille des Rosacées, comme le framboisier"
    }
]

Ta page affiche le premier fruit par défaut.
Si la requête correspond à l'un des fruits stocké, il sera affiché en lieu et place dans la page, sinon qu'il n'est pas dans la bdd.
Modifié par gcyrillus (21 Jul 2024 - 23:39)
Modérateur
@gcyrillus : Tu n'es pas du tout obligé de passer par du php pour faire ce genre de chose. En JS, tu peux gérer un GET (window.location.search & l'objet URLSearchParams). Je pense que tu le sais. Mais tu n'y as pas pensé Smiley smile

@ricem:
Lancement d'un serveur en local sur le port 3000

[ edit ]

edit en python

python3 -m http.server 3000


edit en php:

php -S localhost:3000


edit en express (nodeJS) Suivant la précédente technique. Sinon, avec express, on peut faire un peu plus simple

import express from 'express'
import fs from 'node:fs'
import path from 'path'
import { fileURLToPath } from 'url'

const app = express()
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

app.get('/', (req, res) =>{
    res.sendFile(path.join(__dirname, '/index.html'))
})

app.get('/app.js', function(req, res){
  res.sendfile(path.join(__dirname + '/app.js'));
});

app.get('/data.json', function(req, res){
  res.sendfile(path.join(__dirname + '/data.json'))
});


const port = 3000
app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})



[/ edit ]

data.json

[
    {
        "theme": "cerise",
        "titre": "Cerise",
        "description": "La cerise est le fruit comestible du cerisier, il s'agit d'un fruit charnu à noyau de forme sphérique, généralement de couleur rouge."
         
    },
 
    {
        "theme": "fraise",
        "titre": "Fraise",
        "description": "La fraise est un petit fruit rouge issu des fraisiers, espèces de plantes herbacées appartenant au genre Fragaria"
    },
 
    {
        "theme": "framboise",
        "titre": "Framboise",
        "description": "La framboise est un fruit rouge issu du framboisier, un arbrisseau de la famille des rosacées.."
         
    },
 
    {
        "theme": "mure",
        "titre": "Mûre",
        "description": "La mûre est un fruit comestible de la ronce commune, buisson épineux très envahissant du genre Rubus, de la famille des Rosacées, comme le framboisier"
    }
]


index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <ul>
        <li><a href="?theme=cerise">Cerise</a></li>
        <li><a href="?theme=fraise">Fraise</a></li>
        <li><a href="?theme=framboise">Framboise</a></li>
        <li><a href="?theme=mure">Mure</a></li>
    </ul>
    <div id="result"></div>
    <script src="app.js"></script>
</body>
</html>


app.js

(()=>{
    let getData = async ()=>{
        let response = await fetch('http://localhost:3000/data.json')
        return await response.json()
    }
    if(window.location.search.trim() !== ""){
        let querystring = window.location.search,
            params = new URLSearchParams(querystring),
            theme = params.get('theme'),
            row = {}
        getData().then(d =>{
            let row = d.find(e => e.theme === theme)
            document.getElementById('result').innerHTML = `
                <h1>${row.titre}</h1>
                <div>${row.description}</div>
            `
        })
    }
})()

Modifié par niuxe (22 Jul 2024 - 14:26)
Modérateur
@niuxe oups oui bien sur !!

Du coup voila ma contrib en js en mirroir au php précédent, du coup avec fetch() sur window.onload() pour marquer une difference ...

<!DOCTYPE html>
<html lang="fr">	
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
		<title>Fruits rouges</title>
		<style>
			nav {
			  display:flex;
			  gap:1em;
			  justify-content:center;
			}
			body {
			  display: grid;
			  min-height: 100vh;
			  margin: 0;
			  grid-template-rows: auto 1fr auto;
			  text-align: center;
			  background: #ACD5A0
			}
			main {
			  width:100%;
			  max-width: 800px;
			  min-height: 100%;
			  margin: auto;
			}
			  section {
			  display: grid;
			  gap: 1em;
			  text-align: initial;
			}
			  header,footer{
			  background:#345;color:white;=
			}
			  main {
			  background:tomato;
			  padding:1em;
			}

			a{
			  padding:1em;
			}
			.active{
			  background: white
			}
			
		</style>
	</head>
	<body>
		<header><h1>Les fruits rouges</h1></header>
		<main>
			<nav>
				
			</nav>			
			<section>
				<h2></h2>
				<div></div>
			</section>
		</main>
		<footer><p>Hmm des fruits rouges</p></footer>
	</body>
	
		<script>
window.onload=function() {
    fetch("fruits.json").then(response => response.json()).then(fruits => {
		// on attrape la valeur fruit de L'URL si il y a
		const params = new Proxy(new URLSearchParams(window.location.search), {
			get: (searchParams, prop) => searchParams.get(prop),
		});
		let value = params.fruit;
		// traitement du json
		let title = fruits[0]["titre"];
		let content = fruits[0]["description"];
		let nav = ``;
		let active='';
		let lefruit= title;
		if(value==null) value= lefruit;
		// navigation + class active
		for (var i = 0; i < fruits.length; i++) {
			lefruit = fruits[i]["titre"];
			if (lefruit==value) active= 'active';
			else active="";
			nav += `<a href="?fruit=${lefruit}" class="${active}">${lefruit}</a>`;
		}
		
		for (let f =0; f< fruits.length;f++) {
			if(fruits[f]['titre']==value ) {
				title= fruits[f]['titre'];
				content = fruits[f]['description'];
				break; // on dés qu'on trouve
			}
		}
		// mise à jour des contenus
		document.querySelector("title").innerHTML = 'Fruits rouges '+title;
		document.querySelector("nav").innerHTML = nav;
		document.querySelector("h2").innerHTML = title;
		document.querySelector("div").innerHTML = content;
	})
	.catch(function () {
		// mise à jour des contenus
		document.querySelector("title").innerHTML = 'Pas de données disponibles';
		document.querySelector("nav").innerHTML = 'inconnue en base de données';
		document.querySelector("h2").innerHTML = 'Pas de données disponibles';
		document.querySelector("div").innerHTML = 'Aucune description disponible'; 
		
	});
};
		</script>
</html>

Si le fichier n'est pas trouvé ou invalide, la page indique une bdd sans données disponibles
Modifié par gcyrillus (22 Jul 2024 - 15:11)
a écrit :
J'y ai ajouté des attributs role, mais je ne suis pas certains qu'il soient tous utiles car pas de display:none ni de js impliqués, les balises dt et dd sont dans le flux et dans leur usage habituel. @quentinC saura dire et taper sur les doigts du mauvais élève


Ton utilisation de tablist est effectivement étrange.
1. Normalement, on a la liste des onglets à la suite, et le contenu affiché selon l'onglet en cours est ailleurs, pas intercalé à l'intérieur de la liste
2. Normalement, un seul onglet ne peut être ouvert à la fois. Activer un onglet affiche le contenu correspondant et masque le contenu de l'onglet précédemment actif.

Si tu n'es pas dans ce cas de figure, c'est plutôt un pattern de details/summary, ou avec ARIA, aria-expanded, qu'il faut utiliser.

Petit bonus pour les onglets: indiquer l'onglet actuellement actif avec aria-current.

Cela dit, Jaws et NVDA retranscrivent bien les bonnes informations.
Modérateur
@quentinC
a propos de https://forum.alsacreations.com/topic-1-91081-1.html#p581666

Merci de ton retour, j'en conclu, surement hâtivement, que ces attributs role ici sont une surcharge inutile si non complété avec aria-current et aria-expanded et une pointe de javascript .

L'affichage en grille (grid) et des éléments focusable via tabindex semblerait être "une alternative accessible" pour un système visuel de boite à onglets bien que plusieurs éléments se superposent dans la même zone d'affichage. Est ce un risque ou bien la feuille de style (sans display:none;) n'a pas d'incidences ?

cdt
Bonjour,

a écrit :
L'affichage en grille (grid) et des éléments focusable via tabindex semblerait être "une alternative accessible" pour un système visuel de boite à onglets bien que plusieurs éléments se superposent dans la même zone d'affichage. Est ce un risque ou bien la feuille de style (sans display:none;) n'a pas d'incidences ?


Je ne suis pas sûr de bien comprendre la question, mais
1 - La disposition visuelle n'a généralement aucune influence sur ce qui est lu ou non par les lecteurs d'écran, à quelques exceptions près.
2 - Par contre display:none masque le contenu pour tout le monde, y compris les lecteurs d'écran; c'est une des rares propriétés CSS qui ont une influence
3 - IL n'est pas garanti que les attributs ARIA sur des éléments non focusables, non landmarks, ou avec un rôle habituellement attribué à de tels éléments, soient bien lus.
Donc oui il faut que l'élément qui porte le aria-expanded soit focusable, et c'est lui qui déclenche l'action de dépli/repli.
De toute façon si l'élément qui déclenche l'action n'est pas focusable, alors il n'est pas accessible aux utilisateurs exclusivement au clavier.


Dis-moi si ça répond à la question ou si c'est à côté de la plaque...
Modérateur
QuentinC a écrit :
Bonjour,


Je ne suis pas sûr de bien comprendre la question, mais
1 - La disposition visuelle n'a généralement aucune influence sur ce qui est lu ou non par les lecteurs d'écran, à quelques exceptions près.
2 - Par contre display:none masque le contenu pour tout le monde, y compris les lecteurs d'écran; c'est une des rares propriétés CSS qui ont une influence
3 - IL n'est pas garanti que les attributs ARIA sur des éléments non focusables, non landmarks, ou avec un rôle habituellement attribué à de tels éléments, soient bien lus.
Donc oui il faut que l'élément qui porte le aria-expanded soit focusable, et c'est lui qui déclenche l'action de dépli/repli.
De toute façon si l'élément qui déclenche l'action n'est pas focusable, alors il n'est pas accessible aux utilisateurs exclusivement au clavier.


Dis-moi si ça répond à la question ou si c'est à côté de la plaque...

@quentinC
Oui cela répond tout à fait , je comprend que les attribut role sont inutiles, voir source de confusion, dans ce cas précis puisqu'il ne s'agit que de cosmétique sans conséquences.

Merci beaucoup Smiley smile
Bonjour à vous et merci pour votre contribution, je n'ai pas pu répondre avant, j'étais parti en vacance, je vais pouvoir me replonger sur le sujet et étudier tout ceci.
bon, j'ai voulu essayer plusieurs truc, mais vous êtes parti très très loin dans vos explications...et du coup trop complexe pour moi, qui n'a à peine les bases, du coup je m'y perds plus.
je voudrais le faire en JS et sans que ce soit trop compliqué.
si je récapitule j'ai mon fichier html
<!DOCTYPE html>
<html lang="fr">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="fruits.css">
    <script src="fruits.js" defer></script>
    <title>Fruits rouges</title>
</head>

<body>
    <h1>Les fruits rouges :</h1>
    <main>
        <section class="liste">
            <ul id="resultat">
                <li><a href="">Cerise</a></li>
                <li><a href="">Fraise</a></li>
                <li><a href="">Framboise</a></li>
                <li><a href="">Mûre</a></li>
            </ul>
        </section>
        <section>
            <h2 class="titre"></h2>
            <p class="description"></p>
        </section>
    </main>
</body>
</html>

Ensuite mon fichier .json, et mon fichier JS

//  Récupération des fruits depuis le fichier JSON
fetch("fruits.json")
    .then(Response => Response.json())
    .then(fruits => {
        console.log(fruits); });

je sélectionne la class "titre" avec un "document.querySelectorAll" idem pour la class "description"
const result = document.querySelectorAll('li');
for (let i = 0; i < result.length; i++) {
   ?????
    })
}


Et c'est là que je n'y arrive plus....comment je doit faire la liaison ?
merci d'être explicite sans entrée de trop dans la sécurité, tout les fichiers sont dans le même dossier donc il ne devrait pas y avoir de problème d'accès au fichier.
Modérateur
Bonjour,

Pour
//  Récupération des fruits depuis le fichier JSON
fetch("fruits.json")
    .then(Response => Response.json())
    .then(fruits => {
        console.log(fruits); 
		// traitements des données ici !
	});

Tu récupère tout, mais tu ne veut qu'un enregistrement à la fois.
il te faut donc un moyen d'extraire les infos d'un seul des enregistrements et il est facile d'imaginer que par défaut, c'est le premier.
Ce sera donc fruits[0].

Il n'est pas nécessaire pour le moment de faire une boucle sur tes enregistrements, il te suffit d'en choisir un seul et d'extraire les champs qu'il contient:
[
    {  /* enregistrement 0 */
        "titre": "Cerise",
        "description": "La cerise est le fruit comestible du cerisier, il s'agit d'un fruit charnu à noyau de forme sphérique, généralement de couleur rouge."
         
    },
 
    {  /* enregistrement 1 */
        "titre": "Fraise",
        "description": "La fraise est un petit fruit rouge issu des fraisiers, espèces de plantes herbacées appartenant au genre Fragaria"
    },
 
    {  /* enregistrement 2 */
        "titre": "Framboise",
        "description": "La framboise est un fruit rouge issu du framboisier, un arbrisseau de la famille des rosacées.."
         
    },
 
    {  /* enregistrement 3 */
        "titre": "Mûre",
        "description": "La mûre est un fruit comestible de la ronce commune, buisson épineux très envahissant du genre Rubus, de la famille des Rosacées, comme le framboisier"
    }
]

note : ne pas mettre de commentaire invalide /* enregistrement X */ dans ton fichier json, ils sont juste là pour numéroter les enregistrement.

Cela un représente un tableau et tu peut voir chaque enregistrement dans une ligne, la première ligne est la ligne numéro zéro.
Le premier (0) correspond a cerise, c'est fruits[0]
Dans chaque ligne de ton tableau tu as deux champs (deux autre lignes ou case) :
titre accessible via fruits[0]['titre']
description accessible via fruits[0]['description']

Tu peut donc déjà remplir ta première page par défaut:
//  Récupération des fruits depuis le fichier JSON
fetch("fruits.json")
    .then(Response => Response.json())
    .then(fruits => {
        console.log(fruits); 
		// traitements des données ici !
       document.querySelector('.titre').textContent = fruits[0]['titre'];
       document.querySelector('.description').innerHTML = fruits[0]['description'];
	});

en raccourcie:
textContent sert à injecter du texte pure.
innerHTML sert à injecter du texte balisé.

Ce premier morceau de page peut-être :
<!DOCTYPE html>
<html lang="fr">	
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
		<title>Fruits rouges</title>
	</head>
	<body>
		<header><h1>Les fruits rouges</h1></header>
		<main>		
			<section>
				<h2 class="titre"></h2>
				<div class="description"></div>
			</section>
		</main>
		<footer><p>Hmm des fruits rouges</p></footer>
	</body>
	
		<script>//  Récupération des fruits depuis le fichier JSON
fetch("fruits.json")
    .then(Response => Response.json())
    .then(fruits => {
        console.log(fruits); 
		// traitements des données ici !
       document.querySelector('.titre').textContent = fruits[0]['titre'];
       document.querySelector('.description').innerHTML = fruits[0]['description'];
	});
		</script>
</html>

ou si tu préfere externalisé le traitement avec une fonction
<!DOCTYPE html>
<html lang="fr">	
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
		<title>Fruits rouges</title>
	</head>
	<body>
		<header><h1>Les fruits rouges</h1></header>
		<main>		
			<section>
				<h2 class="titre"></h2>
				<div class="description"></div>
			</section>
		</main>
		<footer><p>Hmm des fruits rouges</p></footer>
	</body>
	
	<script>//  Récupération des fruits depuis le fichier JSON
		fetch("fruits.json")
		.then(Response => Response.json())
		.then(fruits => {
			console.log(fruits); 
			// traitements des données ici !
			printDatas(fruits[0]['titre'],fruits[0]['description'])
			
		});
				
		function printDatas(titre,description) {		
			document.querySelector('.titre').textContent = titre;
			document.querySelector('.description').innerHTML = description;		
		}
	</script>
</html>

et si tu veut construire d'autres pages, il suffit de copier/coller celle-ci en modifiant le numéro d'enregistrement pour chacune d'elle

A ce stade, tu dois avoir compris où et comment traiter tes données.

Ensuite il va te falloir une stratégie pour cibler l'une ou l'autre des lignes de ton tableau.
Pour cela , tu te sert de l'URL de ta page en lui passant en paramètre le nom du fruit voulu.
(on continu avec des fonctions pour mieux voir les étapes et les modifier par la suite)

il faut alors boucler sur tes lignes, extraire le titre et en faire un paramètre à passer dans L’URL.
On peut facilement créer le HTML à injecter à l'aide de https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Template_literals
Ce qui donne:
function getUrls(fruits) {
	let navItems ='';
	for (var i = 0; i < fruits.length; i++) {
		lefruit = fruits[i]["titre"];
		navItems += `<li><a href="?fruit=${lefruit}">${lefruit}</a></li>`;
	}
	return navItems; // ici on récupère la liste de liens fabriqués
}

Ils reste à faire la fonction pour injecter ça dans ton ul
function printNav(nav,items) {
	document.querySelector(nav).innerHTML=items;			
}

Ce qui donne maintenant ta page avec ton menu
<!DOCTYPE html>
<html lang="fr">	
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
		<title>Fruits rouges</title>
	</head>
	<body>
		<header><h1>Les fruits rouges</h1></header>
		<main>	
		<ul id="resultats"></ul>
			<section>
				<h2 class="titre"></h2>
				<div class="description"></div>
			</section>
		</main>
		<footer><p>Hmm des fruits rouges</p></footer>
	</body>
	
	<script>//  Récupération des fruits depuis le fichier JSON
		fetch("fruits.json")
		.then(Response => Response.json())
		.then(fruits => {
			console.log(fruits); 
			// traitements des données ici !
			printDatas(fruits[0]['titre'],fruits[0]['description']);
			const items =getUrls(fruits);
			printNav('#resultats',items);			
			});
		// fonctions de traitements	
			function printDatas(titre,description) {		
			document.querySelector('.titre').textContent = titre;
			document.querySelector('.description').innerHTML = description;		
			}
			
			function getUrls(fruits) {
				let navItems ='';
				for (var i = 0; i < fruits.length; i++) {
					lefruit = fruits[i]["titre"];
					navItems += `<li><a href="?fruit=${lefruit}">${lefruit}</a></li>`;
				}
				return navItems;
			}
			
			function printNav(nav,items) {
				document.querySelector(nav).innerHTML=items;			
			}
		</script>
	</html>	

NOTE le passage de la liste fabriquée en constante dans la fonction d'affichage des liens ainsi que le selecteur '#resultats' ciblant ton ul.
const items =getUrls(fruits);
printNav('#resultats',items);


Maintenant que tu affiches ta page par défaut avec le menu, il faut pouvoir afficher les autres.

Nous avons maintenant pour chaque fruits une URL avec le paramètre ?fruit=fruitDemande

Nous allons donc tenter de récupérer cette variable et renvoyer ce que l'on trouve:
function getQuelFruit() {
	let params = new URLSearchParams(document.location.search);
	let quelFruit = params.get("fruit");
	return quelFruit;
}


voir https://developer.mozilla.org/fr/docs/Web/API/URLSearchParams et https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/get

Si il n'y a pas de paramètre la valeur retournée est null ou que si celle-ci ne correspondra à rien dans le tableau , ils nous faut au préalable définir une ligne par défaut, la 0.

Ajoutons notre variable de ligne par défaut que l'on pourra mettra à jour plus loin.
// fruit par défaut
let lefruit= fruits[0];


Pour trouver le fruit choisi, nous allons faire une boucle sur tous les titres des lignes du tableau fruits en comparant le titre des lignes (fruit[x]['titre']) avec le paramètre trouvé dans l'URL quelFruit et éventuellement mettre à jour lefruit qui correspondra à fruits[n°deLigneTrouvée]['titre'] ou lui laissé sa valeur par défaut fruits[0]['titre']

function leFruitChoisi(fruits, quelFruit, lefruit) {
	for (let f =0; f< fruits.length;f++) {
		if(fruits[f]['titre']==quelFruit ) {
			lefruit = fruits[f];// on a trouvé une demande
			break;
		}
	}	
	return lefruit;
}

il reste à mettre à jour l'appel de la fonction
printDatas(lefruit['titre'],lefruit['description']);

de façon à prendre la ligne lefruit mise à jour.

Cela te donne en final quelque chose comme :
<!DOCTYPE html>
<html lang="fr">	
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
		<title>Fruits rouges</title>
	</head>
	<body>
		<header><h1>Les fruits rouges</h1></header>
		<main>	
			<ul id="resultats"></ul>
			<section>
				<h2 class="titre"></h2>
				<div class="description"></div>
			</section>
		</main>
		<footer><p>Hmm des fruits rouges</p></footer>
	</body>
	
	<script>//  Récupération des fruits depuis le fichier JSON
		fetch("fruits.json")
		.then(Response => Response.json())
		.then(fruits => {
		
			// fruit par défaut
			let lefruit= fruits[0];
			
			// traitement URL si demande
			const quelFruit = getQuelFruit();
			
			// maj du fruit demandé si il y a 
			lefruit = leFruitChoisi(fruits, quelFruit, lefruit);			
			
			// Affichage des données 'lefruit' ici !
			printDatas(lefruit['titre'],lefruit['description']);
			
			// fabrications des liens
			const items =getUrls(fruits);
			
			// affichage des liens
			printNav('#resultats',items);			
		});

		// fonctions de traitements	
		function printDatas(titre,description) {		
			document.querySelector('.titre').textContent = titre;
			document.querySelector('.description').innerHTML = description;		
		}
		
		function getUrls(fruits) {
			let navItems ='';
			for (var i = 0; i < fruits.length; i++) {
				lefruit = fruits[i]["titre"];
				navItems += `<li><a href="?fruit=${lefruit}">${lefruit}</a></li>`;
			}
			return navItems;
		}
			
		function printNav(nav,items) {
			document.querySelector(nav).innerHTML=items;			
		}
			
		function getQuelFruit() {
			let params = new URLSearchParams(document.location.search);
			let quelFruit = params.get("fruit");
			return quelFruit;
		}
			
		function leFruitChoisi(fruits, quelFruit, lefruit) {
			for (let f =0; f< fruits.length;f++) {
				if(fruits[f]['titre']==quelFruit ) {
					lefruit = fruits[f];// on a trouvé une demande
					break;
				}
			}	
			return lefruit;
		}
			</script>
</html>


Bon j’espère que c'est plus clair en hachant le complexe en petit morceau moins complexe et que cela t'aide à t-y retrouver un peu mieux , même si c'est long et que cela reste un exemple.

Une fois le fonctionnement eclaircie, tu peut broder et comparer avec les autres exemples et creuser via ton moteur de recherche préférer Smiley cligne

Cdt
Modifié par gcyrillus (04 Aug 2024 - 14:48)
Merci gcyrillus pour toutes ces explications, en parallèle j'étais en train d'essayer une méthode similaire, mais non pas avec une liste à puce, mais avec des input de types "radio".

j'avais déjà créée un code que j'avais fait pour un site de "mémentos" qui fonctionnait et qui ce trouve ici :http://www.ricem.contact/portfolio/formulaire.php(si vous voulez jeter un coup d’œil)

voici le code html :
<!DOCTYPE html>
<html lang="fr">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="fruits.css">
    <script src="fruits.js" defer></script>
    <title>Fruits rouges</title>
</head>

<body>
    <h1>Les fruits rouges :</h1>
    <main>
        <section class="liste">
            <form action="">
                <p>Votre fruit préféré :</p>

                <input type="radio" name="fruit" value=0>
                <label for="cerise">Cerise</label><br>

                <input type="radio" name="fruit" value=1>
                <label for="fraise">Fraise</label><br>

                <input type="radio" name="fruit" value=2>
                <label for="framboise">Framboise</label><br>

                <input type="radio" name="fruit" value=3>
                <label for="mure">Mûre</label>
            </form>
        </section>

        <section class="contenu">
            <h2 class="titre"></h2>
            <p class="description"></p>

        </section>
    </main>
</body>
</html>


et le code JavaScipt
let favouriteFruit = document.querySelectorAll('input[name="fruit"]');
for (let i = 0; i < favouriteFruit.length; i++) {
    favouriteFruit[i].addEventListener("change", (event) => {

        const result = (event.target.value);
        console.log(result)

fetch("fruits.json")

    .then(Response => Response.json())
    .then(data => {
        let title = data[result]["titre"];
        let content = data[result]["description"];

        document.querySelector(".titre").innerHTML = title;
        document.querySelector(".description").innerHTML = content;

    })})};

il fonctionne, maintenant je vais essayer avec une liste à puce...en faite c'est le "href" qui m’intéresse car je vais par la suite l'intégrer à un fichier svg qui fonctionne avec des liens (href).

Edit : je peux lui rajouter un petit
.catch
:
let favouriteFruit = document.querySelectorAll('input[name="fruit"]');
for (let i = 0; i < favouriteFruit.length; i++) {
    favouriteFruit[i].addEventListener("change", (event) => {

        const result = (event.target.value);
        console.log(result)

        fetch("fruits.json")

            .then(Response => Response.json())
            .then(data => {
                let title = data[result]["titre"];
                let content = data[result]["description"];

                document.querySelector(".titre").innerText = title;
                document.querySelector(".description").innerText = content;

            }).catch((erreur) => console.log('Erreur : ' + erreur));
    })
};

Modifié par ricem (04 Aug 2024 - 23:49)
Modérateur
Bonjour,

oui, tu as bien compris,
Pour ajouter aux exemples, tu peut aussi faire avec un select, en considérant chaque ligne de ton tableau comme un objet Smiley cligne
<!DOCTYPE html>
<html lang="fr">
	
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<link rel="stylesheet" href="fruits.css">
		<script src="fruits.js" defer></script>
		<title>Fruits rouges</title>
	</head>
	
	<body>
		<h1>Les fruits rouges :</h1>
		<main>
			<section class="liste">
				<form action="">
					<p>Votre fruit préféré :</p>
					<select name="fruit">
						<option value="0">Cerise</option>
						<option value="1">Fraise</option>
						<option value="2">Framboise</option>
						<option value="3">Mûre</option>
					</select>
				</form>
			</section>
			
			<section class="contenu">
				<h2 class="titre"></h2>
				<p class="description"></p>
				
			</section>
		</main>
	</body>
</html>

et
let favouriteFruit = document.querySelector('select[name="fruit"]');
favouriteFruit.addEventListener("change", (event) => {	
	const result = (event.target.value);
	console.log(result)	
	fetch("fruits.json")	
	.then(Response => Response.json())
	.then(data => {
		let title = data[result].titre;
		let content = data[result].description;		
		document.querySelector(".titre").innerText = title;
		document.querySelector(".description").innerHTML = content;		
	}).catch((erreur) => console.log('Erreur : ' + erreur));
})

cdt
Modifié par gcyrillus (05 Aug 2024 - 12:59)