Newsgroup: it.comp.lang.javascript
Titolo: Autobind - Variabili

Salve a tutti,
  nel nostro progetto usiamo un framework JS sviluppato internamente
basato su Jquery, quello ci permette di fare e' di poter aggiungere 
plugin velocemente.
Nel FW ho creato una funzione di autobind, e' un ciclo sui plugin 
caricati, cerca se nel plugin c'e' l'array "BINDS" e binda l'evento.
 
 
Questa e' la parte del binding:
 
...
var bind_obj = this[plugin_name][function_name].binds[bind_index];
if (bind_obj.live == 1) {
   jQuery(bind_obj.static_target).on(bind_obj.event,bind_obj.target,this[plugin_name][function_name].f);
  } else {
   jQuery(bind_obj.target).bind(bind_obj.event,this[plugin_name][function_name].f);
  }
...
 
E finqui tutto funziona perfettamente.
Ora vorrei espandere il tutto per eseguire alcune callback (prima della funzione, dopo,
caso di errore ecc..)
 
Quello a cui avevo pensato era di creare una funzione del framework per eseguire le
altre funzioni e gestire il tutto da li qualcosa del tipo (pseudo-codice):
 
function execMe(plugin,metodo) {
   selected_pluging = fw[plugin][metodo]   
   if (fw[plugin][metodo].preDispatch == "function") fw[plugin][metodo].preDispatch()
   fw[plugin][metodo].mainFunc()
}
 
e fare il bind in questo modo:
....
  jQuery(bind_obj.target).bind(bind_obj.event,
     function(){
                fw.execMe(plugin_name,function_name)
     }
  );
....
 
Ma non funziona come mi aspettavo (mi aspettavo la cosa sbagliata)
perche' plugin_name e function_name hanno sempre il valore dell'ultima
funzione bindata. (Se passo a bind un array di valori e' esattamente
la stessa cosa).
 
Ho provato anche questa soluzione:
...
jQuery(bind_obj.target).bind(bind_obj.event,function(){
                    fw[plugin_name][function_name].f()
                })
...
 
Ma ovviamente il risultato e' il medesimo (ovvero plugin_name,function_name
sono sempre all'ultimo valore del ciclo).
 
L'unica idea che mi e' venuta in mente e' quella di scrivere plugin_name e
function_name nel DOM mentre faccio il binding, e poi leggerlo all'interno
della funzione "execMe".
 
Pseudo code:
...
  jQuery(bind_obj.target).bind(bind_obj.event,fw.execMe);
  jQuery(bind_obj.target).attr("plugin_name",plugin_name);
  jQuery(bind_obj.target).attr("function_name",function_name);
...
 
function execMe() {
   selected_pluging = fw[jQuery(this).attr("plugin")][jQuery(this).attr("function_name")]   
   if (selected_pluging.preDispatch == "function") selected_pluging.preDispatch()
   selected_pluging.mainFunc()
}
 
C'e' un modo per passare i parametri a "execMe" senza scriverli sul DOM,
o scriverli sul DOM e' un metodo sensato?
 
 
Grazie
 
J

 funzione bindata.
 
Il tuo � il classico problema di closure. Per farla breve, metti caso di
avere un array di link, e di voler associare a tutti un evento:
 
    for (var i = 0; i < links.length; i++)
        links[i].onclick = function() {
            alert(i);
        }
 
In questo modo tutti i link, una volta cliccati, visualizzeranno il
valore di `links.length`, sebbene la tua idea era che visualizzassero il
loro indice.
 
Perch�? Perch� hai creato una closure: la funzione associata all'event
handler, condivide lo scope in cui � stata creata, e quindi pu� accedere
alla variabile `i`: ma � un riferimento! Dato che il valore di `i`
cambia continuamente, e che la funzione associata � asincrona (viene
invocata quando l'utente clicca sul link), la funzione visualizzer� il
valore di `i` nel momento in cui viene eseguita (cio� al click) e in
quel momento in valore di `i` � pari a `links.length`.
 
Per risolvere tale problema, hai bisogno di creare una funzione che
abbia il valore di `i` "fisso". Questo lo fai usando il metodo `bind`:
 
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
 
 
Che non ha nulla a che vedere con il `bind` di jQuery, per inciso.
 
Il tuo codice quindi diventerebbe:
 
jQuery(bind_obj.target).on(bind_obj.event,
fw.execMe.bind(bind_obj.target, plugin_name, function_name));
 
Ammesso che `bind_obj.target` sia l'elemento DOM ovviamente.
 
Nei browser che non supportano `bind`, c'� uno shim che puoi usare (nel
link sopracitato dovrebbe menzionarlo), altrimenti puoi farlo sempre a
mano, ma diventa molto poco elegante.

 mano, ma diventa molto poco elegante.
 
