2013-11-28 34 views
40

我發現這個代碼片段是某人爲引導模式寫的角度指令的一部分。

//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();                                                           
       }); 

我瞭解,這部分是對的雙向下半年結合,我們結合hide.bs.modal事件和用戶界面的變化更新模式。

我只是想知道爲什麼在調用apply之前爲scope和rootScope檢查$$階段的人?

我們不能直接打電話申請嗎?

什麼是$$階段?

我嘗試了很多搜索,找不到任何好的解釋。

編輯:

我發現在那裏我看到的例子: Simple Angular Directive for Bootstrap Modal

+0

嚴格地說,你應該在'scope。$ apply()'周圍花括號。有些瀏覽器可能不喜歡省略它們。 –

+0

檢查我的更新,我們可以轉移該線程中的更多討論。 –

回答

44

$$phase是設置一個標誌,而角是在$digest週期。

有時(在極少數情況下),您想在執行$apply之前檢查$$phase的範圍。

Error: $apply already in progress

+11

雖然你的答案在技術上是正確的,但我不同意:恕我直言,不,你不想檢查'$$ phase' *經常*。如果你這樣做,它證明了如何正確編寫AngularJS應用程序缺乏理解。很抱歉地說,但如果您以正確的方式進行AngularJS,則很少有情況需要依賴此內部變量(!)。 –

+0

Ohkay!這個東西:「$ digest正在調用$ scope。$ apply() 」 –

+4

@GoloRoden完全是。謝謝,我已更新。 –

6

在這個例子中,結合元素會得到一個非角事件執行:如果您在$digest期間儘量$apply時發生錯誤。在大多數情況下,只需撥打$apply()而不檢查階段是安全的。

但是,如果您查看代碼的其餘部分,則有一個$scope函數,稱爲showModal()。此函數調用可能會導致「hide.bs.modal」事件觸發的非角度代碼。如果事件通過此路線觸發,則調用堆棧位於$digest之內。

所以,這個事件屬於一個函數的罕見情況,它將從角度託管代碼和非角度代碼中被調用。在這種情況下檢查$$phase是必要的,因爲你不知道事件是如何發生的。如果$$phase設置爲某些內容,則摘要循環將完成並且不需要調用$apply()

這種模式通常被稱爲"safe apply"

32

達文是完全正確的,它是在消化週期中角度設置的標誌。

但是不要在你的代碼中使用它。

我最近有機會問米斯科(角作者)關於$$階段,他說,從來沒有使用它;這是摘要循環的內部實現,它不是未來的安全。

爲了確保您的代碼將繼續在今後的工作中,他建議任何你想做的「安全應用」一$超時

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

的內包裝這來了很多,當你有回調或其他在摘要循環中可能會解析的東西(但並不總是)

下面是我處理谷歌圖書館的一個示例代碼片段:(其餘的服務來自於此)已從中斷。)

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); 
      } 
     }); 
    }); 
}); 

注意,對於$超時延遲參數是可選的,默認爲0,如果未設置($timeout電話$browser.deferdefaults to 0 if delay isn't set

小非直觀的,但是這是從人寫角的答案,所以它的對我來說足夠好!

+0

在控制器中注入$ timeout或者會出現「$ timeout not defined」錯誤 – nik

2

我的理解是消化或應用範圍時很好用。如果問題很嚴重,這意味着目前正在進行消化或$應用階段。如果您收到相關錯誤,您可以執行$ scope。$$階段|| $ scope.digest();如果$ scope。$$ pahse是虛假的,它將只會消化。