Newsgroup: it.comp.lang.javascript
Titolo: generalizzare una funzione

come faccio a generalizzare la funzione:
 
$('#hidden-1').hide();
$('a#slidetoggle1').click(function() {
  $('#hidden-1').slideToggle(400);
  return false;
});
 
ora ho 5 di queste div a scomparsa:
id="hidden-1"
id="hidden-2"
id="hidden-3"
id="hidden-4"
id="hidden-5"
 
ad ognuna è associato un link di azione per abbassarla o chiuderla:
<a href="#" class="icona aggiungi" id="slidetoggle1"></a>
<a href="#" class="icona aggiungi" id="slidetoggle2"></a>
<a href="#" class="icona aggiungi" id="slidetoggle3"></a>
<a href="#" class="icona aggiungi" id="slidetoggle4"></a>
<a href="#" class="icona aggiungi" id="slidetoggle5"></a>
 
Ora ne ho 5 di funzioni, una per ogni div, vorrei farne una
sola generalizzata. Ho provato un sacco di varianti ma non riesco.
grazie
 
-- ciao!
 
...nixs.................................................................
nixs.lucchetto.@lagirandola.it
 
togli la ".SERRATURA." per scrivermi
........................................................................
L'uomo non smette di giocare perché invecchia,
ma invecchia perché smette di giocare.
(George Bernard Shaw) 
 

 <a href="#" class="icona aggiungi" id="slidetoggle5"></a>
 
Quando hai elementi che si ripeto in questo modo, e soprattutto se ti
trovi costretto ad aggiungere un incrementale alla fine dell'ID,
solitamente è indice che dell'ID non hai proprio bisogno.
 
Quindi prima della funzione Javascript, devi generalizzare l'HTML.
 
Inoltre, che relazione c'è tra questi link e i DIV a scomparsa? Intendo
dire, nella struttura del documento dove si trovano rispettivamente?
 
Semplificando il codice HTML (che già è una buona cosa di per sé)
otterrai come effetto di semplificare anche il codice JS (altra buona cosa).

 <a href="#" class="icona aggiungi" id="slidetoggle5"></a>
 
$('div[id^=hidden]').hide();
$('a.icona.aggiungi').click(function() {
  $('#hidden-'+$(this).data('id')).slideToggle(400);
  return false;
});
 
ora ho 5 di queste div a scomparsa:
id="hidden-1"
id="hidden-2"
id="hidden-3"
id="hidden-4"
id="hidden-5"
 
ad ognuna è associato un link di azione per abbassarla o chiuderla:
<a href="#" class="icona aggiungi" id="slidetoggle1" data-id='1'></a>
<a href="#" class="icona aggiungi" id="slidetoggle2" data-id='2'></a>
<a href="#" class="icona aggiungi" id="slidetoggle3" data-id='3'></a>
<a href="#" class="icona aggiungi" id="slidetoggle4" data-id='4'></a>
<a href="#" class="icona aggiungi" id="slidetoggle5" data-id='5'></a>
 
 
Saluti. Carlo.

dire, nella struttura del documento dove si trovano rispettivamente?
 
<form>
 
<div>
    <div>
        <a href="#" class="icona aggiungi" id="slidetoggle1"></a>
    </div>
    <div id="hidden-1">
        div contenitore nascosto con alcuni campi input con id univoco
    </div>
</div>
 
<div>
    <div>
        <a href="#" class="icona aggiungi" id="slidetoggle2"></a>
    </div>
    <div id="hidden-2">
        div contenitore nascosto con alcuni campi input e radio con altri id 
univoci
    </div>
</div>
 
ecc.
 
</form>


});
 
ok, perfetto.
 
credo di aver semplificato ulteriormente in questo modo
 
$('div[id^=hidden]').hide();
    $('a.icona.aggiungi').click(function() {
    $('#hidden-'+$(this).attr('id')).slideToggle(400);
    return false;
});
 
con i link:
<a href="#" class="icona aggiungi" id="1"></a>
ecc.


 </div>
 
Non vedo la necessità del `<div/>` che contiene il tag `<a/>`. Come mai
l'hai messo?
 
Supponendo che tu non ne abbia bisogno, io semplificherei in:
 
    <div class="box">
        <a href="#" class="icona aggiungi"></a>
        <div>
            div contenitore nascosto con alcuni campi input
            con id univoco
        </div>
    </div>
 
Ho aggiunto una classe "box" perché non ho idea di cosa rappresenti
questo agglomerato di elementi per te. Dagli una classe più sensata.
 
Inoltre, sempre per la stessa ragione esposta nel post precedente, i
campi input non dovrebbero avere affatto ID univoco; dato che questo
blocco è ripetuto "n" volte.
 
A livello di CSS avrai qualcosa tipo, suppongo:
 
    .box > div {
        display: none
    }
 