Si ne parla, grazie mille.
Domani o dopodomani tornero' sull'implementazione, poi faro' sapere
 
J.
 
 

 
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
 
 
 
colgo l'occasione x un ringraziamento anche io, perchè conoscevo il prb, 
ma non conoscevo la funzione bind..
 
-- 
Z.

 <
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/
 
Statements/let>
 
una cosa sul let che non ho mai capito... ma fare
 
for (let i=0; i<10; i+=1) {
   ...
}
 
è legale? e sopratutto, lo scope di i qual è?
 
 
Vabbè che comunque, finché si potrà usare con "tranquillità" e senza 
problemi di compatibilità questa feature ci vorranno anni...
 
 
-- 
By ZeD

 problemi di compatibilità questa feature ci vorranno anni...
 
Io la uso già da almeno un lustro in modo regolare.
Per quanto riguarda a livello cross-browser, le cose sono decisamente
cambiate da quando i browser hanno le rapid release e gli aggiornamenti
automatici. Pensa solo a quanti anni ci siamo tenuti ES3, e quanto
velocemente è stato adottato ES5, invece. E siamo già a ES6.
Anche la Microsoft con IE10 ha cambiato filosofia; ed ella stessa
suggerisce di non supportare più i suoi browser vetusti.
 
Lo sviluppo web inoltre si è spostato largamente da siti ad
applicazioni, e anzi la distinzione tra i due non è più così netta come
un tempo. Negli ultimi anni si è visto un aumento incredibile delle
innovazioni a livello di JavaScript e tecnologie web, proprio per
questo. Così come un tempo si diceva "JavaScript non serve solo a fare
rollover", ora si può dire "JavaScript non serve solo a fare siti web".
 
Sono quindi molto fiducioso, in merito.

 
 
 
Alla fine ho implementato con ".bind" e funziona che e' una meraviglia.
 
Ho fatto qualcosa del genere:
 
Bind:
 
..
 
jQuery("#DOM").bind(EVENT, this.execute.bind("#DOM",this[plugin_name][function_name]));
//in questo caso quando eseguo "execute" mi trovo direttamente il plugin
..
 
 
Ho quindi implementato preDispatch e afterDispatch (2 callback sincrone)
 e 3 callback asincrone usando deferred.
 
Siccome "execute" e' usata da tutti i plugin creo la variabile deferred
e la passo alla funzione, sta poi al  plugin settare deferred per lanciare 
"onSuccess" o "onError"
 
Tutte plugin.preDispatch, .afterDispatch, .onSuccess ecc sono funzioni
che possono essere definite oppure no nel plugin.
 
//-------
this.execute = function(plugin,e) {
 
	//eseguo la prima funzione sincrona
        if (typeof plugin.preDispatch == "function") {
            plugin.preDispatch();
        }
 
 
        var deferred = new jQuery.Deferred();
 
	//bind onSuccess
        if (typeof plugin.onSuccess == "function") {
            deferred.done(plugin.onSuccess);
        }
 
	//bind onError
        if (typeof plugin.onError == "function") {
            deferred.fail(plugin.onError);
        }
 
 
        //bind onComplete
        jQuery.when(deferred).then(function(){
            if (typeof plugin.onComplete == "function") {
                plugin.onComplete();
            }
        });
 
 
        plugin.f(e,deferred);
 
 
	//eseguo la 2nda funzione sincrona
        if (typeof plugin.afterDispatch == "function") {
            plugin.afterDispatch();
        }
 
 
    }
//------------
 
La mia domanda e' se questo approccio e' giusto, visto che e' la 
prima volta che uso le deferred/promise
 
Grazie
 
J.

 suggerisce di non supportare più i suoi browser vetusti.
 
Hai un link? un qualcosa?
 
Ho una "webapp" per la quale devo mantenere la compatibilità con ie7, e 
vorrei *almeno* scalare di una versione!
 
-- 
By ZeD

 vorrei *almeno* scalare di una versione!
 
Sono molto grato di non dover pensare più al mondo Microsoft. ;)


 
 
Chiedo scusa, sono un novellino, come si risolve il problema di sopra 
con il bind invece che con il let o doppia clojure?
 
Grazie

 prima volta che uso le deferred/promise
 
Onestamente a prima vista trovo tutto il codice un po' macchinoso e
ridondante, non mi è chiaro perché uno dovrebbe specificare sia funzioni
di callback come `onSuccess`, sia usare il deferred.
 
Ma non so bene quale sia il tuo scopo e se a te piace e funziona,
preferisco non imbarcarmi nella discussione, temo porterebbe via troppo
tempo. :)


 
Grazie chiarissimo