Visualizzazione dei risultati da 1 a 10 su 10
  1. #1

    Creazione dinamica menu a piu livelli

    Salve,

    diciamo che debba implementare questo menu:

    codice:
    Sorgente 1
        |- figlio 1
              |- sotto figlio 1
                      |- sotto-sotto figlio 1
                             |- etc etc
    Sorgente 2
        |- figlio 1
             |- sotto figlio 1
                 etc etc
    Sorgente 3
         etc etc
    .
    .
    .Sorgnte N
    la tabella è strutturata in questo modo:

    codice:
    id - idgenitore - voce - link
    con l'accortezza che se la voce è SORGENTE allora id=idgenitore


    mi dite come cavolo lo stampo questo menu??? la funzione che ho fatto io non è che mi faccia impazzire, troppi accessi al db...voi avete qualche idea/cosa già pronta?


  2. #2
    Ciao Santino
    Io ho avuto lo stesso "problema" qualche tempo fà , ovvero anche io avevo l'esigenza di creare 1 menu "infinito" ...con quello che so io di ASP sono arrivato a sviluppare 1 menu dove per ogno sottovoce apro la tabella (che è strutturata come la tua), per non avere tutti i cicli annidati qualcuno mi aveva detto di usare gli array...ma non ci sono riuscito...

    per cui, ti passo quello che ho fatto io (anche se ho capito e visto che tu hai + esperinza di me in ASP)...
    <%
    Dim IDMenu1
    set Menu = Server.CreateObject("ADODB.Recordset")
    sql = "select * from Menu where IDPadre =" & 0
    Menu.ActiveConnection = cn
    Menu.Open sql, cn
    %>

    <div id="menu">

    <h2>titolo menu</h2>

    <%
    Do while not Menu.EOF
    IDMenu1 = Menu("IDMenu")
    %>
    <ul>[*]" class="x"><%=Menu("voce")%>

    <%
    Dim IDMenu2
    set Menu2 = Server.CreateObject("ADODB.Recordset")
    sql = "select * from Menu where IDPadre =" & IDMenu1
    Menu2.ActiveConnection = cn
    Menu2.Open sql, cn
    %>
    <%if not Menu2.EOF then %>
    <ul>
    <%
    Do while not Menu2.EOF
    IDMenu2 = Menu2("IDMenu")
    %>[*]" class="x"><%=Menu2("voce")%>



    <%
    Dim IDMenu3
    set Menu3 = Server.CreateObject("ADODB.Recordset")
    sql = "select * from Menu where IDPadre =" & IDMenu2
    Menu3.ActiveConnection = cn
    Menu3.Open sql, cn
    %>
    <%if not Menu3.EOF then %>
    <ul>
    <%do while not Menu3.EOF%>[*]" class="x"><%=Menu3("voce")%>
    <%
    Menu3.movenext
    loop
    %>[/list]
    <%end if%>

    <%
    Menu2.movenext
    loop
    %>[/list]
    <%end if%>

    [/list]
    <%
    menu.movenext
    loop
    menu3.close()
    Set menu3 = nothing
    menu2.close()
    Set menu2 = nothing
    menu.close()
    Set menu = nothing
    %>

    </div>
    <%
    Pagina.close()
    Set Pagina = nothing
    %>

    --------------------------------------------

    questo il foglio di stile

    #menu{
    background:#000000;
    padding:1px;
    z-index:2;
    width:170px;
    }

    #menu a, #menu h2{
    display:block;
    font:bold 11px/16px verdana;
    border-top:1px solid #ccc;
    border-left:1px solid #bbb;
    border-right:1px solid #888;
    border-bottom:1px solid #555;
    white-space:nowrap;
    text-indent:2px;
    width:170px;
    }

    #menu a{
    background:#000000;
    text-decoration:none;
    }

    #menu a, #menu a:visited{
    color:#494c59;
    }

    #menu a:hover{
    color:#000;
    background:#fff;
    }

    #menu a:active{
    color:#060;
    background:#e2e2ec;
    }

    #menu h2{;
    color:#fff;
    background:#369;
    text-transform:uppercase;
    margin:0;
    padding:0;
    width:170px;
    }

    #menu li{
    list-style-type:none;
    }

    #menu ul li{
    position:relative;
    font:bold 10px/16px verdana;
    }

    #menu li ul{
    position:absolute;
    top:0;
    left:170px;
    display:none;
    }

    /* Fix IE. Hide from IE Mac \*/
    * html #menu ul li{float:left;height:1%;}
    * html #menu ul li a{height:1%;}
    /* End */

    div#menu ul, #menu ul ul, div#menu ul ul ul{
    margin:0;
    padding:0;
    list-style-image:none;
    width:170px;
    }

    div#menu ul ul, div#menu ul ul ul, div#menu ul li:hover ul ul, div#menu ul li:hover ul ul ul{
    display:none;
    }

    div#menu ul li:hover ul, div#menu ul ul li:hover ul, div#menu ul ul ul li:hover ul{
    display:block;
    }

    /* Styling for Expand */

    #menu a.x, #menu a.x:visited{
    font-weight:bold;
    text-indent:2px;
    color:#494c59;
    background:#edeef6;
    }

    #menu a.x:hover{
    color:#fff;
    background:#000000;
    }

    #menu a.x:active{
    color:#060;
    background:#e2e2ec;
    }


    -------------------------------------------------------

    se riesci a scrivere meno codice fammelo sapere..

  3. #3
    sai che pensavo? per fare meno accessi al db bisogna aggiungere una flag per dirgli "guarda, il figlio che stai leggendo è a sua volta padre di altri" in maniera che il controllo non lo fai per tutti i record ma solo per uno...

    mo ci penso

  4. #4
    Per 1 menu a 4 livelli....

    Se ho bene capito una cosa tipo
    step 1 pesco tutti i pardi che non sono figli
    (per cui il livello 1)

    step 2
    "guarda, il figlio che stai leggendo è a sua volta padre di altri"
    pesco i figli che sono anche padri
    nel mentre pesco l'ID che servirà per il figlio
    (secondo livello)

    step 3 con l'ID pesco i relativi figli
    "guarda, il figlio che stai leggendo è a sua volta padre di altri"
    pesco i figli che sono anche padri
    nel mentre pesco l'ID che servirà per il figlio
    (terzo livello)

    step 4 con l'ID pesco i relativi figli
    pesco i figli
    (quarto livello livello)

    ...se ho ben capito quell oche intendi...non vedo differenza di accessi al DB...oppure non ho capito cosa intendi per Flag


    .... ma se invece si imposta tutto con degli array? ...così da creare davvero infiniti sottolivelli?


    Tipo
    Creao una variabile chiamata "quantisottomenu"


    Apro la tabella 1 volta sola, pesco tutti gli ID, IDPadre, voci

    Creo 1 ciclo = quantisottomenu
    Da quì inizio a creare gli array facendo dei confronti con gli ID e gli IDPadri

    quantisottomenu, cicla

    ...ora ...io non ho mai usato gli array ...mo mi documento e provo...credo che a logica sia giusta...ma non so se è fattibile mettere in atto quella logica degli array :master:

  5. #5
    Con questo software per creare menù in DHTML hai la possibilità di fare una cosa del genere, quindi pescare dal db le voci che poi andranno nel mnù: DHTMLMenu.

    Provalo.

  6. #6
    puff puff che faticaccia che ho fatto


    codice:
    <div style="width:230px; overflow:auto;  position:relative; top:0px; left:0px;">
    
    <%
    dim dMenu
    dim toStamp 'conterrà il menu
    
    oConn ""
    oRs "rs","select id,idgenitore,voce,link,ordine,flag from cms_menu order by idgenitore asc,flag asc,ordine asc",1,1
    
    conta=1
    set dMenu=server.CreateObject("Scripting.Dictionary")
    while not rs.eof
    
    if clng(rs(0))=clng(rs(1)) then
    redim preserve testeSerie(conta)
    testeSerie(conta-1)=rs(0)
    conta=conta+1
    end if
    
    idchiave=clng(rs(0))
    
    stringa=rs(0) & "|" & rs(1) & "|" & rs(2) & "|" & rs(3) & "|" & rs(4) & "|" & rs(5)
    
    dMenu.Add idchiave,stringa
    idchiave="": stringa=""
    
    rs.movenext
    wend
    
    cRs rs: cConn
    
    
    sub creaMenu(categoria)
    
    stampaVoce categoria,1
    
    end sub
    
    sub stampaVoce(categoria,tipo)
    dim arrT
    arrT=split(dMenu.item(categoria),"|")
    if ubound(arrT)>0 then
    select case tipo
    case 1 'è genitore
    toStamp=toStamp & vbcrlf & "<div style=""" & stileGenitore & """>"
    toStamp=toStamp & vbcrlf & "<div style=""float:left; width:10px"">menu" & categoria & "');"">" target="_blank"></div><div style=""position:relative;left:3px;top:-2px""><a href=""" & arrT(3) & """>" & toLow(arrT(2)) & "</div></div>" & vbcrlf
    
    if hasFigli(categoria) then stampaFigli categoria
    
    case else 'è figlio
    toStamp=toStamp & vbcrlf & "<div style=""" & stileFiglio & """>" & toLow(arrT(2)) & "</div>" & vbcrlf
    end select
    end if
    
    erase arrT
    end sub
    
    
    function hasFigli(categoria)
    dim chiavi,rit
    chiavi=dMenu.keys
    rit=false
    for each chiave in chiavi
    str=dMenu.item(chiave)
    
    pos1=instr(1,str,"|")
    pos2=instr(pos1+1,str,"|")
    
    if clng(left(str,pos1-1))<>clng(categoria) and clng(mid(str,pos1+1,(pos2-pos1)-1))=clng(categoria) then 'è il figlio
    rit=true
    end if
    
    
    next
    erase chiavi
    hasFigli=rit
    end function
    
    
    sub stampaFigli(categoria)
    dim chiavi
    chiavi=dMenu.Keys
    toStamp=toStamp & vbcrlf & "<div id=""menu" & categoria & """ style=""padding-left:20px;display:none"">"
    for each chiave in chiavi
    arrT=split(dMenu.item(chiave),"|")
    
    if clng(arrT(0))<>clng(categoria) and clng(arrT(1))=clng(categoria) then stampaVoce clng(arrT(0)),cint(arrT(5))
    
    next
    toStamp=toStamp & vbcrlf & "</div>"
    erase chiavi: erase arrT
    end sub
    
    
    '*************************
    'prendo la prima voce dell'array che abbia id=idgenitore e la stampo, e controllo che abbia figli e stampo a sua volta (ricorsivamente)
    'così via fino alle ennesima voce nell'array che abbia id=idgenitore
    
    
    '*************************
    'scorro tutte le teste di serie, per ogni testa di serie stampo il menu
    
    for f=0 to ubound(testeSerie)
    
    creaMenu testeSerie(f)
    
    next
    
    response.Write(toStamp)
    
    
    %>
    
    </div>

    un accesso al db=stampo tutto il menu

    legenda:

    -oConn,oRs, cConn,cRs sono funzioni per aprire/chiudere recordset/connessioni

    -gli elementi che avranno id=idgenitore saranno quelli visibili all'inizio (le root dell'albero)

    -flag=1, è un Genitore, flag=0 è un figlio (e quindi non perdo tempo a cercare se ha figli)

    -lo javascript se serve a qualcuno lo posto, altrimenti potete farlo da soli

    -testeSerie è un array che contiene tutti gli id dei record che hanno id=idgenitore



    se qualcuno ha un'idea migliore è ben accetta

  7. #7
    Funzione ricorsiva

    ho aggiunto alla tabella il campo 'ordine' di tipo intero per ordinare le varie voci di menu

    codice:
    'Funzione ricorsiva per generazione menu
    'il parametro strMenu è passato per referenza
    function menuAlbero(idgenitore,byref strMenu)
    
    	dim RsFigli,Rs1
    	set Rs1=Server.CreateObject ("ADODB.recordset")
    	set RsFigli=Server.CreateObject ("ADODB.recordset")
    		
    	'Query iniziale			
    	sSQL="SELECT distinct * "
    	sSQL=sSQL & " FROM wmenu"
    	sSQL=sSQL & " WHERE  idgenitore=" & idgenitore
    	sSQL=sSQL & " ORDER BY ordine"		
    
    	Rs1.Open sSQL,objConn,3,3
    	
    
    	if not Rs1.EOF then
    		do while not Rs1.EOF 
    			id=Rs1.Fields ("id")
    			idgenitore=Rs1.Fields ("idgenitore")
    			link=Rs1.Fields ("link")
    			voce=Rs1.Fields ("voce")
    			
    			'Controllo se la voce in questioj ha dei figli
    			sSQL="select count(*) as NumFigli from wmenu where idgenitore=" & id
    			RsFigli.Open sSQL,objConn,3,3
    			NumFigli=RsFigli.Fields ("NumFigli")
    			RsFigli.Close
    				
    			if NumFigli>0 then
    				'trovati dei figli
    				
    				'stampo la vce a video
    				strMenu=strMenu & "[*]"
    				strMenu=strMenu & "" & voce & ""
    				strMenu=strMenu & "<ul>"
    				'Richiamo la funzione passando come idgenitore l'id della voce di menu attuale
    				call menuAlbero(id,strMenu)			
    				strMenu=strMenu & "[/list]"
    				
    			else
    				'Nessun figlio trovato
    				strMenu=strMenu & "[*]"
    				strMenu=strMenu & "" & voce & ""
    				strMenu=strMenu & ""
    			end if
    			Rs1.MoveNext 
    		loop
    
    
    	end if
    	Rs1.Close
    	set Rs1=nothing
    	set RsFigli=nothing
    
    end function
    Per richiamarla

    codice:
    'Apri connessione
    
    strMenu=""
    'Chiamo la funzione 
    'il primo parametro è l'idgenitore che deve essere settato a zero per le voci di menu pricipale
    call menuAlbero(0,strMenu)
    Response.Write (strMenu)
    
    'Chiudi connessione

    ciao

  8. #8
    Mazza....scusate ...posso "prendere" il tutto ?

  9. #9
    il fatto è che io volevo evitare proprio questo:
    codice:
    'Controllo se la voce in questioj ha dei figli
    			sSQL="select count(*) as NumFigli from wmenu where idgenitore=" & id
    			RsFigli.Open sSQL,objConn,3,3
    			NumFigli=RsFigli.Fields ("NumFigli")
    			RsFigli.Close
    forse però si potrebbe spostare il tutto nell'sql...


    -AA- giù le mani :lol: :maLOL:

  10. #10
    Originariamente inviato da santino83
    il fatto è che io volevo evitare proprio questo:
    Perchè?


    Originariamente inviato da santino83
    forse però si potrebbe spostare il tutto nell'sql...
    Potresti modificare la prima query in questo modo

    codice:
    sSQL="SELECT distinct wmenu.* , "
    sSQL=sSQL & " (select count(*) as NumFigli from wmenu as tFigli where tFigli.idgenitore=wmenu.idgenitore) as numFigli"
    sSQL=sSQL & " FROM wmenu"
    sSQL=sSQL & " WHERE  idgenitore= " & idgenitore
    sSQL=sSQL & " ORDER BY ordine	"
    Come vedi con una query trovi anche il numero dei figli corrispondenti alla voce di menu.
    Attenzione a quello scritto in grassetto devi dare un alias alla tabella che usi per il calcolo dei figli altrimenti la condizione di uguaglianza non si verifica in modo corretto.


    ciao

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.