Newsgroup: it.comp.lang.javascript
Titolo: ciclo for... qualcosa non va...

Ciao ragazzi, premesso che non sono esperto di javascript, sto cercando 
di realizzare in una pagina del mio sito un effetto un po' complesso con 
l'aiuto di ajax e la libreria scriptaculous. In breve questo è quello 
che accade:
1- nella pagina c'è un link, cliccandoci sopra tramite ajax mi compare 
dinamicamente nella home page direttamente il contenuto del file ciao.php.
2- per fare apparire questo contenuto in maniera carina ci ho messo un 
effetto appear che fa apparire la scritta e dopo tot secondi la fa 
scomparire.
3- il mio fine è far comparire 5 scritte diverse con lo stesso effetto 
compare-scompare una dopo l'altra... e per ottenere ciò ho realizzato il 
seguente miniscript di prova:
var i=0;
var w=0;
for (i=0;i<=5;i++)
{
w=w+4;
Effect.Appear('ultime', {duration: 1, from:1, to:0, delay: w});
document.getElementById('ultime').innerHTML=i;
w=w+4;
Effect.Appear('ultime', {duration: 1, from:0, to:1, delay: w});
}
ma... stranamente il ciclo for non funge come mi aspettavo. Il 
document.getelementByID dovrebbe stampare a ogni apparire-scomparire 
delle scritte un valore diverso ma non lo fa! Stampa direttamente 
l'ultimo valore, come se il for avesse raggiunto già la fine del ciclo 
mentre è ancora in esecuzione!
Per essere più chiaro come potete vedere nel codice di sopra, ho 
associato a innerHTML il contenuto della variabile 'i', ma purtroppo mi 
appare per ogni lampeggio lo stesso valore che è l'ultimo, cioè 5!
Solo quello... ma non dovrebbe apparire al primo lampeggio 1... poi al 
secondo lampeggio 2... poi 3... ecc.???
Come mai? Che ne pensate?
Che c'entri ajax?
Per bypassare il problema del javascript contenuto in response di ajax 
che come saprete non viene di regola eseguito, ho incorporato come 
stratagemma tutto il codice in questo modo nel file ciao.php:
<img src="imgs/bannhome.jpg" border="0" onload="javascript:
var i=0;
var w=0;
for (i=0;i<=50;i++)
{
w=w+4;
Effect.Appear('ultime', {duration: 1, from:1, to:0, delay: w});
document.getElementById('ultime').innerHTML=w;
w=w+4;
Effect.Appear('ultime', {duration: 1, from:0, to:1, delay: w});
}
">
<div height="25px" id="ultime">
</div>
Ciao a tutti e grazie. Max

 mentre è ancora in esecuzione!
Esatto. E' un comportamento normale, non solo di javascript e/o della 
programmazione internet, ma di qualsiasi linguaggio di programmazione: 
devi dare il tempo alla pagina di aggiornare il layout ... (in molti 
linguaggi esistono comandi tipo DoEvents() per farlo, in ambiente 
internet non esiste).
Dopo ogni ciclo, quindi, devi uscire dalla function e rieseguire lo step 
successivo dopo tot millisecondi.
 Vedi 
https://developer.mozilla.org/en/DOM/window.setTimeout
Un ciclo for diventerebbe quindi:
 function cicla(i) {
	if(i>=5)
		return; //fine del ciclo
	document......//visualizzi il tuo dato
	setTimeout("cicla("+(++i)+")",1000);
 }
Da eseguire p.e. onload="cicla(0)"

 mentre � ancora in esecuzione!
Il tuo errore � pensare che il ciclo for sia ancora in esecuzione. � ovvio
che, se il valore che appare � l'ultimo, il ciclo for si � concluso.
Quello che � in azione, invece, � l'effetto di Scriptaculous, che non si
completa *durante* l'esecuzione del tuo codice, ma in fasi successive con
eventi scatenati tramite setTimeout o setTimer. Se vuoi eseguire delle
azioni quando l'esecuzione del singolo effetto �  terminata, devi
agganciare il tuo codice a qualche 'callback' prevista da Scriptaculous.
Non conosco la libreria in questione, ma basta una rapida ricerca per
trovare:
 
http://madrobby.github.com/scriptaculous/core-effects/
C'� una sezione 'callback'. Direi che dovresti usare 'afterFinish'.
Max

 Da eseguire p.e. onload="cicla(0)"
Grazie per la risposta, dunque ho trasformato il codice in questo modo:
<img src="imgs/bannhome.jpg" border="0" onload="
var i=0;
var w=0;
	function scrollevnws(i)
	{
	if (i>=5){
	return;
	}
	w=w+4;
	Effect.Appear('ultime', {duration: 1, from:1, to:0, delay: w});
	document.getElementById('ultime').innerHTML=i;
	w=w+4;
	Effect.Appear('ultime', {duration: 1, from:0, to:1, delay: w});
	setTimeout('scrollevnws('+(++i)+')',5000);
	}
scrollevnws(0);
">
ma non va ugualmente, cioè il valore di 'i' resta 0 a ogni lampeggiare. 
Che ne pensi?
Ancora grazie.
Max


ok, chiaro. Avevo raggirato l'inserimento di un callback diretto basando 
l'attivazione dei singoli effetti sul parametro delay con valore di 
tempo autoincrementato a ogni ciclo. E' una soluzione che almeno con 
questo effetto mi funziona ugualmente, ma seguirò il tuo consiglio in 
futuro. Thanks!

 	function scrollevnws(i)
no, per favore, togli questa function, da qua richiami la function, la 
function va messa nel tag script, non dentro l'attributo del tag.
A parte questo, interviene quell'Appear che non è più "javascript" ma uno 
dei 1000 pacchetti prefatti. Vedi quindi il consiglio di Max M. che ne sa 
qualcosa (io no).

 mentre è ancora in esecuzione!
E' normale, il codice relativo agli effetti non è bloccante, quindi nel 
tuo caso non aspetta di finire il primo Effect.Appear per passare al 
secondo Effect.Appear.
Sul sito di scriptaculous 
(
http://madrobby.github.com/scriptaculous/core-effects/
) è prevista una 
opzione callback chiamata afterFinish, quindi per attendere l'esecuzione 
devi mettere il codice nella callback, ad es.:
Effect.Appear('ultime', {
      duration: 1, from:1, to:0, delay: w,
      afterFinish: function() {
          alert("Questo codice è eseguito alla fine.");
      }
});
quindi la soluzione potrebbe essere:
// Recursive function
function animate(elemId, delay, stepDelay, numberOfTimes, count)
{
     if (count == null)
         count = 0;
     if (count == numberOfTimes))
         return;
     Effect.Appear(elemId, {
        duration: 1, from:1, to:0, delay: delay,
        afterFinish: function() {
           document.getElementById(elemId).innerHTML = count;
           Effect.Appear(elemId, {
           duration: 1, from:0, to:1, delay: delay,
           afterFinish: function() {
             animate(elemId, delay, stepDelay+4, numberOfTimes, ++count);
           }
        }
     })
};
// Call to recursive function.
animate('ultime', 0, 4, 5);
Ho scritto questo codice di getto, non l'ho provato per niente, nè 
conosco scriptaculous, per cui potrebbero esserci degli errori, ma il 
concetto di base è quello che ho scritto, sicuramente puoi migliorare il 
codice.
Ciao!
--- news://
freenews.netfront.net/
 - complaints: 
ne...@netfront.net
 ---