AngularJS如何在setTimeout之后强制DOM更新

时间:2018-08-02 19:53:07

标签: javascript html angularjs dom angularjs-material

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

在更改DOM中的内容之前,我已经使用了promises,并且它们工作正常。为什么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);
}

2 个答案:

答案 0 :(得分:2)

除非代码开始在角度上下文中执行,否则不对AngularJs进行更改检测(称为“摘要循环”)。因此,异步事情并不能很好地工作。这就是为什么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);

答案 1 :(得分:1)

使用$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服务,将在AngularJS执行上下文中执行包装的setTimeout

有关更多信息,请参见