Ir directamente al contenido de esta página

codexexempla.org

Problemas al eliminar elementos de una lista de nodos

Tabla de contenidos

  1. Introducción
  2. El problema
  3. La solución
  4. Pruebas en navegadores

Introducción

En «childNodes y el problema de los nodos de texto vacíos», al programar un JavaScript que limpiara un documento de nodos de texto vacíos y comentarios, topé con un problema: la primera versión del script no lograba acceder a los comentarios. Podría haber seguido dándome cabezazos contra la pantalla del monitor si no hubiese sido porque recordé que Peter-Paul Koch1 hacía referencia a un problema que podría ser al que me estaba enfrentando.

El problema

El problema es que las listas de nodos que se obtienen por medio de getElementsByTagName se actualizan inmediatamente cuando se alteran por medio de un script. Así, si se tiene una lista de elementos, la referencia a uno de ellos en concreto a través de su índice puede no dar el resultado deseado si ya se ha eliminado un elemento anterior. Quedará más claro a través de un ejemplo concreto.

Tenemos una lista de elementos. Si pinchamos, por ejemplo, el botón para obtener el tercer elemento de lista —que en la variable que recoge document.getElementsByTagName tiene el índice 2—, la alerta nos devuelve Agua. Seguidamente eliminamos ese li. Por último, pinchamos para obtener el cuarto elemento de la lista —el que originalmente tenía el índice 3—: no obtenemos Fuego, sino Vacío. ¿Qué ha ocurrido? Pues que en el mismo instante en el que hemos eliminado el tercer li, los índices del resto se han actualizado.

Los resultados, cuando se trata de eliminaciones automáticas, son más dramáticos. Con el mismo ejemplo, voy a aplicar este script:


    var lis = document.getElementsByTagName('li');
    
    function eliminar(){
        for (var i=0;i<lis.length;i++){
            lis[i].parentNode.removeChild(lis[i]);
        }
    }
            

El efecto deseado sería que el bucle fuese eliminando cada elemento de la lista, pero como se puede comprobar, el resultado no es ése. Para cuando i vale 0, se elimina el primer li; pero para cuando su valor es 1, lis[1] ya no apunta al segundo elemento de la lista original, puesto que éste ya ha actualizado su índice a 0; como consecuencia, el script no puede acceder a —y por tanto, no puede eliminar— los elementos que al actualizarse adopten un índice inferior al valor actual de i. Por ello, en el script inicial que desarrollé en «childNodes y el problema de los nodos de texto vacíos», al borrar los nodos de texto vacíos perdía la posibilidad de alcanzar los nodos de comentarios inmediatamente posteriores.

La vida del programador es dura.

La solución

La solución que recomienda ppk es crear una matriz en la que albergar los nodos que se quieran destruir, y después en otro bucle u otra función trabajar sobre esa matriz:


    var lis = document.getElementsByTagName('li');
    var nodos_a_eliminar = new Array();
    
    function eliminar(){
        for (var i=0;i<lis.length;i++){
            nodos_a_eliminar[nodos_a_eliminar.length] = lis[i];
        }
        for (var j=0;j<nodos_a_eliminar.length;j++){
            nodos_a_eliminar[j].parentNode.removeChild(nodos_a_eliminar[j]);
        }
    }
            

¿Y cómo puede ser así? Pues porque en la matriz se alojan referencias a cada elemento li concreto, y no a su posición dentro de una determinada lista de nodos que, como la donna de Verdi, è mobile.

Y sí, funciona, como se puede ver en este último ejemplo.

He comprobado que este script funciona correctamente —sobre Windows— en:

Notas

  1. En PPK on JavaScript, pp. 399-403. New Riders, 2006. Volver

Contacto

En virtud de la Ley Orgánica 15/1999 de Protección de Datos de Carácter Personal le informo de que los datos que proporcione no serán empleados para otro fin que el de responder a su mensaje. En especial, me comprometo a no cederlos a terceros ni a emplearlos para enviar información no solicitada.

Del blog de Digital Icon