11521 sujets

JavaScript, DOM et API Web HTML5

Bonsoir à tous
Je suis en train de reprendre un vieux code et je tombe sur le problème suivant :
J'ai un code HTML de la forme suivante :

<div>
    <!-- différents éléments contenant du texte des images, etc. -->
    <ul> //liste de niveau 1
         <li>
             ...... 
             <ul> //liste de niveau 2
                .....
             </ul>
         </li>
         ........
    </ul>
    <!-- différents éléments contenant du texte des images, etc. -->
    <ul> //liste de niveau 1
         <li>
             ...... 
             <ul> //liste de niveau 2
                .....
             </ul>
         </li>
         ........
    </ul>
    ...
</div>


Je recherche les listes de niveau 1.
Pour le moment je fais

const div = ...;
const lists = div.querySelectorAll('ul');
for(const list of lists) {
    if(list.parentNode.isSameNode(div) {
        ....
    }
}

Il faudrait quelque chose comme
 div.querySelectorAll('>ul');
mais ce sélecteur est erroné.
Avez vous une solution à proposer ?
Merci de votre aide
Modérateur
Bonsoir,

j'aurais tenter un truc du genre :
const lists = document.querySelectorAll('ul');
for(const list of lists) {
    if(list.parentNode.tagName !='LI') {
        list.style.border='solid';// ou mieux classList.add('xx');
    }
}

tout en me méfiant des styles héritables par les enfants Smiley cligne

Cdt
Modérateur
Salut,

Tu as le choix :
1. (ce qui inclus un remapping au cas où)

let $uls = document.querySelectorAll('div > ul')


2. [^1]

let $div = document.querySelector('div')
let $uls = Array.from($div.childNodes).filter($el => $el.parentNode.nodeName === 'DIV' && $el.nodeName === "UL")


[^1] :
- nodeType (pour le contexte, ça te permet de filtrer par node et non par text/comment
- nodeName
Modifié par niuxe (10 Jan 2023 - 20:47)
Modérateur
ah zut, j'ai mal lu la question,
alors un
const lists = document.querySelectorAll('div>ul:not(ul ul)');
for(const list of lists) { 
        list.style.border='solid';    // ou mieux classList.add('xx');
}

serait peut-être plus approprié Smiley cligne ]

il faut au moins un parent pour appliquer un selecteur direct . au minimum un * > enfant_direct
Modifié par gcyrillus (10 Jan 2023 - 20:41)
Modérateur
gcyrillus a écrit :
ah zut, j'ai mal lu la question,


À moins que j'ai compris de travers, ta première proposition me parait pas mal Smiley smile . tu filtres dans le sens inverse de ce que j'ai proposé. Par contre, avoue que ton sélecteur est un peu violent (cibler tous les ul). Autant faire un div > ul Smiley smile
Modifié par niuxe (10 Jan 2023 - 20:42)
Modérateur
niuxe a écrit :


À moins que j'ai compris de travers, ta première proposition me parait pas mal Smiley smile


C'est le selecteur >ul que j'avais zappé en fait Smiley smile ça s’interprète comme ul enfant direct de rien Smiley decu
Modifié par gcyrillus (10 Jan 2023 - 20:44)
Modérateur
gcyrillus a écrit :


C'est le selecteur >ul que j'avais zappé en fait Smiley smile ça s’interprète comme ul enfant direct de rien Smiley decu


Ça me parait pas mal
Modifié par niuxe (10 Jan 2023 - 20:52)
Modérateur
niuxe a écrit :


Ça me parait pas mal


ah oui, c'est un peu brutal, mais ça marche aussi Smiley smile

Firefox semble être le seul qui bogue avec le selecteur > element lorsque > n'est préceder de rien.
Modifié par gcyrillus (11 Jan 2023 - 12:50)
Modérateur
Mathieuu a écrit :
Salut,

Ce n'est pas juste un truc dans le genre ?


document.querySelectorAll('ul:not(ul ul)')

ça marche aussi Smiley cligne voir https://forum.alsacreations.com/topic-5-90210-1-Enfants-direct-dun-nYud-avec-certaines-caracteristiques.html#p575378

:not() est plutôt bien implémenter , il y a :has() aussi qui devient assez fiable aussi Smiley smile , mais ne passe pas partout (FF => nop)
document.querySelectorAll('ul:has(ul)');

Modifié par gcyrillus (11 Jan 2023 - 13:49)
Merci de vos réponses.
Je remarque que vous utilisez document.querySelectorAll, mais on n’est pas forcé de rechercher dans tout le document, on peut très bien appliquer la méthode à n’importe quel noeud
myDiv.querySelectorAll(">ul"), si ça marchait, ne signifierait pas "enfant direct de rien" mais "enfant direct de myDiv".
Mais, bon! ça ne marche pas. Je dois donc remonter un cran au dessus (parent de myDiv) pour retrouver ce que je cherche.

Il faudrait que je regarde dans les quelques centaines de pages comment les infos sont écrites par le propriétaire du site…
L’exemple que j’ai donné est beaucoup plus simple que la réalité, évidemment.
Toutes les listes de niveau 1 ne contiennent pas des listes de niveau 2, mais certaines listes de niveau 2 contiennent des listes de niveau 3.
Mon programme actuel fonctionne, inutile de le remplacer par quelque chose d’aussi complexe qu’il faudrait mettre au point et maintenir.
Modifié par PapyJP (11 Jan 2023 - 14:21)
Personnellement j'utilise document pour rester sur un cas général que tu peux ensuite adapter facilement avec le sélecteur que tu veux pour limiter à la portion voulu si nécessaire :

document.querySelectorAll('ul:not(ul ul)')

myDiv.querySelectorAll('ul:not(ul ul)')


Et pour le coup ta remarque m'a fait penser à un cas qui pourrait être un bug potentiel avec ma formule : Si l'on cherche à obtenir le 1er niveau d'ul à partir d'un descendant d'un ul (on pourrait imaginer partir du premier niveau d'ul puis pour chacun récupérer récursivement le nouveau 1er niveau de ul).
J'ai testé, ça m'a l'air de bug, j'ai regardé la doc ( https://developer.mozilla.org/fr/docs/Web/API/Element/querySelectorAll#javascript ) il y a l'air d'y avoir un mot clé :scope qui semble adapté à ce problème, mais cela ne fonctionne pas j'ai l'impression Smiley ohwell (ou je ne sais pas m'en servir)

Exemple : https://jsfiddle.net/z80u4s7j/
Modérateur
PapyJP a écrit :
Merci de vos réponses.
Je remarque que vous utilisez document.querySelectorAll, mais on n’est pas forcé de rechercher dans tout le document, on peut très bien appliquer la méthode à n’importe quel noeud
myDiv.querySelectorAll("&gt;ul"), si ça marchait, ne signifierait pas "enfant direct de rien" mais "enfant direct de myDiv".
Mais, bon! ça ne marche pas. Je dois donc remonter un cran au dessus (parent de myDiv) pour retrouver ce que je cherche.

Il faudrait que je regarde dans les quelques centaines de pages comment les infos sont écrites par le propriétaire du site…
L’exemple que j’ai donné est beaucoup plus simple que la réalité, évidemment.
Toutes les listes de niveau 1 ne contiennent pas des listes de niveau 2, mais certaines listes de niveau 2 contiennent des listes de niveau 3.
Mon programme actuel fonctionne, inutile de le remplacer par quelque chose d’aussi complexe qu’il faudrait mettre au point et maintenir.


attention, chez moi et avec firefox : myDiv.querySelectorAll(">ul") ne fonctionne pas, pour FF il lui faut un élément devant le sélecteur , c'est pour cela que j'ai évoqué enfant direct de rien Smiley smile Chrome applique > ul à partir d'une feuille de style mais pas depuis un querySelector apparement Smiley decu .

le plus simple et économique est surement d'avoir un div >ul ou .maListe > ul pour ne cibler qu'un premier niveau depuis un conteneur nommé, soit à partir d'une feuille de style ou un querySelector si il faut traiter autre chose que de simple styles.

Cdt
Modifié par gcyrillus (11 Jan 2023 - 17:51)
Merci beaucoup
Effectivement j’utilise FF pour les tests et ce n’est qu’après coup que je vérifie si ça marche aussi sur d’autres navigateurs.
La bonne solution est sans doute de mettre un id sur la div et de faire document.querySelectorAll("#divID > ul").
J’ai d’autres cas de figure où j’aurais bien aimé utiliser ce sélecteur sans mettre un id dans la balise mère., mais au moins les choses sont un peu plus claires dans ma tête et je vais faire avec.
Modérateur
Enfin,
div.querySelectorAll('* >ul');

fonctionnerait comme attendu à priori.

Cdt
Meilleure solution
gcyrillus a écrit :
Enfin,
div.querySelectorAll('* &gt;ul');

fonctionnerait comme attendu à priori.

Cdt

Génial ! j'ai essayé, ça marche ! je vais changer mon code.
Modifié par PapyJP (12 Jan 2023 - 12:20)