DOM


Il W3C ha creato il modello DOM (Document Object Model), un sistema tramite il quale gli script possono agire sulla pagina web ovvero il documento html. Esso consente a Javascript non solo di apportare modifiche alla struttura del documento , ma anche di accedere ai suoi stili, per cambiare il suo aspetto. Il browser trasforma il documento html (una lunga stringa di caratteri ) in una pagina web divisa in titoli, paragrafi, immagini, etc. Il browser conserva la propria interpretazione del codice html come una struttura di oggetti Javascript chiamata modello DOM. In questo modello ogni elemento, attributo e testo diviene un oggetto. Utilizzando opportune funzioni (metodi) Javascript può modificare gli elementi desiderati. Il codice html è scritto con una gerarchia di elementi nidificati rappresentati da tag-start e tag-end (quello che contiene è definito genitore, quello contenuto figlio). Il DOM, per ogni elemento, crea un oggetto distinto che unisce con il relativo genitore e così via. Le relazioni genitori-figlio che si creano, costituiscono una gerarchia ad albero.

Nodo elemento : è rappresentato con un rettangolo con all'interno il nome del tag. I vari nodi sono uniti fra di loro da linee continue. Nello schema i genitori sono sopra i figli e viceversa.

Nodi testuali : tutto ciò che non è contenuto tra parentesi angolari, viene interpretato dal modello DOM come nodo testuale. Sono rappresentati come i nodi elemento, ma al contrario di questi, non possono avere figli (cioè sono terminali del ramo). All'interno del simbolo che rappresenta il titolo va scritto il testo, o riferimenti all'immagine. Viene collegato con l'elemento genitore mediante una linea continua. E' importante precisare che alcuni browser considerano nodi testuali anche gli spazi vuoti creati con l'indentazione del codice e i codici di fine riga. Quindi bisogna prestare molta attenzione quando si contano gli elementi e si cercano, vedremo come, in base all'ordine.

Nodi attributi : sono uniti da linee continue all'elemento e sono contenute graficamente all'interno di cerchi, non sono considerati figli, quindi non fanno parte della struttura del DOM, ma sono legati all'elemento. Quindi la modifica richiederà metodi specifici.


Prendendo il seguente codice HTML come esempio :

<!DOCTYPE html>

<html>

<head>

<title>titolo</title>

<head>

<body>

<p>

Oggi è una bella giornata

<a href=”www.reggioemilia.it”>reggio emilia</a>

</p>

<a href=”www.inter.it”>vai al sito dell'inter</a>

</body>

</html>

La struttura della pagina HTML ha ogni elemento collegato al proprio genitore :

per esempio : <html> è genitore e ha due figli : <head> e <body>



mentre l'albero del modello DOM, ha in alto il nodo principale sempre presente che è rappresentato dal nodo document :



Accedere ai vari nodi del DOM, per fare modifiche o impostare delle caratteristiche, richiede un metodo per identificare gruppi o singoli elementi o oggetti. Il metodo è lo stesso che viene usato per gli ID del linguaggio CSS. Quindi, agli elementi che devono essere gestiti singolarmente, devono avere l'attributo id.

Manipolare un elemento DOM è un po' come applicare un effetto da CSS :

  1. specifico l'elemento o gli elementi da modificare

  2. specifico l'effetto che voglio ottenere su di essi

Il percorso diretto per raggiungere un elemento prevede l'uso dell'attributo id. Il valore assegnato a questo attributo, all'interno dello stesso documento deve essere univoco :


esempio

<p id=”idesempio”> …. </p>


con questa tecnica è possibile individuare, mediante script, qualsiasi elemento. Questo identificativo è utilizzato anche dal linguaggio CSS, e per definire le caratteristiche dell'elemento si usa il simbolo # come prefisso del valore dell'id :


esempio di codice CSS legato all'esempio di codice HTML sopra

#idesempio

{

color:red;

}


