Treeview con caricamento dinamico dei nodi 'figlio'

di Andrea Zani, in .NET,

Le domeniche pomeriggio tra le fredde Alpi sono tristi. Il sole sorge tardi e tramonta presto. Fa freddo. Eccomi allora a fare le mie prove - utili o meno - con .net e altri divertimenti simili. In questi giorni mi trovo troppo spesso a far uso di treeview. Se per la versione 2.0 di asp.net il web control inserito può definirsi sufficiente per il 90% delle situazioni, per asp.net 1.1 la cosa non può definirsi così rosea. L'uso del treeview presente nei wbecontrol scaricabili in aggiunta dal sito di Microsoft è limitata a Explorer, e se non ricordo male, non permette il caricamento dinamico dei nodi "figli".

L'argomento lo avevo già trattato in un mio vecchio blog. E sempre in quel blog citavo un treeview che personalmente trovato, e trovo, ben fatto, quello realizzato con una manciata di righe di codice Javascript e CSS, presente sul portale Constile. L'unico suo difetto è l'impossibilità di caricare dinamicamente i nodi figli. Allora perché non ampliare questo treeview aggiungendo, grazie alla moda del momento - Ajax - questa funzionalità?

Non ho mai nascosto che l'implementazione per me meglio fatta, per semplicità di utilizzo e di installazione, è quella creata da Matteo Casati che si trova a questo link. Grazie alle sue funzioni Javascript è possibile richiamare dei web services per ottenere le informazioni desiderate per l'aggiornamento della pagina senza il caricamento completo della stessa. Mi fermo qui, di Ajax se n'è parlato fin troppo in questo periodo, un'ulteriore spiegazione di cosa sia è inutile.

Uniamo dunque le due cose per ottenere quanto voluto. Dal link a fondo blog è presente un link dove scaricare l'esempio scritto (esempio che è possibile scaricare solo dopo all'autenticazione a questo sito). L'esempio è composto da una sola pagina asp.net che visualizza in due zone della pagina, i due treeview: il primo è così come è spiegato sul sito Constile, il secondo è con l'aggiunta del caricamento dinamico dei nodi figlio:

I due treeview nell'esempio

A prima vista non c'è differenza, ma se clicchiamo su un altro nodo vedremo l'effetto voluto del caricamento dei dati con una chiamata al web services:

Immagine del treeview caricato dinamicamente

Voluto perché nella chiamata del web services è presente il comando per rallentare la risposta:

System.Threading.Thread.Sleep(300);

Per simulare una situazione reale ho creato un database Access contenente una tabella con tre campi:

  • id
  • voce
  • padre

La voce "padre" è relazionata con "id", in questo modo posso inserire tutte le voci dei nodi all'interno di un'unica tabella in questo modo:

Ogni singolo record avrà come padre il record con "id" uguale a "padre". I record con valore zero, non hanno padri.

Creata la pagina html includendo lo script per richiamare i web services, ho scritto il mio codice per richiamare il tutto:

<script type="text/javascript">
<!--
// Eseguito immediatamente
var url='<%=Url%>';

// Funzioni per l'albero
function mmenu(mID) {
 var menu = document.getElementById(mID);
 var display = menu.style.display;
 menu.style.display = (display == "block") ? "none" : "block";
 menu.parentNode.style.listStyleImage = (display == "block") ? "url(images/cartellachiusa.gif)" : "url(images/cartellaaperta.gif)";
}

window.onload = function() {
 // Precarica immagini
 if (document.images)
 {
  var immagine1=new Image;
  immagine1.src='images/cartellaaperta.gif';
  var immagine2=new Image;
  immagine2.src='images/cartellachiusa.gif';
  var immagine3=new Image;
  immagine3.src='images/doc.gif';
 }
 var uls = document.getElementsByTagName("ul");
 for (i=0;i<uls.length;i++) {
  if(uls[i].className=="submenu")uls[i].style.display = "none";
 
 CreaTree('0');
 }
}

var attuale='';
function CreaTree(oggetto)
{
 attuale=oggetto;
 var espandere=window.document.getElementById(attuale);
 if (espandere.innerHTML=='')
 {
  // Non c'è ancora nulla, carico...
  espandere.innerHTML="Caricamento...";
  mmenu(attuale);
  var pl = new SOAPClientParameters();
     pl.add("livello", oggetto);
  SOAPClient.invoke(url, "CreaAlbero", pl, true, CreaTree_Back);
 }
 else
  mmenu(attuale);
}
function CreaTree_Back(r)
{
 var espandere=window.document.getElementById(attuale);
    if (espandere!=null)
  espandere.innerHTML=r;
}
function Risultato(v)
{
 alert(v);
}
//-->
</script>

L'unica funzione non modifica è "mmenu". Alcune modifiche alla funzione caricata all'onload di pagina per il precaricamento delle immagini e per la creazione della base della treeview dinamica: CreaTree('0'). Esso fa riferimento al tag <ul id='0'></ul> presente nel codice html della pagina. "CreaTree" richiama il web sercices "CreaAlbero", che non fa altro che richiedere i record aventi padre il codice passato:

  [WebMethod]
  public string CreaAlbero(string livello)
  {
   System.Threading.Thread.Sleep(300);
   DataTable dt;
   if (livello.Length==1)
    dt=Figli(0);
   else
    dt=Figli(Convert.ToInt32(livello.Substring(livello.LastIndexOf("-")+1)));
   StringBuilder sb=new StringBuilder();
   foreach (DataRow dr in dt.Rows)
   {
    // Controllo che abbia figli
    if (dr["numero_figli"].ToString()=="0")
    {
     // Non ha figli
     sb.Append("<li><a href='#' onclick='Risultato(\"");
     sb.Append(dr["id"]);
     sb.Append("\")'>");
     sb.Append(dr["voce"]);
     sb.Append("</li>\r\n");
    }
    else
    {
     // Ha figli
     sb.Append("<li class='menu'>\r\n");
     sb.Append("<a href=\"javascript:CreaTree('");
     sb.Append(livello);
     sb.Append("-");
     sb.Append(dr["id"]);
     sb.Append("')\">");
     sb.Append(dr["voce"]);
     sb.Append("</a>\r\n");
     sb.Append("<ul class=\"submenu\" id='");
     sb.Append(livello);
     sb.Append("-");
     sb.Append(dr["id"]);
     sb.Append("' style=\"display = 'none';\"></ul>");
     sb.Append("</li>\r\n");
    }
   }
   return sb.ToString();
  }

Questa funzione ritorna il codice HTML puro con i fili del nodo passato, diversificando la creazione nel caso questi abbiamo loro stessi dei figli.

Non proseguo oltre con le spiegazioni. Sono stanco, ed ho voglia di panettone. Il tutto è così semplice che è sufficiente una lettura per capire il funzionamento di tutto... L'esempio da provare e esaminare è possibile scaricarlo da questo link.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Nella stessa categoria
I più letti del mese