E in jquery:
 
    $(".box > a").click(function() {
        $(this).next().slideToggle(400);
        return false;
    })

blocco è ripetuto "n" volte.
 
beh... mi hai fatto na' capa tanta per gli id univoci, giorni fa, e ora mi 
dici
il contrario? :-)))
 
Oltretutto, è vero che i blocchi si ripetono, ma non sono identici.
Uno contiene 4 input text, un altro 6 input text e 6 radio, il terzo
contiene 8 input text e 8 select, ecc.


 Oltretutto, è vero che i blocchi si ripetono, ma non sono identici.
 
Questo è irrilevante, dipende da cosa essi rappresentano. Ti faccio un
esempio concreto. Tu potresti avere:
 
    <div id="panel-1">
        <h1 id="title-panel-1">Settings</h1>
        <div id="content-panel-1">
            <table>...</table>
            <div>...</div>
            <!-- etc.. qualsiasi cosa ti venga in mente -->
        </div>
        <div id="buttons-panel-1>
            <button id="buttons-ok-panel-1">Save</button>
            <button id="buttons-ok-panel-1">Cancel</button>
        </div>
    </div>
 
    <div id="panel-2">
        <h1 id="title-panel-2">Options</h1>
        <div id="content-panel-2">
            <a href="#">foo</a>
            <!-- etc.. qualsiasi cosa ti venga in mente -->
        </div>
        <div id="buttons-panel-2">
            <button id="buttons-ok-panel-2">Cancel</button>
        </div>
    </div>
 
Il contenuto è diverso, ma quello che rappresentano è la stessa cosa. Il
fatto che tu stia usando un incrementale, è indice che hai sbagliato
approccio. Un modo corretto di avere questo codice HTML è:
 
    <div class="panel">
        <h1>Settings</h1>
        <div>
            <a href="#">foo</a>
            <div>...</div>
            <!-- etc.. qualsiasi cosa ti venga in mente -->
        </div>
        <fieldset>
            <button class="button-save">Save</button>
            <button class="button-cancel">Cancel</button>
        </fieldset>
    </div>
 
    <div class="panel">
        <h1>Options</h1>
        <div>
            <a href="#">foo</a>
            <!-- etc.. qualsiasi cosa ti venga in mente -->
        </div>
        <fieldset>
            <button class="button-cancel">Cancel</button>
        </fieldset>
    </div>
 
In questo caso specifico, io userei anche un ID per identificare i
singoli pannelli (perché sono *specifici*), ma in altri casi non lo farei:
 
        <div class="panel" id="settings">
            <!-- il resto rimane invariato -->
        </div>
 
        <div class="panel" id="options">
            <!-- il resto rimane invariato -->
        </div>
 

             <button id="buttons-ok-panel-1">Cancel</button>
 
Ovviamente questo sarebbe stato "buttons-cancel-panel-1".

approccio. Un modo corretto di avere questo codice HTML è:
 
l'incrementale serve a decidere quale pannello si deve aprire, altrimenti
come lo identifichi?
La funzione:
$('div[id^=hidden]').hide();
    $('a.icona.aggiungi').click(function() {
    $('#hidden-'+$(this).attr('id')).slideToggle(400);
    return false;
});
 
vuole un id preciso del DIV che deve aprire (hidden-1, hidden-2, ecc.)
 
C'è qualcosa che forse mi sfugge?


 -- ciao!
 
P.S.
La tua signature non rispetta la giusta sintassi quindi i newsreader non
la trattano come tale ricopiandola ogni volta (e quindi va eliminata
manualmente ogni volta :) ). La signature è separata dal contenuto del
messaggio da una riga composta solo due trattini, seguiti da uno spazio
(e poi un a capo, e il corpo della firma).

La tua signature non rispetta la giusta sintassi quindi i newsreader non
 
Proviamo ora:


<span class="symbol"> = </span></td></td>
 
qui c'è un errore di chiusura del td che ho già corretto


no, niente da fare, la funzione... non funziona.
Si aprono tutti insieme. Bah!


*NON* può iniziare con un numero:
 
hai ragione, lo sapevo ma non me ne sono ricordato, ma non è questo il 
problema
perchè l'id in titolo non è utilizzato, è un refuso di una prova, lo posso 
eliminare.


Ho risolto!
 
La funzione è diventata:
$('.panel').hide();
$('a.icona.aggiungi').click(function() {
    $('#' + 
this.id
 + '_panel').toggle(400);
  return false;
});
 
 
dando al link per l'azione l'id="toggle_1" e così via,
e ad ogni div da mostrare/chiudere l'id="toggle_1_panel" e così via.
 
In pratica somma l'id del link cliccato con "_panel" per identificare l'id 
del pannello da aprire.


 Proviamo ora:
 
