Je peux évidemment faire ceci:
d3.selectAll('div#some-div>ul')
Mais que se passe-t-il si j'utilise un nœud DOM ou une sélection D3 existante:
d3.select(this).selectAll('ul')
va me chercher tous les ULs descendants. Donc si
var div = d3.select('div')
m'a obtenu ce noeud:
<div>
<ul>
<li>foo
<ul><li>bar</li></ul>
</li>
<ul>
</div>
Ensuite
var uls = div.selectAll('ul')
va me chercher deux UL. Je suppose que je pourrais distinguer un niveau supérieur comme:
uls.filter(function() { return this.parentNode === div.node() }
Donc, j'ai répondu à ma propre question. Peut-être que ce sera utile à quelqu'un. Ou peut-être que quelqu'un peut recommander une solution moins laide.
La réponse de nrabinowitz ci-dessous est meilleure et renvoie des résultats identiques à ceux ci-dessus. Voici un violon altéré qui les compare (mais n'utilise pas console.log, qui agit bizarrement pour moi dans jsfiddle)}
La solution de @ nrabinowitz ne fonctionne pas tout le temps.
Dans mon cas, j'essayais de faire d3.select(this).selectAll(".childNode > *")
.
J'essayais donc d'obtenir tous les enfants immédiats de .childNode. Le problème est qu'il s'agissait d'une pile imbriquée. Ainsi, .childNode pouvait également apparaître dans les enfants, ce qui posait problème.
Le meilleur moyen que j'ai trouvé est:
var child = d3.select(this).select(".childNode");
var sel = d3.select(this).selectAll(".childNode > *").filter(function() {
return this.parentNode == child.node();
});
Je ne m'attendais pas à ce que cela fonctionne, mais il semblerait que D3 sous-sélectionne tout élément enfant de la sélection et que correspond au sélecteur - cela fonctionne donc:
d3.select(this).selectAll('div > ul');
Si quelqu'un est toujours intéressé, d3.select(this.childNodes)
m'aidait à résoudre mon problème de sélection de tous les enfants immédiats. Alternativement, vous pouvez utiliser
selection.select(function(){
return this.childNodes;
})
La méthode selectAll
repose sur la méthode native querySelectorAll
(au moins en v4).
Cela signifie que vous pouvez utiliser le pseudo-sélecteur :scope
:
var uls = div.selectAll(':scope > ul')
le pseudo sélecteur :scope
est actuellement une spécification draft et n'est pas encore pris en charge par tous les navigateurs. Plus d'informations sur le pseudo sélecteur :scope
disponible sur MDN
d3.selectAll('#id > *')
peut être utilisé, p.ex. dans d3.selectAll('#id > *').remove()
pour supprimer tous les enfants d'un élément avec id = id
Basé sur la solution de Sigfrid, voici quelque chose que j'ai ajouté au prototype, dans un projet sur lequel je travaille.
/**
* Helper that allows to select direct children.
* See https://stackoverflow.com/questions/20569670/d3-selector-for-immediate-children
*
* @param {string} selector
* @returns {Selection}
*/
d3.selectAll('__nonexisting__').__proto__.MYPREFIX_selectChildren = function (selector) {
var expectedParent = this.node();
return this.selectAll(selector).filter(
function() {
return this.parentNode === expectedParent;
}
);
};
La façon dont je saisis l'objet prototype a l'air un peu maladroite. Peut-être y a-t-il un meilleur moyen.
"MYPREFIX_" est destiné à empêcher les conflits de noms.
Le jsdoc @returns {Selection}
est ambigu, ce type est malheureusement déclaré dans une fermeture et ne possède pas de nom global référençable par jsdoc (afaik).
Une fois ce fichier inclus, vous pouvez alors procéder comme suit:
d3.select('#some_id').MYPREFIX_selectChildren('ul')