Il codice CSS è molto spoglio e immediato, mentre Javascript per far riferimento a un elemento con un id utilizza il metodo getElementById(“valore_id”) che è disponibile solo per l'elemento document. Questo metodo accetta come argomento una stringa : il valore dell'attributo id (in questo caso si punta solo l'elemento con il valore dell'id corrispondente).


var pluto = getElementById(idesempio);


la variabile pippo farà riferimento al nodo del DOM relativo al tag <p> con attributo id=”idesempio”.


Se si vogliono puntare tutti gli elementi di un tag specifico uso il metodo getElementsByTagName(“nome_tag”) . In questo caso il metodo individua, l'ordine in cui incontra i tag omogenei specificati nel codice. Quindi se ho un codice HTML di questo tipo

<p>primo paragrafo</p>

...

<p>secondo paragrafo</p>

<p>terzo paragrafo</p>

...

<p>quarto paragrafo</p>


mediante l'istruzione Javascript


var pippo = document.getElementsByTagName(“p”);


in questo caso la variabile pippo è tipo un array. Quindi io posso puntare i specifici elementi omogenei con l'indice, così come si fa negli array. Per creare una variabile che fa riferimento al terzo paragrafo, quello che contiene “terzo paragrafo”, posso scrivere (tenendo presente che gli indici partono da 0)


var pippo3 = pippo[2];


Le variabili che rappresentano gli elenchi di nodi, hanno il metodo lenght, che permette di visualizzare il numero di elementi


var num_p = pippo.lenght;


e nel nostro caso num_p=4. Il metodo è utile per evitare errori e puntare tag che non esistono. Infatti anche se non esistono tag del tipo specificato, viene comunque creato un elenco che avrà lunghezza 0. Un altro metodo che funziona con entrambi i metodi visti sopra, è quella di visualizzare a quali tag è riferita la variabile, il metodo è nodeName quindi scrivendo


alert(pluto.nomeNode);//visualizza una finestra con il nome del tag, nel nostro caso p


alert(pippo[2].nomeNode);//visualizza il tag del terzo tag ricercato, nel nostro caso p


Volendo, il metodo che fa riferimento ai nomi dei tag può svincolarsi dall'elemento document che si rivolge all'intero documento. Ipotizzando di avere il seguente codice :


<ul>

<li>riga a1</li>

<li>riga a2</li>

<li>riga a3</li>

<li>riga a4</li>

</ul>

...

<ul>

<li>riga b1</li>

<li>riga b2</li>

<li>riga b3</li>

<li>riga b4</li>

</ul>

<ul>

<li>riga c1</li>

<li>riga c2</li>

<li>riga c3</li>

<li>riga c4</li>

</ul>


è possibile mediante


var pippo = document.getElementsByTagName(“ul”);

var pippo3 = pippo[3];

var pippo3_1 = pippo3.getElementsByTagName(“li”);


in questo caso pippo3_1 fa riferimento ai 4 elementi <li> che contengono riga c?. Mediante il codice


var pippo3_1_2 = pippo3_1[1];


che contiene il riferimento al <li> che contiene “riga c2”.

Per creare un elenco con tutti i tag della pagina, senza specificarne il nome, passo al posto del nome del tag il simbolo speciale “*” :


var tuttiTag = getElementsByTagName(“*”);


questo non funziona con Internet Explorer con cui uso l'oggetto speciale :


document.all;


quindi non sapendo con che browser verrà aperta la pagina devo scrivere il seguente codice :


var tuttiTag = [];

if (typeof document.all != “undefined”)

{

tuttiTag = document.all;

}

else

{

tuttiTag = document.getElementsByTagName(“*”);

}


questo codice verifica se esiste document.all, in tal caso esegue il primo blocco, perché il browser utilizzato gestisce tale oggetto (oltre a Internet Explorer altri browser gestiscono document.all) altrimenti esegue il secondo blocco.


