2013-11-28 9 views
40

Ho trovato questo snippet di codice che fa parte di una direttiva angolare che qualcuno ha scritto per il modal bootstrap.

//Update the visible value when the dialog is closed                                                    
       //through UI actions (Ok, cancel, etc.)                                                       
       element.bind("hide.bs.modal", function() {                                                      
        scope.modalVisible = false;                                                         
        if (!scope.$$phase && !scope.$root.$$phase)                                                     
         scope.$apply();                                                           
       }); 

ho capito che questa parte è per la seconda metà del bidirezionale legame si legano a hide.bs.modal evento e aggiornare modale quando cambia UI.

Volevo solo sapere perché la persona che controlla la fase $$ per scope e rootScope prima di chiamare applica?

Non possiamo chiamare immediatamente?

Che cos'è la fase $$ qui?

Ho provato a cercare molto, non ho trovato alcuna spiegazione valida.

EDIT:

ho trovato dove ho visto l'esempio: Simple Angular Directive for Bootstrap Modal

+0

Strettamente parlando, dovresti avere parentesi graffe attorno a 'scope. $ Apply()'. Alcuni browser potrebbero non volerli omettere. –

+0

controlla il mio aggiornamento, possiamo spostare più della discussione in quel thread. –

risposta

44

$$phase è un flag impostato mentre angolare è in un ciclo $digest.

A volte (in rari casi), si desidera controllare $$phase sull'oscilloscopio prima di eseguire uno $apply. Si verifica un errore se si tenta di $apply nel corso di una $digest:

Error: $apply already in progress

+11

Mentre la tua risposta è tecnicamente corretta, non sono d'accordo: IMHO no, non vuoi controllare la '$$ fase' * spesso *. Se lo fai, dimostra una mancanza di comprensione su come scrivere correttamente un'app AngularJS. Mi spiace dirlo, ma se si fa AngularJS nel modo giusto, raramente c'è un caso in cui è necessario fare affidamento su questa variabile interna (!). –

+0

Ohkay! questa cosa: "$ digest già in corso quando si chiama $ scope. $ apply() " –

+4

@GoloRoden Sì, completamente. Grazie, ho aggiornato. –

6

In questo esempio, il legame elemento otterrà eseguito da un evento non-angolare. Nella maggior parte dei casi, è possibile chiamare semplicemente $apply() senza controllare la fase.

Se si guarda il resto del codice, tuttavia, esiste una funzione $scope denominata showModal(). Questa funzione richiama il codice non angolare che probabilmente causerà un evento "hide.bs.modal" da attivare. Se l'evento viene attivato tramite questa rotta, lo stack di chiamate si trova all'interno di uno $digest.

Quindi, questo evento rientra nel raro caso di una funzione che verrà chiamata sia dal codice gestito angolarmente sia dal codice non angolare. Il controllo di $$phase in questo caso è necessario perché non si conosce il modo in cui è stato generato l'evento. Se $$phase è impostato su qualcosa, il ciclo digest terminerà fino al completamento e non sarà necessario chiamare $apply().

Questo modello è spesso denominato "safe apply".

32

Davin è assolutamente corretto che è una bandiera che imposta angolare durante il ciclo di digestione.

Ma non utilizzarlo nel codice.

Recentemente ho avuto la possibilità di chiedere a Misko (autore angolare) della fase $$, e ha detto di non usarlo mai; è un'implementazione interna del ciclo di digest e non è sicuro per il futuro.

Per assicurarsi che il codice continua a lavorare in futuro, ha suggerito involucro quello che vuoi "applicare sicuro" all'interno di un $ timeout

$timeout(function() { 
    // anything you want can go here and will safely be run on the next digest. 
}) 

Questo metodo è un sacco quando si dispone di callback o altro cose che potrebbero risolversi durante il ciclo di digest (ma non sempre)

Ecco uno snippet di esempio di quando avevo a che fare con una delle librerie di google: (Il resto del servizio da cui era stato rimosso è stato disattivato.)

window.gapi.client.load('oauth2', 'v2', function() { 
    var request = window.gapi.client.oauth2.userinfo.get(); 
    request.execute(function(response) { 
     // This happens outside of angular land, so wrap it in a timeout 
     // with an implied apply and blammo, we're in action. 
     $timeout(function() { 
      if(typeof(response['error']) !== 'undefined'){ 
       // If the google api sent us an error, reject the promise. 
       deferred.reject(response); 
      }else{ 
       // Resolve the promise with the whole response if ok. 
       deferred.resolve(response); 
      } 
     }); 
    }); 
}); 

Nota che l'argomento ritardo per $ timeout è facoltativo e sarà di default a 0 se non viene impostata ($timeout chiamate $browser.defer che defaults to 0 if delay isn't set)

Un po 'non-intuitivo, ma questa è la risposta dai ragazzi che scrivono angolare, quindi è abbastanza buono per me!

+0

Inject $ timeout in controller o ci sarà errore "$ timeout non definito" – nik

2

la mia comprensione è che è buono da usare durante la digestione o l'applicazione dell'ambito. Se è vero, significa che al momento è in corso una fase $ digest o $ apply. Se ricevi errori correlati puoi fare $ scope. $$ phase || $ Scope.digest(); che sarà digerito solo se $ scope. $$ pahse è falsy.

Problemi correlati