2013-11-28 29 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是虚假的,它将只会消化。