MICHELEPISANI.IT

Guida al DOM

Tutto ciò che è necessario per scorrere la struttura della pagina attraverso i nodi

I nodi: metodi e proprietà

Agosto 20
07:532014

Di seguito una lista con breve spiegazione dei metodi e delle proprietà da applicare ai nodi, siano essi elementi che nodi di testo, per navigare la struttura di una pagina attraverso le sue interazioni (i nodi stessi). Dato che la rete è piena di esempi classici che riportano la sintassi standard per ciascuna funzione e che spesso e volentieri il loro utilizzo diretto in un contesto finisce con il non funzionare cercherò di fare di più inserirendo un esempio completo che ho realizzato e testato dove utilizzo tutti i metodi e le proprietà discusse.

Tra i metodi dei nodi citiamo hasChildNodes, nodo.hasChildNodes(), per verificare la presenza o meno di nodi figli dell'elemento indicato. Il valore restituito è di tipo true/false (boolean). Il metodo appendChild, nodoEsistente.appendChild(nuovoNodo), inserisce o "appende" il nodo passato alla funzione in fondo al nodo o alla lista dei figli del nodo indicato. Stessa cosa con insertBefore, nodoPadre.insertBefore(nodoNuovo,nodoFigliodiNodoIndicato), solo che questa inserisce il nodo passato al metodo prima di un nodo già presente all'interno del nodo indicato. Il metodo replaceChild, nodoPadre.replaceChild(nodoNuovo,nodoVecchio), sostituisce un nodo presente con uno passato alla funzione, mentre removeChild, nodoPadre.removeChild(nodoElimina), rimuove un nodo da un altro nodo e lo restituisce al metodo per eventuali utilizzi. Interessante anche il metodo cloneNode, nodoIndicato.cloneNode(true), che serve per duplicare un nodo con tutti i suoi attributi ed eventualmente con tutti i suoi figli (mentre duplica solo il nodo senza figli se il parametro passato è false) e lo ritorna al metodo.

Tra le proprietà menzioniamo childNodes, nodo.childNodes, che applicato ad un elemento restituisce un array dei nodi figli ove presenti, altrimenti il suo valore sarà vuoto. Per conoscere il numero dei figli di un nodo basta utilizzare la proprietà length di Javascript (nodo.childNodes.length). La proprietà firstChild di un nodo, nodo.firstChild, restituisce il riferimento al suo primo figlio ove presente, altrimenti il suo valore sarà null. Lo stesso riferimento si può ottenere con la proprietà precedente indicando l'elemento con l'indice 0, nodo.childNodes[0]. Stesso discorso per lastChild, nodo.lastChild, ma per recuperare il riferimento dell'ultimo nodo figlio di un elemento; lo stesso riferimento si può recuperare con la proprietà childNodes agendo sul numero dei nodi figli e recuperando il penultimo indice, nodo.childNodes[nodo.childNodes.length - 1]. La proprietà nextSibling, nodo.nextSibling, serve per recuperare il nodo successivo adiacente a quello indicato, se non esiste viene restituito null. Stesso ragionamento con previousSibling, nodo.previousSibling,ma per recuperare quello immediatamente precedente. La proprietà parentNode, nodo.parentNode, ad eccezione se applicata ad un nodo di testo o all'oggetto document dove restituirà null, dà sempre come risultato il riferimento al nodo gerarchicamente superiore a quello indicato. La proprietà nodeValue, nodo.nodeValue, restituisce il valore del nodo, solitamente utilizzato per i nodi di tipo testuale, se non esiste un valore viene restituito null.

Come promesso riporto di seguito un pezzo di codice testato e funzionante con tutti i metodi e le proprietà elencate.

Codice HTML:

