Je débute dans le html, css et je ne connais pas encore grand chose au JavaScript. J'ai une liste d'article dans des <div> que j'aimerais pouvoir afficher/désafficher avec des boutons, exactement comme sur cette page :
Tu parles des boutons qui permettent de faire un filtrage des articles?
Si tu es débutant ca pas te paraitre un poil complexe, mais il faut pour cela utiliser la méthode filter() qui s'applique à un tableau obligatoirement.
Merci NadfriJS pour la réponse. Effectivement je parle de ces boutons. J'ai une longue séries d'articles crée avec des <div> flexbox. Ils ont 4 ou 5 catégories différentes que j'ai définis avec un ID.
Tu veux dire que cette fonction ne marche que pour un tableau <table> ? Car c'est justement une page qui est actuellement en format <table> dont j'essaye d'améliorer le design...
Salut, non je parlais des tableaux en Javascript. Enfait il faut que l'affichage de tes articles soient gérer par Javascript, donc ils ne doivent pas être coder uniquement en dur dans le HTML.
Je t'ai fais une petit démo ici, qui est largement optimisable:
Il y aura plein de notion qui peuvent te sembler vague, comme appendChild, qui permet d' ajouter un élément à la fin d'un autre élément HTML.
createElement, qui permet de créer un élément HTML.
forEach(), tu dois surement connaitre, sinon c'est comme une boucle for pour tableau mais en plus court à écrire.
et filter(), qui permet de filtrer un tableau par rapport à une condition (ici "theme")
Et la notion d'objets dans le tableau data.
Si tu n'es pas encore bien à l'aise avec ces methodes, regardes un de mes tuto, sur comment faire une todoList en JS, je reprends pas mal de ces methodes.
Dans le dernier message je donne un petit bout de code qui fonctionne, à adapter au besoin.
[edit]
Ah, non, je viens de voir l'exemple que tu veux suivre, c'est un peu différent. Je vais me pencher sur le sujet. Bon, moi je fais ça en javascript "old school".
- Edité par LucasWerquin 22 septembre 2021 à 12:44:06
@NadfriJS Merci pour ton exemple, c'est exactement ce que je cherche ! Dommage que ça ne marche pas avec mes div html/css. ça va être compliqué pour moi d'adapter les styles a mes besoin mais je vais tout de même essayer...
@LucasWerquinSi il existe une solution plus simple je suis bien sur preneur.
Bon, je ne sais pas si c'est vraiment ce que tu souhaites, mais voilà ce que je peux te filer. Par défaut, les articles sont tous visibles. Si on clique sur un bouton, le bouton est "actif" ( ou devient inactif si on clique sur un bouton activé ). A chaque appui sur un bouton, on actualise la liste des tags activés, puis on affiche seulement les articles contenant le ou les tags actifs.
Donc à modifier si tu souhaite n'afficher que les articles possédant TOUS les tags actifs.
Et enfin le JS, que j'ai commenté le plus possible pour que tu comprenne la démarche ( et que tu puisse l'adapter à tes besoins ) :
document.addEventListener('DOMContentLoaded', () => { //lance la fonction createTABbuttons une fois le DOM chargé
createTABbuttons();
});
const createTABbuttons = function() { //créé les boutons TAB
let tagList = []; //déclare un array vide, qui sera rempli par les tags récupérés
let items = document.getElementById('MesArticles').children; //récupère un array contenant les liens contenus dans 'MesArticles'
for(let i=0; i<items.length; i++){ //pour chaque lien
let dataTags = items[i].getAttribute('data-tag').split(' '); //récupère le data-tag, puis le transforme en array de tags
for(let y=0;y<dataTags.length;y++){ //Pour chaque tag de ce lien
if(!tagList.includes(dataTags[y])) //si le array tagList ne contient pas le tag
tagList.push(dataTags[y]); //l'ajouter
}
}
for(i=0;i<tagList.length;i++){ //pour chaque tag contenu dans le array tagList
let newButton = document.createElement('button'); //créer un élément button
newButton.setAttribute('class', "btn"); //lui attribuer la class 'btn'
newButton.setAttribute('id', 'TABbtn_' + tagList[i]); //lui attribuer un id
newButton.innerHTML = tagList[i]; //remplir le bouton avec la valeur du tag
newButton.addEventListener('click', () => { //lui ajouter un eventListener
if(event.target.innerHTML.indexOf('V ') >-1){ //si l'élément contient "v " ( ou la balise image )
event.target.innerHTML = event.target.innerHTML.substring(2); //enlever "v ", ou la balise image, dans ce cas 2 devra être remplacé par le nombre de caractères de la balise image, ou event.target.innerHTML.substring(event.target.innerHTML.indexOf('>')), soit le chevron de fermeture de la balise
}
else{
event.target.innerHTML = "V " + event.target.innerHTML; //sinon ajouter "v " ou la balise image
}
event.target.toggleAttribute('isActive');//ajouter l'attribut "isActive
let activeTags = [];//déclarer ou réinitialiser le array de tags actifs
for(i=0; i<document.getElementById('TABbuttons').children.length;i++){ //pour chaque bouton présent dans "TABbuttons"
if(document.getElementById('TABbuttons').children[i].hasAttribute('isActive')){//si l'élément a l'attribut "isActive"
activeTags.push(document.getElementById('TABbuttons').children[i].getAttribute('id').substring(7));//récupérer le nom du tag en découpant l'id du bouton ( enlever "TABbtn_", soit 7 caractères)
}
}
if(activeTags.length<1)//si aucun tag n'est activé
for(i=0;i<document.getElementById('MesArticles').children.length;i++){
document.getElementById('MesArticles').children[i].setAttribute('class', 'Art-visible');//afficher tous les articles
}
else{
for(i=0;i<document.getElementById('MesArticles').children.length;i++){
document.getElementById('MesArticles').children[i].setAttribute('class', 'Art-hidden');//sinon les cacher tous dans un premier temps
}
for(i=0;i<activeTags.length;i++){ //pour chaque tag présent dans le array des tags actifs
for(let y=0;y<document.getElementById('MesArticles').children.length;y++){ //et pour chaque article
if(document.getElementById('MesArticles').children[y].getAttribute('data-tag').indexOf(activeTags[i]) > -1) //si le tag est présent dans le data-tags
document.getElementById('MesArticles').children[y].setAttribute('class', 'Art-visible'); //afficher l'article
}
}
}
});
document.getElementById('TABbuttons').appendChild(newButton); //ajouter le bouton créé dans 'TABbuttons'
}
}
J'ai pas regardé la solution de NadfriJS, mais d'après son post je vois qu'il utilise des méthodes plus efficaces que ce que je te propose ( mais peut-être plus compliquées à appréhender quand on débute ), en regardant les deux méthodes tu devrais pouvoir t'en sortir
Si, tu peux utiliser des espaces, mais pas tout au début, ni tout à la fin. Sinon la méthode split() de la ligne 9 va te créer des index vides, ce qui posera problème.
Mais tu vois que dans mon HTML j'utilise des espaces et ça marche. Alors à moins d'un fonctionnement différent selon le navigateur, ça doit le faire.
Sinon remplace les espaces par des underscores "_" dans tes data-tag et dans ton split()
- Edité par LucasWerquin 23 septembre 2021 à 14:09:37
Tu as raison, ça fonctionnne tip-top, j'avais pas remarqué qu'il crée simplement un bouton par mots lorsqu'il y a un espace...
Autre question, est-ce qu'il y a moyen simple de faire qu'en chargeant la page, elle n'affiche qu'un des tag ? Par exemple, le lien sur l'index de mon site affiche la page complète mais le lien d'une autre page n'affiche que les tags "toto" ?
Bon, pour bien mettre ça en place, il va sans doute falloir factoriser certaines partie du code que je t'ai filé, c'est à dire créer une fonction qui affiche les articles, prenant en paramètre un tag, ou l'absence de tag, ou plusieurs tags. Je te laisse réfléchir à ça un petit moment ( j'ai une disponibilité limitée pour le moment ).
[edit]
Allez, j'ai trouvé un peu de temps et j'ai déjà ça pour commencer :
let params = new URLSearchParams(document.location.search.substring(1)); //créé un objet à partir de la "querystring"
// la querystring étant toute la partie de l'url du document à partir du "?", qu'il faudra enlever ( substring(1) ) pour en faire un paramètre valable pour URLSearchParams()
console.log(params.get('datatag')); //de l'objet params, on peut extraire les données GET, en donnant en paramètre le nom de la variable GET.
Voilà, pour le moment ça affiche la valeur de la variable GET dans la console des outils de dev. Il n'y a plus qu'à traiter ça.
Donc ligne 22 à 28 du code donné plus haut, tu vois comment on traite le contenu d'un bouton ( ajouter/enlever "V " ou une balise image ) puis comment on gère l'attribut isActive. Enfin, il faut afficher les articles voulus, en analysant ce qui est fait de la ligne 30 à 50.
Donc soit tu fais une fonction qui répète ces actions ( bof ), soit tu crée des fonctions qui font ces deux choses ( gerer les boutons, puis gérer l'affichage ), et tu les utilise à la fois dans l'ajout des eventListeners aux boutons, mais aussi dans l'initialisation de ta page, tout simplement en insérant à partir de la ligne 2 l'appel à ces deux nouvelles fonctions ( gererBoutons() et genererAffichageArticle(), par exemple.
- Edité par LucasWerquin 23 septembre 2021 à 18:29:08
Merci mais là ça dépasse complétement mes capacités... Par contre j'ai un pote qui s'y connait un peu plus que moi et qui pourra peut-être m'aider à implémenter cela à partir de tes explications
Bon, c'est dommage de "baisser les bras", mais je peux comprendre. L'art de la factorisation n'est pas facile au début, mais c'est important de bien le maîtriser pour éclaircir son code.
Voilà l'idée pour commencer :
- écrire une fonction "toggleButton" dont le rôle est de passer un bouton de l'état "actif" à "inactif" et inversement. Le contenu de cette fonction est déjà présent de la ligne 22 à 28. Simplement, cette fonction devra prendre un paramètre, appelons-le "button", qui remplacera event.target dans cette partie de code.
- dans l'ajout des eventListeners, tu remplace ce bout de code par l'appel à la fonction toggleButton en passant event.target comme paramètre.
Le but du jeu étant de se retrouver avec exactement le même fonctionnement. C'est simple et ça ne ma pris que quelques minutes. J'ai déclaré la fonction, dans le corps de cette fonction j'ai copié/collé les lignes, remplacé event.target par button, ensuite j'ai placé les lignes dans un commentaire ( pour les garder au cas où ) et ajouté l'appel.
HOP! voilà la gestion du bouton exporté dans une fonction. Du coup je peux appeler cette fonction dans un autre contexte. elle sera soit appelée quand je clique sur un boutton ( comme avant ), mais peux aussi être appelée juste après la création des boutons, dans le cas où un paramètre GET est détecté ( comme je te l'ai montré dans mon message d'hier ). Ton eventListener 'DOMContentLoaded' ressemblera donc à :
document.addEventListener('DOMContentLoaded', () => { //lance la fonction createTABbuttons une fois le DOM chargé
createTABbuttons();
let params = new URLSearchParams(document.location.search.substring(1));
if(params.get('datatag'))
toggleButton(document.getElementById('TABbtn_' + params.get('datatag')));
});
Bon, en l'état, ça active juste le bouton correspondant. Il reste juste à "extraire" l'affichage des articles. Dans le code donné plus haut, il s'agit des lignes 30 à 50. Là c'est encore plus simple, pas de paramètre à gérer, la fonction s'occupe toute seule de récupérer les tags actifs en inspectant les boutons, puis affiche les articles ( tous si aucun tag n'est actif, ou seulement les articles ayant le ou les tags actifs dans leur data-tag ). Il n'y a plus qu'à placer l'appel dans ton eventListener DOMContentLoaded, juste après l'appel à toggleButton, et dans les eventListeners de tes boutons ( donc à la place des lignes 30 à 50 ).
Je t'encourage vivement à faire tout ça tout seul, ça te sera très utile pour tes futurs projets ou pour l'amélioration de celui-là.
- Edité par LucasWerquin 24 septembre 2021 à 13:56:37
document.addEventListener('DOMContentLoaded', () => { //lance la fonction createTABbuttons une fois le DOM chargé
createTABbuttons();
let params = new URLSearchParams(document.location.search.substring(1));
if(params.get('datatag'))
toggleButton(document.getElementById('TABbtn_' + params.get('datatag')));
});
let toggleButton =function(target){
target.toggleAttribute("isactive");
}
const createTABbuttons = function() { //créé les boutons TAB
let tagList = []; //déclare un array vide, qui sera rempli par les tags récupérés
let items = document.getElementById('MesArticles').children; //récupère un array contenant les liens contenus dans 'MesArticles'
for(let i=0; i<items.length; i++){ //pour chaque lien
let dataTags = items[i].getAttribute('data-tag').split(' '); //récupère le data-tag, puis le transforme en array de tags
for(let y=0;y<dataTags.length;y++){ //Pour chaque tag de ce lien
if(!tagList.includes(dataTags[y])) //si le array tagList ne contient pas le tag
tagList.push(dataTags[y]); //l'ajouter
}
}
for(i=0;i<tagList.length;i++){ //pour chaque tag contenu dans le array tagList
let newButton = document.createElement('button'); //créer un élément button
newButton.setAttribute('class', "btn"); //lui attribuer la class 'btn'
newButton.setAttribute('id', 'TABbtn_' + tagList[i]); //lui attribuer un id
newButton.innerHTML = tagList[i]; //remplir le bouton avec la valeur du tag
newButton.addEventListener('click', () => { //lui ajouter un eventListener
if(event.target.innerHTML.indexOf('✔ ') >-1){ //si l'élément contient "v " ( ou la balise image )
event.target.innerHTML = event.target.innerHTML.substring(2); //enlever "v ", ou la balise image, dans ce cas 2 devra être remplacé par le nombre de caractères de la balise image, ou event.target.innerHTML.substring(event.target.innerHTML.indexOf('>')), soit le chevron de fermeture de la balise
}
else{
event.target.innerHTML = "✔ " + event.target.innerHTML; //sinon ajouter "v " ou la balise image
}
event.target.toggleAttribute('isActive');//ajouter l'attribut "isActive
let activeTags = [];//déclarer ou réinitialiser le array de tags actifs
for(i=0; i<document.getElementById('TABbuttons').children.length;i++){ //pour chaque bouton présent dans "TABbuttons"
if(document.getElementById('TABbuttons').children[i].hasAttribute('isActive')){//si l'élément a l'attribut "isActive"
activeTags.push(document.getElementById('TABbuttons').children[i].getAttribute('id').substring(7));//récupérer le nom du tag en découpant l'id du bouton ( enlever "TABbtn_", soit 7 caractères)
}
}
if(activeTags.length<1)//si aucun tag n'est activé
for(i=0;i<document.getElementById('MesArticles').children.length;i++){
document.getElementById('MesArticles').children[i].setAttribute('class', 'Art-visible');//afficher tous les articles
}
else{
for(i=0;i<document.getElementById('MesArticles').children.length;i++){
document.getElementById('MesArticles').children[i].setAttribute('class', 'Art-hidden');//sinon les cacher tous dans un premier temps
}
for(i=0;i<activeTags.length;i++){ //pour chaque tag présent dans le array des tags actifs
for(let y=0;y<document.getElementById('MesArticles').children.length;y++){ //et pour chaque article
if(document.getElementById('MesArticles').children[y].getAttribute('data-tag').indexOf(activeTags[i]) > -1) //si le tag est présent dans le data-tags
document.getElementById('MesArticles').children[y].setAttribute('class', 'Art-visible'); //afficher l'article
}
}
}
});
document.getElementById('TABbuttons').appendChild(newButton); //ajouter le bouton créé dans 'TABbuttons'
}
}
Ligne 31 et 35, il semble qu'un copié-collé ai eu des conséquences bizarre Il t'as collé l'image dans l'éditeur ?
Bon, si tu veux afficher une image, il faut, à la ligne , rechercher l'existence de la balise image. Donc :
if(event.target.innerHTML.indexOf('<img') >-1 {
event.target.innerHTML = event.target.innerHTML.substring(event.target.innerHTML.indexOf('>') + 1); // découpe le innerHTML après la fermeture de la balise image
}
Et du coup, ligne 35 :
event.target.innerHTML = '<img src='adresse de l image' *attributs* > + event.target.innerHTML; //ajoute l'image, en écrivant la balise en html.
Ou à l'aide de la manipulation du dom, il y a moyen de faire bien plus propre
Ah, j'avais pas bien compris. La console te dit quelque chose?
Et que se passe-t-il concrètement quand tu demandes l'adresse normale de la page ? Tout s'affiche-t-il correctement ? les appuis sur les boutons fonctionnent-ils normalement ? ( toujours vérifier la console si présence d'erreur ou pas )
Et quand tu tapes l'adresse en y ajoutant "?datatag=toto" ? erreur dans la console avant la moindre action ? Ou après ?
J'ai pas énormément de dispo en ce moment pour inspecter en détail, mais j'ai du garder la version que j'avais faite et elle fonctionnait, donc on va finir par trouver.
Lorsque je demande l'adresse normale de la page tout fonctionne correctement. Et en y ajoutant "?datatag=toto" la page continue de fonctionner normalement mais cela n'a aucune action... je ne vois pas non plus d'erreur dans la console.
Oui, la version qui est tout en haut de cette discussion fonctionne très bien
Tu as raison. J'ai ajouté une parenthèse, l'erreur a disparu et les boutons sont de nouveau affiché. Par contre il ne se passe toujours rien quand j'ajoute un datatag dans l'URL...
document.addEventListener('DOMContentLoaded', () => { //lance la fonction createTABbuttons une fois le DOM chargé
createTABbuttons();
let params = new URLSearchParams(document.location.search.substring(1));
console.log('datatag : ' + params.get('datatag'));
if(params.get('datatag') !== null){
console.log('condition déclenchée');
toggleButton(document.getElementById('TABbtn_' + params.get('datatag')));
}
});
Bon, voici ce que j'essayais d'expliquer plus haut, il faut "exporter" la partie qui gère l'affichage des articles ( lignes 39 à 59 ) dans une fonction.
Cette fonction sera appelée à la fois dans les eventListeners de tes TABbtn, comme avant, mais également dans l'eventListener "DOMContentLoaded", une fois que les paramètres GET ont été traités. Car, actuellement ( dans la dernière version du code que tu as posté ) tu gère bien les paramètres GET, et normalement tes TABbtn doivent réagir ( la coche verte devrait apparaître sur le TABbtn correspondant au paramètre GET renseigné ), mais l'affichage des liens n'est pas redemandé.
Voici donc ce que j'ai de mon côté :
document.addEventListener('DOMContentLoaded', () => { //lance la fonction createTABbuttons une fois le DOM chargé
createTABbuttons();
let queryString = new URLSearchParams(document.location.search.substring(1));
if(queryString.get('datatag')){
toggleButton(document.getElementById('TABbtn_' + queryString.get('datatag')));
}
afficherArticles();
});
const toggleButton = function(button) {
if(button.innerHTML.indexOf('>') >-1){ //si l'élément contient "v " ( ou la balise image )
button.innerHTML = button.innerHTML.substring(button.innerHTML.indexOf(">")+1); //enlever "v ", ou la balise image, dans ce cas 2 devra être remplacé par le nombre de caractères de la balise image, ou event.target.innerHTML.substring(event.target.innerHTML.indexOf('>')), soit le chevron de fermeture de la balise
}
else{
button.innerHTML = "<img src='coche_verte.png' alt='coché'>" + button.innerHTML; //sinon ajouter "v " ou la balise image
}
button.toggleAttribute("isActive");//ajouter ou retirer l'attribut "isActive
}
const afficherArticles = function(button) {
let activeTags = [];//déclarer ou réinitialiser le array de tags actifs
for(i=0; i<document.getElementById('TABbuttons').children.length;i++){ //pour chaque bouton présent dans "TABbuttons"
if(document.getElementById('TABbuttons').children[i].hasAttribute('isActive')){//si l'élément a l'attribut "isActive"
activeTags.push(document.getElementById('TABbuttons').children[i].getAttribute('id').substring(7));//récupérer le nom du tag en découpant l'id du bouton ( enlever "TABbtn_", soit 7 caractères)
}
}
if(activeTags.length<1)//si aucun tag n'est activé
for(i=0;i<document.getElementById('MesArticles').children.length;i++){
document.getElementById('MesArticles').children[i].setAttribute('class', 'Art-visible');//afficher tous les articles
}
else{
for(i=0;i<document.getElementById('MesArticles').children.length;i++){
document.getElementById('MesArticles').children[i].setAttribute('class', 'Art-hidden');//sinon les cacher tous dans un premier temps
}
for(i=0;i<activeTags.length;i++){ //pour chaque tag présent dans le array des tags actifs
for(let y=0;y<document.getElementById('MesArticles').children.length;y++){ //et pour chaque article
if(document.getElementById('MesArticles').children[y].getAttribute('data-tag').indexOf(activeTags[i]) > -1) //si le tag est présent dans le data-tags
document.getElementById('MesArticles').children[y].setAttribute('class', 'Art-visible'); //afficher l'article
}
}
}
}
const createTABbuttons = function() { //créé les boutons TAB
let tagList = []; //déclare un array vide, qui sera rempli par les tags récupérés
let items = document.getElementById('MesArticles').children; //récupère un array contenant les liens contenus dans "MesArticles"
for(let i=0; i<items.length; i++){ //pour chaque lien
let dataTags = items[i].getAttribute('data-tag').split(' '); //récupère le data-tag, puis le transforme en array de tags
for(let y=0;y<dataTags.length;y++){ //Pour chaque tag de ce lien
if(!tagList.includes(dataTags[y])) //si le array tagList ne contient pas le tag
tagList.push(dataTags[y]); //ajouter le tag
}
}
for(i=0;i<tagList.length;i++){ //pour chaque tag contenu dans le array tagList
let newButton = document.createElement('button'); //créer un élément button
newButton.setAttribute('class', 'btn'); //lui attribuer la class 'btn'
newButton.setAttribute('id', 'TABbtn_' + tagList[i]); //lui attribuer un id
newButton.innerHTML = tagList[i]; //remplir le bouton avec la valeur du tag
newButton.addEventListener('click', () => { //lui ajouter un eventListener
toggleButton(event.target);
afficherArticles();
});
document.getElementById('TABbuttons').appendChild(newButton); //ajouter le bouton créé dans 'TABbuttons
}
}
Etant entendu que tu aies une image nommée "coche_verte.png" dans le même répertoire que ton HTML.
- Edité par LucasWerquin 19 octobre 2021 à 12:34:23
Merci, j'ai copié ton code 1/1, les boutons sont toujours là et fonctionnent correctement mais aucune action lorsque j'ajoute "?datatag=toto" à l'URL...
Erreur dans la console :
Uncaught ReferenceError: queryString is not defined
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
La meilleure solution est toujours la plus simple. Ma chaîne Youtube [Tutos pour débutants]
La meilleure solution est toujours la plus simple. Ma chaîne Youtube [Tutos pour débutants]