Nota – Typeof controlla il tipo di dati e restituisce una stringa che identifica tale ricerca (es. “number”, “string”, “object” quest'ultimo fornito anche in caso di valore NULL. Ma se viene passata una variabile o un oggetto senza valore restituisce la stringa “undefined”.


Abbiamo visto metodi per arrivare ad avere riferimenti a elementi ben precisi del DOM. Ricordando che per ogni elemento si ha un genitore (ad eccezione dell'elemento document), e ogni genitore può avere più figli. Quindi per raggiungere il genitore da uno dei figli o raggiungere uno dei figli dal genitore, ho a disposizione dei metodi specifici. Partendo dal codice :


<ul id=”elenco1”>

<li id=”elenco1_1”>riga a1</li>

<li>riga a2</li>

<li>riga a3</li>

<li>riga a4</li>

</ul>

...

<ul id=”elenco2”>

<li>riga b1</li>

<li>riga b2</li>

<li>riga b3</li>

<li>riga b4</li>

</ul>

vediamo che ho individuato i due elenchi con due id. Ora con il metodo parentNode posso ricavare il riferimento al genitore :


var rigaElenco1_1 = document.getElementById(“elenco1_1”);

var genElenco1_1 = rigaElenco1_1.parentNode;


infatti la variabile genElenco1_1 fa riferimento all'elenco genitore della riga a cui fa riferimento la variabile rigaElenco1_1.

Mentre con il metodo childNodes posso ricavare il riferimento a uno dei figli :


var elenco_1 = document.getElementById(“elenco1”);

var riga1Elenco_1 = elenco_1.childNodes[0];


la variabile riga1Elenco_1 fa riferimento al primo figlio (in ordine nel codice) del genitore elenco_1.

Ci sono altri due metodi che puntano il primo e l'ultimo figlio di un genitore : firstChild e lastChild. Ecco come usarli facendo riferimento al codice precedente :


var elenco_1 = document.getElementById(“elenco1”);

var primaElenco_1 = elenco_1.firstChild;

var ultimoElenco_1 = elenco_1.lastChild;

Se invece abbiamo la necessità di spostarci tra nodi dello stesso livello abbiamo i due metodi : nextSibling e previousSibling. Il primo permette di raggiungere l'elemento seguente, mentre il secondo l'elemento precedente. Prendendo il seguente codice come riferimento

<ul id=”elenco1”>

<li id=”elenco1_1”>riga a1</li>

<li>riga a2</li>

<li>riga a3</li>

<li>riga a4</li>

</ul>

...

<ul id=”elenco2”>

<li>riga b1</li>

<li>riga b2</li>

<li>riga b3</li>

<li>riga b4</li>

</ul>

e scrivendo il codice per assegnare a una variabile il riferimento all'elemento scritto in rosso :

var elenco2 = document.getElementById(“elenco2”);

var riga_b2 = elenco2[1];

var prima_riga_b2 = riga_b2.previousSibling;

...

mentre per assegnare a una variabile il riferimento all'elemento scritto in viola :

var elenco2 = document.getElementById(“elenco2”);

var riga_b2 = elenco2[1];

var prima_riga_b2 = riga_b2.previousSibling;

...

Quando ci si trova all'ultimo o al primo elemento dello stesso livello, cercando rispettivamente il seguente o il precedente, ottengo un valore NULL che verrà assegnato alla variabile.


ATTRIBUTI

Gli attributi fanno parte integrante dell'elemento a cui sono abbinati (infatti vanno scritti all'interno delle parentesi angolari del tag-start). Quindi nel DOM possono essere rappresentati, ma ci sono solo 2 metodi per per lavorare con gli attributi, e sono utilizzabili solo dopo aver raggiunto un riferimento all'elemento. Raggiunto l'elemento si può leggere il valore assegnato ai suoi attributi passando la stringa del nome dell'attributo stesso al metodo getAttribute. Per esempio, se abbiamo un link

<a href = “http://www.inter.it” id=”inter”>vai al sito della migliore squadra italiana</a>

procedo in questo modo

var linkInter = document.getElementById(“inter”);

var indInter = linkInter.getAttribute(“href”);


A questo punto la variabile indInter contiene la stringa “http://www.inter.it”.

Questo sistema, che vale per tutti gli attributi che posso assegnare agli elementi, rispetta le regole fissate da W3C, però non tutti i browser lo gestiscono. Quindi se provando con alcuni browser si hanno dei problemi è possibile utilizzare dei metodi classici. Scrivo direttamente il nome dell'attributo senza il metodo. Lo stesso esempio di prima diventa :

var linkInter = document.getElementById(“inter”);

var indInter = linkInter.href;

nella maggior parte dei casi funziona, ma in alcuni casi il nome dell'attributo è una parola riservata e quindi nei due casi si usa :

  1. se l'attributo è class scrivo : className

  2. se l'attributo è for scrivo : htmlfor

Oltre a essere letti, i valori degli attributi possono essere scritti (cioè inserire attributi non presenti nel codice) o modificati sul DOM. Il metodo per scrivere i valori degli attributi è setAttribute a cui vanno passate due stringhe separate da virgola, la prima è il nome dell'attributo e la seconda è il valore da assegnare all'attributo stesso.

var linkInter = document.getElementById(“inter”);

linkInter.setAttribute(“href”,”http://www.inter/articolo23/”);

linkInter.setAttribute(“title”,”collegamento sito inter”);

Con questo codice l'indirizzo a cui punterà il link è http://www.inter/articolo23/”. Con la terza riga è stato aggiunto l'attributo title al collegamento che diventa :

...

<a href = “http://www.inter.it/articolo23/” id=”inter” title=”collegamento sito inter”>vai al sito della migliore squadra italiana</a>

...

Questo attributo è funzionante su tutti i browser, quindi non ha senso usare altri metodi.

L'effetto più grande che si può raggiungere è lavorare sull'attributo style che contiene il codice CSS. L'unica eccezione è che le istruzioni formate da parole composte, che nel linguaggio CSS sono unite dal trattino “-” in Javascript, all'interni del codice, vengono scritte con la tecnica del Camel case (es. background-color diventa backgroundColor), se viene usato il simbolo Javascript tenterà di eseguire la differenza tra le due parole con conseguente errore. Quindi se per esempio ho un codice HTML tipo :

<p id=”paragrafoA” style=”color:yellow; background-color:blue;”>Testo giallo e sfondo blu</p>

var parA = document.getElementById(“paragrafoA”);

parA.style.color = “blue”;

parA.style.backgroundColor = “yellow”;

sotto possiamo vedere l'effetto iniziale della pagina (a sinistra), e poi dopo le ultime tre istruzioni in javascript (a destra).



E' importante ricordare, che se le impostazioni del CSS vanno in contrasto con il codice originale che gestisce il layout della pagina, quello inline ha priorità, quindi vince per esempio sulle impostazioni scritte in un file esterno .css e legato all'elemento mediante l'id. Per evitare che certe dichiarazioni fatte in CSS vengano modificate, bisogna aggiungere la parola chiave !important. Quindi se avessi avuto un id sul file .css come il seguente :

...

p#paragrafoA

{

color : yellow !important;

background-color : blue;

font-family : verdana, arial, sans-serif;

}

...

non avrei potuto cambiare la proprietà del colore del testo. Avrei potuto cambiare la proprietà del tipo di carattere (font-family) o come nel codice sopra il colore di sfondo (background-color). Il consiglio è di usare il meno possibile Javascript per la formattazione del Layout. Infatti HTML, CSS e Javascript hanno ruoli diversi e vanno tenuti separati. Quindi è consigliabile cambiare il valore dell'id per assegnare codici CSS diversi agli elementi, in questo modo cambia il layout, ma il codice che lo gestisce è sempre CSS, così come deve essere. Ovviamente per creare degli effetti, come le dimensioni di una finestra o la sua posizione, è possibile lavorare sulle proprietà delle relative dichiarazioni.