【问题标题】:AngularJS How to force DOM update after setTimeout [duplicate]AngularJS如何在setTimeout之后强制DOM更新[重复]
【发布时间】:2019-01-10 16:08:53
【问题描述】:

下面的代码块等待超时,然后执行带有承诺的 HTTP 请求,然后根据响应更改 Angular Material 范围变量。在输入字段上使用ng-change 调用它。我的 HTML 中还有一个带有 ng-hide="showStuff" 的元素,显然,当 $scope.showStuff 变为 false 时,我希望它立即消失。不幸的是,直到我在 DOM 中选择其他内容时它才会真正消失。

我之前使用过 Promise 来更改 DOM 中的内容,并且效果很好。为什么 DOM 不自行更新,我该如何解决?

$scope.checkSomething = function() {
    // Use a timeout to prevent a checks from going off too rapidly
    if (queryTimeout) {
        clearTimeout(queryTimeout);
    }
    queryTimeout = setTimeout(function() {
        bluebird.bind({}).then(function() {
            return makeHttpRequest();
        }).then(function(res) {
            $scope.showStuff = res.data.length > 0;
        })
    }, 500);
}

【问题讨论】:

  • 你是如何发出 HTTP 请求的?你在使用 AngularJS $http 服务吗?

标签: javascript html angularjs dom angularjs-material


【解决方案1】:

AngularJs 的更改检测(称为“摘要循环”)不知道要运行,除非代码开始在 Angular 上下文中执行。所以异步的东西不能很好地处理它。这就是为什么 Angular 提供诸如 $timeout、$interval 和 $q 之类的服务来执行异步操作,从而为您处理摘要周期的启动。使用这些,这种类型的问题将非常罕见。

如果您想使用除 $q 之外的其他类型的 Promise,则需要手动启动摘要循环。如果您希望它立即发生,您可以使用$scope.$apply() 执行此操作,如果您希望它很快发生,但不是同步发生,您可以使用$scope.$applyAsync 执行此操作(如果您可能有多个调用它并且您希望它们被批处理,则很有用一起)。

因此,如果您不想使用 $timeout 和 $q,则必须执行以下操作:

setTimeout(function() {
    bluebird.bind({}).then(function() {
        return makeHttpRequest();
    }).then(function(res) {
        $scope.showStuff = res.data.length > 0;
        $scope.$apply();
    })
}, 500);

【讨论】:

  • 我宁愿检查 @Christopher Waugh 使用什么来发出 HTTP 请求,也不愿用 $apply() 强制 $digest。无论使用什么库,Promise 本身都不应触发脏检查。
  • AngularJS 有它自己的超时方法$timeout,所以你不必使用$scope.$apply()。但是,是的,我会对 HTTP 请求更感兴趣
  • 使用$timeout 服务而不是setTimeout,则不需要$apply。请记住,在大多数地方(控制器、服务)$apply 已经为您调用过。只有在实现自定义事件回调或使用第三方库回调时,才需要显式调用 $apply。
【解决方案2】:

使用$timeout 服务,它返回一个与AngularJS 执行上下文及其摘要循环集成的promise:

$scope.checkSomething = function() {
    // Use a timeout to prevent a checks from going off too rapidly
    if (queryTimeout) {
        $timeout.cancel(queryTimeout);
    }
    queryTimeout = $timeout(function() {
        return makeHttpRequest();
    }, 500);

    queryTimeout.then(function(res) {
        $scope.showStuff = res.data.length > 0;
    })
}

这将使makeHttpRequest 的执行延迟500 毫秒。 $timeout 服务返回一个用于解析来自服务器的数据的承诺。

AngularJS 通过提供自己的事件处理循环来修改正常的 JavaScript 流程。这将 JavaScript 拆分为经典和 AngularJS 执行上下文。只有在 AngularJS 执行上下文中应用的操作才能受益于 AngularJS 数据绑定、异常处理、属性监视等。

通过使用 AngularJS 的 $timeout 服务,封装的 setTimeout 将在 AngularJS 执行上下文中执行。

有关详细信息,请参阅

【讨论】:

  • 所有这些答案都很好,但我将其标记为正确,因为它提到了取消超时,这就是我想使用超时而不是承诺的原因。
猜你喜欢
  • 2011-07-07
  • 2013-01-30
  • 1970-01-01
  • 2023-03-20
  • 2019-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多