1

我有一个 UI 组件,$watch它的宽度有回调(原因与这篇文章无关)。问题是在某些情况下:

  • 宽度从非角度上下文改变->
  • 没有$digest循环->
  • 我的$watch回调没有被调用

尽管我的应用程序是一个完整的 Angular 应用程序,但仍然存在代码在非 Angular 上下文中执行的情况。例如:JQuery 调用window.setTimeout- 所以即使我的代码JQuery是从角度上下文中调用的,超时回调也会在非角度上下文中调用,并且$watch之后不会执行我的回调。

顺便说一句,即使是棱角分明的自己也会打电话给window.setTimeout他们AnimatorService......

所以我的问题是:如何确保在$digest执行任何代码后始终执行循环?(即使代码是第 3 方代码......)

我考虑过覆盖原始window.setTimeout方法,但是:

  • 感觉有点丑陋和危险。
  • 恐怕它不会涵盖所有用例。

添加一个plunker。plunker 样本包含:

  • 可以使用 JQueryfadeOut方法隐藏的元素。
  • 执行fadeOut隐藏元素调用的按钮。
  • 显示元素显示状态的文本(Shown!!!Hidden!!!)。此文本通过$watch对元素display属性进行 ing 更新。
  • 一个按钮,除了启动一些角度代码之外什么都不做,以便$digest调用一个循环。

流动:

  • 单击Fade Out按钮 -> 元素将被隐藏但状态文本将保留Shown!!!。您现在可以永远等待 - 或者:
  • 单击Do Nothing按钮-> 文本会突然改变。

为什么?

单击Fade Out按钮时JQuery.fadeOut调用该window.setTimeout方法。之后我的$watch回调被调用,但元素仍然没有隐藏。该元素仅在调用超时回调后才隐藏 - 但是没有$digest循环(而且我无法知道触发一个)。只有在下次运行角度代码时,我的$watch函数才会被再次调用并且状态会被更新。

4

2 回答 2

1

AngularJS 在对象上提供了一个特殊的$apply方法,scope允许您从 AngularJS 框架之外执行代码。

$apply函数将在正确的上下文中执行您的代码,然后应用一个$digest循环,因此您不必自己处理。

要在您的代码中实现它,您可以:

// Get element
var $element = $('#yourElement');

// Get scope
var scope = angular.element($element).scope();

// Execute your code
scope.$apply(function(scope){
    // Your logic here
    // All watchers in the scope will be triggered
});

(上面的场景可能会根据您的实际应用而改变)。

您可以在此处阅读有关$apply范围对象方法的更多信息:http: //docs.angularjs.org/api/ng.$ro​​otScope.Scope

希望有帮助!

于 2013-06-23T11:36:54.523 回答
0

查看您的 plunker,您可以在调用 animate 时添加一个回调,以便在动画完成后手动触发对 Angular 范围的更新:

前:

$scope.fadeOut = function() {
    animatedElement.fadeOut('slow');
};

var getDisplay = function() {
    return animatedElement.css('display');
};

$scope.$watch(getDisplay, function(display) {
    console.log('$watch called with display = `' + display + '`');
    $scope.display = display === 'none' ? 'Hidden!!!' : 'Shown!!!';
});

后:

$scope.fadeOut = function() {
    animatedElement.fadeOut('slow', function() { $scope.$digest(); });
};

这将导致您在 getDisplay 上的手表在动画完成时被调用,届时它将返回正确的值。

于 2013-08-14T12:54:26.650 回答