No, ma ho visto che nel nuovo thread hai corretto ;)

 Invece dei tag <table>, <
 
Invece dei tag <table>, <tr>, <td>, etc; tu hai usato i tag <div>, ma
hai fatto la stessa cosa: hai scritto codice non semantico, e
strutturando i div a mo' di righe/colonne e usando classi specifiche ne
hai definito il layout dello stesso.
Ergo, se tanto vuoi commettere lo stesso errore, tanto vale che ti
appoggi alle tabelle, che se non altro ti sono più semplici.
 
Ovviamente la cosa migliore sarebbe evitare di usare sia i div che le
tabelle per tale scopo.

identificasse un "pannello", cosa che qui non hai.
 
Per esempio???
 
ma veniamo alla nostra funzione.
L'ultima versione è questa:
$('.panel').hide();
$('a.icona.aggiungi').click(function() {
$('#' + 
this.id
 + '_panel').toggle(400);
return false;
});
 
So già che mi farai na capa tanta per il fatto che è legata
agli id, ma non so fare di meglio.
 
A proposito di id, hai più volte ribadito questo concetto:
"O dai un ID univoco (no incrementali) perché devi riferirti ad esso in
modo specifico, oppure non hai bisogno di un ID".
Che non ho ben capito.
Un id incrementale è univoco, nel senso che sta SOLO lì, perchè
non va bene? "panel_1" è diverso e univoco da "panel_2", perchè
non usarli? In fondo sono descrittivi (mi dicono su quale pannello mi trovo)
e in più, e questo è il motivo che diventa tentazione, è un modo per
riferirsi all'interno dell'insieme facendo variare l'incrementale per
individuare ricorsivamente ognuno, cosa impossibile da fare usando id
come "panel_black", "panel_white" ecc.


> $('a.icona.aggiungi').click(function() {
 
tra icona e aggiungi c'è un puntino di troppo 
 
 

 tra icona e aggiungi c'è un puntino di troppo 
 
No, va bene. È un selettore CSS che dice "prendi tutti gli elementi
aventi tag `a` e classe `icona` *e* `aggiungi`".
 
In pratica ti recupererebbe:
 
    <a class="icona aggiungi"></a>
    <a class="icona aggiungi foo"></a>
 
Ma non:
 
    <a class="icona"></a>
    <a class="aggiungi"></a>
    <a class="icona foo"></a>
    <a class="aggiungi bar"></a>

 come "panel_black", "panel_white" ecc.
 
Di nuovo, stai mischiando le due cose. "panel-black" e "panel-white"
sono ID univoci, che vengono applicati quando hai bisogno di specificità
e non di generalità. Variare l'incrementale per accedere ricorsivamente
a ognuno dei panelli partendo da un panello, manca di specificità: è
un'azione generica, che deve poter essere eseguita su qualsiasi
pannello, senza bisogno di sapere quale panello sia (che sia
"panel-black" o "panel-white" poco importa: deve funzionare in quanto
sono entrambi pannelli e quella è un'operazione generica sui pannelli).
 
Quindi, come ti ho già spiegato prima, un'azione generica non ha bisogno
di un ID puoi benissimo farne a meno. Nel caso del codice di cui prima,
se ho:
 
    <div id="my-closest-friends">
        <div class="friend"></div>
        <div class="friend"></div>
        <div class="friend"></div>
    </div>
 
Posso ottenere tranquillamente la lista di amici:
 
    $("#my-closest-friends .friend")
 
Ciclarla:
 
    $("#my-closest-friends .friend").each(function() { ... })
 
E, supponendo di avere il riferimento di uno qualunque di essi, posso
accedere al successivo:
 
    // restituisce un oggetto jquery
    var nextFriend = friend.next()
 
    if (nextFriend.length) {
        // fai qualcosa con il successivo elemento
    } else {
        // sei arrivato alla fine della lista, decidi cosa fare
    }
 
Se avessi il riferimento di un qualunque elemento all'interno del div,
potrei sempre fare:
 
    var friend = element.closest(".friend")
 
E poi lo stesso codice di cui sopra. Oppure, se so che è il nodo parent,
potrei sempre fare:
 
    var friend = element.parent()
 
In questi casi il codice HTML è strutturato in modo tale che non si
possa avere tag diversi da <div> con classe "amico" nel <div>
contenitore. Personalmente trovo avere questo genere di "contratti"
molto utile in questioni di design. Se per qualche motivo non puoi farlo
o non sei sicuro, puoi sempre passare a `next` la classe a cui vuoi
riferirti.
 
Per concludere: nota che in caso di HTML semantico, ovviamente in base
al contenuto stesso, in questo specifico esempio sarebbe stato più
corretto avere:
 
     <ul id="my-closest-friends">
        <li class="friend"></li>
        <li class="friend"></li>
        <li class="friend"></li>
    </ul>
 
Tramite CSS avrei poi eliminato lo stile della lista, e visualizzato
questi elementi come più mi aggradava. Ad esempio, in HTML menù a
cascata, menu tab o comunque orizzontali, vengono fatti in questo modo:
usando tag <ul> con elementi <li> che contengono tag <a>, che poi
vengono spalmati in orizzontale tramite CSS, e modificati in modo
appropriato. Così, se anche lo stile viene rimosso, tale menù mantiene
comunque la sua "consistenza" (ovvero una lista di link, visibilmente
raggruppati, con magari un'intestazione).

sono entrambi pannelli e quella è un'operazione generica sui pannelli).
 
Ora ho capito il senso.
Una funzione come quella che serve a me deve ragionare in stile:
"fai questo sul prossimo (o sul precedente, o sul corrente) elemento che 
trovi a partire dal punto dove ho cliccato"
e non
"fai questo sull'elemento con indice 3"
 
In modo che se cambio disposizione o numero di oggetti non devo preoccuparmi
di rinumerare, aumentare, diminuire gli indici.
 
Comunque, alla fine credo di avercela fatta.
Ho perso 4 ore sulla funzione per accorgermi che con gli strumenti che JQ 
mette
a disposizione per il traversing non potevo (con le mie capacità) ottenere 
quello
che cercavo, perche la struttura era sbagliata e quindi nè con next, nè con 
altri funzionava.
Allora ho cambiato l'oggetto del click, invece che sul link, che si trova 
all'interno
di <p>, l'ho settato proprio sul <p>, cioè su tutta la barra che fa da 
header al pannello
e che è ADIACENTE al pannello (il fieldset), e ora funziona:
 
$('.panel').hide();
$('.panel-caption').click(function() {
          $(this).next('.panel').slideToggle(400);
          return false;
});
 
Sono stato un bravo apprendista? :-))


c'è qualcosa che non va.
 
Scusate l'intromissione....
si può fare un esempio brutale di codice semantico e codice non
semantico?
e un esempio, sempre brutale, di codice HTML strutturato in base al
layout e di codice HTML strutturato in base al contenuto.
 
ho provato a togliere i css dalla pagina iniziale di yahoo.
questa è un porzione del risultato.
http://i49.tinypic.com/kb3z9x.png
 
è una pagina ben strutturata?
 
 
saluti
 
 
 

 Sono stato un bravo apprendista? :-))
 
