Get great-grandson of a div

5

How can I get the great-grandchild of a div ? Eye without libraries, only pure JavaScript . In this case, it's not just about the great-grandson, but I really want to locate any son, grandson or great-grandchild.

In the following code, is it advisable to use [0] ? If I change the position element, the tag will no longer work. I mean that the index indicates a position and if a tag is added or deleted different elements will be obtained.

var x = document.getElementById("uno");
var y = x.children[0];
console.log(x, y);
<div id="uno">
  <div id="cuatro">
    otro
  </div>
  <div id="dos">
    <div id="tres">
      hola
    </div>
  </div>
</div>
    
asked by hubman 04.07.2017 в 02:46
source

5 answers

4

I recommend extending the prototype of Node , since every HTMLElement inherits the prototyping of Node , this is recommended when the use of the function is intense, it can be seen as a more sugary syntax or an extension to the WebAPI

;(function()
{
"use strict"
/**
 * Obtiene el i-ésimo hijo de un Nodo
 * nodo.getChildDepth(i)
 */
Node.prototype.getChildDepth = function(depth) 
{
	var depth = depth && depth > 0 ? depth : 1
	var child = this.children[0] // fix text nodes

	for (let i = 0; child != undefined && (i < depth - 1) ; i++) 
	  {
	  	child = child.children[0]
	  }

	return child
}
var body = document.body;
console.log(body.getChildDepth(1)) // return div#uno
console.log(body.getChildDepth(2))// return div#dos
console.log(body.getChildDepth(3)) // return div#tres
console.log(body.getChildDepth(4)) // return undefined
}())
<div id="uno">
  <div id="dos">
    <div id="tres">
      hola
    </div>
  </div>
</div>
    
answered by 04.07.2017 в 03:47
4

I know that this method may seem a bit crazy, but you can use the direct descendant selector > next to the universal selector * , to select all descendants of level N.

The universal selector is the least efficient and slowest, but in modern browsers (and limiting its scope to a part of the page in particular) its impact on the performance of the page should not be important. If you only want to work with div , you could replace the * below with div and the result would be more efficient.

From that, you can make a function that creates a selector of N levels (for example, children would be #padre > * , grandchildren would be #padre > * > * , great grandchildren would be #padre > * > * > * , and so on). For each level there should be a > * .

Then we would have this function that would take as parameters the selector of the element from which we want to obtain its descendants, and a number specifying the level of the descendant:

function getDescendientesDeNivel(selector, nivel) {
  // si no es un nivel válido, devolvemos false
  if (!nivel || nivel < 1) { return false; }
  // creamos un selector con el selector del elemento raíz y n veces  "> *"
  var selector = selector + Array(nivel + 1).join(" > *");
  // devolvemos los elementos seleccionados
  return document.querySelectorAll(selector);
}

And here's a demo:

function getDescendientesDeNivel(selector, nivel) {
  if (!nivel || nivel < 1) { return false; }
  var selector = selector + Array(nivel + 1).join(" > *");
  return document.querySelectorAll(selector);
}

var hijos = getDescendientesDeNivel("#padre", 1);
var nietos = getDescendientesDeNivel("#padre", 2);
var bisnietos = getDescendientesDeNivel("#padre", 3);
var tataranietos = getDescendientesDeNivel("#padre", 4);

console.log(bisnietos);
<div id="padre">
  <div id="hijo-1">
    <div id="nieto-1">
    </div>
  </div>
  <div id="hijo-2">
    <div id="nieto-2">
      <div id="bisnieto-1">
      </div>
    </div>
    <div id="nieto-3">
    </div>
  </div>
  <div id="hijo-3">
    <div id="nieto-4">
    </div>
    <div id="nieto-5">
      <div id="bisnieto-2">
      </div>
    </div>
  </div>
</div>

This function can be used to extend the prototype of Node (as suggested by Eduen in your answer ) , which could be done using :scope to specify that you start searching from the active element:

Node.prototype.getDescendientesDeNivel = function(nivel) {
  if (!nivel || nivel < 1) { return false; }
  var selector = ":scope " + Array(nivel + 1).join(" > *");
  return this.querySelectorAll(selector);
}

What you can see working here:

Node.prototype.getDescendientesDeNivel = function(nivel) {
  if (!nivel || nivel < 1) { return false; }
  var selector = ":scope " + Array(nivel + 1).join(" > *");
  return this.querySelectorAll(selector);
}

var padre = document.getElementById("padre");
var hijos = padre.getDescendientesDeNivel(1);
var nietos = padre.getDescendientesDeNivel(2);
var bisnietos = padre.getDescendientesDeNivel(3);
var tataranietos = padre.getDescendientesDeNivel(4);

console.log(bisnietos);
<div id="padre">
  <div id="hijo-1">
    <div id="nieto-1">
    </div>
  </div>
  <div id="hijo-2">
    <div id="nieto-2">
      <div id="bisnieto-1">
      </div>
    </div>
    <div id="nieto-3">
    </div>
  </div>
  <div id="hijo-3">
    <div id="nieto-4">
    </div>
    <div id="nieto-5">
      <div id="bisnieto-2">
      </div>
    </div>
  </div>
</div>
    
answered by 04.07.2017 в 06:25
2

One possibility would be that, after selecting the parent div, you would make a getElementsByTagName('div') to get all the divs that are nested.

Then as you wish the last one with length - 1 you get the one you are looking for.

var x=document.getElementById("uno").getElementsByTagName("div");
console.log(x[x.length - 1]);
<div id="uno">
  <div id="dos">
    <div id="tres">
      hola
    </div>
  </div>
</div>

The second option is how you were doing but you missed x.children[0].children since children returns an array of children, therefore you must use the [0] to specify which child you are going to search for (In this case, there is only 1 , it is placed 0) and after this, say that you return your children.

var x=document.getElementById("uno");
var y=x.children[0].children;
console.log(y);
<div id="uno">
  <div id="dos">
    <div id="tres">
      hola
    </div>
  </div>
</div>
    
answered by 04.07.2017 в 03:05
1

With your own code provided it may be possible. We only have to access the children of the second element:

var x=document.getElementById("uno");
 var y=x.children;
 var bisnieto = y[0].children[0];
 console.log(x);
 console.log(bisnieto)
<div id="uno">
  <div id="dos">
    <div id="tres">
      hola
    </div>
  </div>
</div>
    
answered by 04.07.2017 в 03:07
1

It is not really necessary to use libraries for this, since javascript provides a very powerful DOM scanning tool that is based on the search from CSS selectors

  

« querySelectorAll » returns a list of items within the   document, ... is compatible with Chrome 1+, Firefox (Gecko) 3.5+,   Internet Explorer 8+, Opera 10+ and Safari (WebKit) 3.2 +

for more information you can consult at: link

One way to implement it in your problem would be something like this:

var descendencia = document.querySelectorAll("#uno div"); //Lista a cualquier div descendiente
var i = descendencia.length;                              //Cuentas las coincidencias
while (i--) {                                             
  console.log(descendencia.item(i));                      
}
<div id="uno">
  <div id="cuatro">otro</div>
  <div id="dos">
    <div id="tres">hola</div>
  </div>
</div>
    
answered by 04.07.2017 в 04:42