<head>
  <style type="text/css">
    .selected_item {color:#AA0000;}
    .added_item {color:#00AA00;}  
  </style>
</head>
<body id="corpo">
    <div id="contenitorePrincipale">
        <h1>Titolo</h1>
        <h2>Sottotitolo</h2>
        <p>Questo e' un paragrafo</p>
        <ul id="lista">
            <li class="selected_item">Primo elemento</li>
            <li>Secondo elemento</li>
            <li>Terzo elemento</li>
        </ul>
        <p id="par2">Secondo paragrafo (Questo paragrafo verrà rimosso la prima volta che clicchi sul secondo bottone)</p>
        <p >Terzo paragrafo</p>
        <p>Ultimo paragrafo</p>
    </div>        
    <input type="button" value="Analizza il contenitore" onclick="testFirstContainer();" /><br />
    <input type="button" value="Esegui operazioni sul contenitore" onclick="testActions();" /><br /><br />
    NB: il primo bottone dà informazioni sul contenuto del contenitore, il secondo bottone esegue alcune operazioni tra cui eliminare un paragrafo ed inserire e/o clonare e sostituire elementi nella lista.
</body>

Funzioni Javascript:

function testFirstContainer() {
    var idNodo = document.getElementById("contenitorePrincipale");
    var idNodoLista = document.getElementById("lista");
    var numeroFigli = idNodo.childNodes.length;
    var primoNodoFiglio = idNodo.firstChild;
    var ultimoNodoFiglio = idNodo.lastChild;
    
    var listaMsg = "La lista ha " + idNodoLista.childNodes.length + " nodi figli";
    if (!idNodoLista.hasChildNodes) {listaMsg = "La lista NON ha figli";}
    
    alert("primoContenitore ha " + numeroFigli + " figli
Il valore del primo nodo adiacente al contenitore e' il testo stesso ovvero '" + primoNodoFiglio.nextSibling.firstChild.nodeValue + "'
Il valore dell'ultimo e' invece '" + ultimoNodoFiglio.previousSibling.firstChild.nodeValue + "'
Inoltre 'primoContenitore' e' figlio di '" + idNodo.parentNode.id + "'
" + listaMsg);
}

function testActions() {
    var idNodo = document.getElementById("contenitorePrincipale");
    var idNodoLista = document.getElementById("lista");
    var idNodoSecondoPar = document.getElementById("par2");
    if (idNodoSecondoPar != null && idNodoSecondoPar != 'null' && idNodoSecondoPar != '') {
        idNodo.removeChild(idNodoSecondoPar);
    }
    var li_element = document.createElement("li");
    li_element.innerHTML = "<li class='added_item'>Elemento aggiunto in fondo alla lista</li>";
    idNodoLista.appendChild(li_element);
    
    var elementoClonato = idNodoLista.firstChild.nextSibling.cloneNode(true);   
    idNodoLista.insertBefore(elementoClonato,idNodoLista.childNodes[1].nextSibling)
    var elementoSostituto = document.createElement('li');
    elementoSostituto.innerHTML = "Clonato 'Primo elemento', inserito nella lista prima dello stesso e sostituito il testo con il presente messaggio";
        idNodoLista.childNodes[1].firstChild.parentNode.replaceChild(elementoSostituto.firstChild,idNodoLista.childNodes[1].firstChild);
    
    alert(idNodoLista.childNodes[1].firstChild.nodeValue + " - " + elementoSostituto.firstChild.nodeValue);
}


Di seguito, nel tab "Result", l'esempio dal vivo dove potete testarne l'effettivo funzionamento (sicuramente su Firefox ed IExplorer):

 

E' bene sapere che non tutti i browser possono interpretare i nodi allo stesso modo, un esempio eclatante è l'intepretazione degli spazi che causa un malfunzionamento su l'uno o sull'altro browser del codice prodotto. Esistono per questo motivo dei workaround per ovviare al problema, il primo tra tutti è quello di limitare al massimo le ambiguità. Spiegandomi meglio, se ho una lista (ul) e voglio recuperare il riferimento al primo elemento di lista (li), verrebbe automatico l'impiego della proprietà firstChild con il problema però che il primo figlio di un elemento lista può essere considerato per un browser il primo elemento vero e proprio mentre per un altro uno spazio vuoto, da qui nasce la problematica della gestione degli spazi e per evitare la loro intepretazione e le conseguenti risposte di tipo null conviene utilizzare le collection come già mostrato nell'articolo riferito all'oggetto document.
Per chiarire il concetto e per essere certi di recuperare tutti e solo gli elementi della lista (li) è possibile ricorrere al metodo getElementsByTagName() che recupera una famiglia di elementi, una collezione appunto, caratterizzata dallo stesso tag organizzata in un array. Va da se che l'elemento di lista di nostro interesse sarà il primo elemento dell'array con indice 0.

var riferimento_lista = document.getElementById("lista");

// Preferito alla proprietà firstChild per recuperare il primo elemento di lista
var elementi_lista = riferimento_lista.getElementsByTagName("li")
var primo_elemento = elementi_lista.item(0)

 

Tags
Condividi

Autore

Michele Pisani

Michele Pisani

Ho uno spiccato orientamento al problem-solving, se è troppo facile non mi diverto :)
Credo nella volontà e nel cambiamento perchè hanno fatto della mia passione il mio pane quotidiano.
Se devo descrivermi con una sola parola direi... "Concretezza", la mia stretta di mano è una garanzia.

0 Commenti

Non ci sono commenti

Nessuno ha ancora commentato questo articolo, fallo tu per primo!

Scrivi un Commento

Scrivi un Commento

Il tuo indirizzo email non sarà pubblicato.
I campi contrassegnati da un * sono obbligatori

Articoli e Argomenti correlati

Categorie popolari

Iscriviti alla mia newsletter

La tua e-mail con me sarà al sicuro.
Non fornirò mai le tue informazioni a nessuno!

Ultimi commenti

Michele Pisani

Ciao alessandro,
questa regex dovrebbe fare al caso tuo:

alessandro

ciao sto cercando una regex per numeri interi o decimali, positivi o negativi; la tua regex mi pare …

Michele Pisani

Ciao Nicola,
ti riferisci per caso alla situazione di gianluigi?
In tutti i casi la via …

Nicola

Ciao Michele, mi trovo nella medesima situazione in cui si trovava Gianluca un anno fa. Sei poi …