Stai andando bene. :)
 

 è una pagina ben strutturata?
 
Solitamente siti come Yahoo e Google non si preoccupano troppo di
"strutturare bene" le pagine, ma hanno altre priorità. Google ad esempio
ha sempre fallito la validazione del codice HTML.
 
Premesso questo, dubito quindi che la homepage di Yahoo sia ben
strutturata in toto, ma nello screenshot che hai fornito puoi già vedere
alcune delle cose di cui abbiamo parlato. Ad esempio, la toolbar è un
fieldset con una lista che, tramite CSS, è spalmata in orizzontale. Non
sono giusto degli <span> o una serie di link <a> sparati a caso e non
raggruppati.
 
Concludo con questo aneddoto:
Una volta lessi che per disegnare dei personaggi di fumetti che siano
credibili nonostante abbiano un'anatomia sballata o esagerata, bisogna
sapere come disegnare l'anatomia correttamente. Solo allora puoi
prenderti il lusso di non disegnarla corretta in quanto la stai piegando
consapevolmente alle tue esigenze, e non la stai disegnando "male" per
ignoranza.
 
Lo stesso credo si possa applicare a diverse discipline, come anche la
scrittura, e nel nostro caso la programmazione.

Stai andando bene. :)
 
e meno male! :-))
Valgono molto più queste discussioni che un intero manuale!
 
Se hai un po' di tempo mi aiuti anche per l'altra questione che
mi manca per finire?
E' il TD "a spasso per il DOM: reperire i campi giusti" la prima
discussione con Andrea Scartabelli. Sono arrivato ad un pelo
dalla soluzione, ma Andrea non mi ha più risposto.


        <div class="panel">...</div>
 
ormai i miei "panel" sono diventati CULT! :-))))))))



grazie per le preziosi informazioni
simo

 dalla soluzione, ma Andrea non mi ha più risposto.
 
Provo a buttargli un'occhiata, allora.

Provo a buttargli un'occhiata, allora.
 
Attendo fiducioso :-)


 vari e salti.
 
Allora vuol dire che la tua struttura non era quella descritta, oppure
che l'elemento di partenza non era quello che immaginavi. Se
`p.next().show()` ti da il risultato che ti aspetti, mentre
`a.parent().next.show()` no; vuol dire che `p !== a.parent()`, molto
semplicemente. Quindi, o il tuo tag di partenza non era il tag A che ti
aspettavi, oppure A non era figlio diretto di P.