2013-04-17 80 views
30

我有一個觸發DOM事件的手錶:

scope.$watch(function() { return controller.selected; }, function(selected) { 
    if (selected) { 
     $input.trigger('focus'); 
    } 
}); 

問題是,我有,做了scope.$apply「專注」的處理程序。

$input.bind('focus', function() { 
    scope.$apply(function() { controller.focused = true; }); 
}); 

所以,當我的$watch$digest內解僱了,因爲它試圖觸發另一個$digest它會導致一個錯誤。

我的解決方法是將觸發器放入$timeout

scope.$watch(function() { return controller.selected; }, function(selected) { 
    if (selected) { 
     $timeout(function() { $input.trigger('focus'); }); 
    } 
}); 

此作品...迄今爲止。這是處理這個問題的正確方法嗎?我不確定這是否能夠捕捉到每一個案例,並且希望看到是否有一種角度認可的方式在摘要之後推出一段代碼。

謝謝!

+0

$ input.trigger('focus') - >是試圖將焦點設置爲輸入元素嗎? – ganaraj

+0

是的......看起來我可以用$ input.focus()代替。 「 – anonymous

回答

64

$timeout通常用於在摘要循環後運行某些內容(並且在瀏覽器呈現之後爲)。

$timeout將導致執行該函數後執行另一個摘要循環。如果您的trigger不影響Angular的任何內容,則可以將invokeApply參數設置爲false以避免運行另一個摘要循環。

如果你希望你的回調運行之前,瀏覽器呈現:如果代碼是使用$evalAsync從指令排隊,應該在DOM後運行已被角操作,但瀏覽器呈現前。但是,如果代碼使用來自控制器的$evalAsync排隊,則它將在DOM被Angular(並且在瀏覽器呈現之前)操縱之前運行。另見https://stackoverflow.com/a/17303759/215945

+0

」'$ timeout'將導致執行另一個摘要循環。「 ... 奇怪的。我會想,如果是這樣的話,我的事件處理程序調用'應用程序'我會得到相同'已在$摘要'錯誤。 – anonymous

+0

噢好吧,它在函數執行後調用'$ apply'。所以我應該將'invokeApply'參數設置爲false以避免無用的'$ digest'。謝謝。 – anonymous

+0

@eyston,我忘記了'invokeApply'參數。我會更新我的答案,而不是'setTimeout'。 –

0

像大家一直說的,你不應該在你的控制器中做DOM東西。

這裏是一個解決方案,它將雙向數據綁定應用於焦點。現在你的注意力集中在一個變量上。所以當你把變量設置爲true時,它將焦點設置在相應的元素上,並且當元素獲得焦點時,變量被設置。

http://plnkr.co/edit/CvPCVxy4MfJEM1UksrrA?p=preview

我們現在已經成功分離的焦點從控制器代碼。它還處理所有的$超時問題(我猜)。唯一需要注意的是你不應該使用相同的變量綁定到兩個不同元素的焦點。

編輯:更新了普朗克,因爲上一個沒有工作正常。

+0

這就是全部在指令中。 – anonymous

+0

@eyston這是重點。現在你所有的DOM東西都在指令中。另請注意,該指令不包含任何特定於應用程序的邏輯。這是邏輯的正確分離。 看到這個主題:https://github.com/angular/angular.js/issues/1277 – ganaraj

+1

我在說我的問題中的所有代碼都存在於指令中。 – anonymous