2015-02-18 15 views
12

Vorrei iniziare dicendo che sono nuovo di jQuery e sospetto che stia facendo qualcosa di stupido, quindi spero che questo sia molto semplice per qualcuno.jQuery. Quando(). Done() non funziona

Sto tentando di aggiungere un sottomenu mobile scorrevole al mio sito web. Voglio un effetto accordian per cui se faccio clic su un collegamento genitore, si apre il sottomenu figlio e tutti gli altri sottomenu si chiudono. Il problema è il tempismo: il sottomenu figlio si apre e viene di nuovo chiuso dal ripristino di tutti i sottomenu. Presumo che la risposta sia usare i differiti, ma tutto quello che ho provato è fallito. Questo è il codice (attualmente non funzionante):

function ResetMenu(){ 
    jQuery(".mobile-menu").find(".sub-menu").slideUp(100); 
    jQuery(".mobile-menu").find(".menu-item-has-child").removeClass("open"); 
}; 

function OpenSubmenu(){ 
    jQuery(this).next("ul").slideDown(100); 
    jQuery(this).parent().addClass("open"); 
}; 

jQuery("li.menu-item-has-children > a").click(function(){ 

    if(jQuery(this).parent().hasClass("open")){ 
     jQuery(".mobile-menu").find(".sub-menu").slideUp(100); 
     jQuery(this).parent().removeClass("open"); 
    } else { 
     jQuery.when(ResetMenu()).done(OpenSubmenu()); 
    } 
    return false; 
}); 

Qualsiasi aiuto sarebbe molto apprezzato. Grazie!

Ronel

+1

'ResetMenu' necessità di restituire una promessa per far funzionare tutto questo .. –

risposta

22

Questo è un errore comune su come utilizzare jQuery.when().

jQuery.when() richiede promesse come argomenti. Non ha poteri magici per sapere quando le funzioni passate sono in qualche modo fatte. Queste funzioni DEVONO restituire promesse risolte o rifiutate quando viene eseguito il codice sottostante e quindi è possibile passare tali promesse a jQuery.when().

La tua funzione ResetMenu() non restituisce nulla quindi, il tuo jQuery.when() non aspetta nulla. Esegue immediatamente il gestore .then() (il che sembra che non sia quello che vuoi).

Così, in questa linea:

jQuery.when(ResetMenu()).done(OpenSubmenu()); 

ResetMenu() deve restituire una promessa per jQuery.when() sapere quando è fatto.

Si potrebbe fissare ResetMenu() a lavorare in questo modo in questo modo:

function ResetMenu(){ 
    return jQuery(".mobile-menu").find(".sub-menu").slideUp(100).promise().then(function() { 
     // remove this class when the animation has completed 
     jQuery(".mobile-menu").find(".menu-item-has-child").removeClass("open"); 
    }); 
}; 

E, poi ulteriormente, è necessario cambiare il modo di passare una funzione per .done() a questo, che sia lo rende solo un riferimento funzione che può essere eseguita dopo e lega una appropriata this valore ad essa:

jQuery.when(ResetMenu()).done(OpenSubmenu.bind(this)); 

nota, il .bind(this) presuppone che this è il valore appropriato. È possibile passare qualsiasi valore è il valore corretto lì e che diventerà il valore this all'interno di OpenSubmenu() quando viene eseguito.

+3

buono con la' then' richiamata ... '.done (OpenSubmenu()); 'dovrebbe essere' .done (OpenSubmenu); ' –

+0

@ArunPJohny - buon catc h. Fisso. – jfriend00

+0

Grazie mille, che risolve la parte .quando. Sfortunatamente il.parte completata non funziona ancora - ho capito che la funzione OpenSubmenu ha bisogno di un parametro, in particolare jQuery (this) deve essere passato dalla funzione evento click. Tuttavia quando ho provato a usare .done (function() {OpenSubmenu (jQuery (this));}); tutto fallisce di nuovo. Ho il sospetto che ciò sia dovuto al fatto che sto passando una funzione anziché un riferimento a una funzione, come da ultimo commento, tuttavia non vedo come si potrebbe fare altrimenti. Per favore potresti aggiungere questo alla tua risposta? – Ronelz

3

Quando si passa un oggetto non promessa di $.when() i callback passati al done() viene richiamato immediatamente, nel caso in cui ResetMenu non restituisce nulla la OpenSubmenu viene chiamato immediatamente, c'è un altro problema anche - non si dovrebbero invocare OpenSubmenu direttamente (con l'aggiunta di ()), è necessario passare un riferimento alla funzione di done()

function ResetMenu() { 
    jQuery(".mobile-menu").find(".menu-item-has-child").removeClass("open"); 
    return jQuery(".mobile-menu").find(".sub-menu").slideUp(100).promise(); 

}; 

function OpenSubmenu() { 
    jQuery(this).next("ul").slideDown(100); 
    jQuery(this).parent().addClass("open"); 
}; 

jQuery("li.menu-item-has-children > a").click(function() { 

    if (jQuery(this).parent().hasClass("open")) { 
     jQuery(".mobile-menu").find(".sub-menu").slideUp(100); 
     jQuery(this).parent().removeClass("open"); 
    } else { 
     jQuery.when(ResetMenu()).done(OpenSubmenu); 
    } 
    return false; 
});