AngularJS 摘要循环在 $http.post.then() 期间未触发

AngularJS digest cycle not firing during $http.post.then()

使用AngularJS 1.6.1 (ES6/Babel)...控制器调用一个使用$[=的服务方法34=]() 所以我认为它会自动 运行 摘要。不得不添加 $timeout 来强制它(最好避免 $scope.$apply 因为这是一个 Angular 组件,很快就会升级到 AngularJS 2)。

是否有比我所做的更好的方法?原本是 $http.post 的 then() 应该有 运行 摘要循环吗?如果我不包括 $timeout,则视图中不会更新任何内容。

下订单 按钮提交一个表单,其 ngClick 为 $ctrl.placeOrder(checkout):

placeOrder(form) {
  if(form.$valid) {
    return this.Cart.placeOrder()
      .then(saleResponse => {
        // Page has {{ $ctrl.pageName }} but won't update without digest cycle
        this.pageName = 'Order Confirmation'; // displays confirmation
        form.$setPristine(); // treat the fields as untouched
        form.$submitted = false; // reset submitted state

        // Force a digest to run. Why is this needed?
        this.$timeout(() => this.pageName);
      })
      .catch(saleResponse => {
        form.$submitted = false;
        this.errorMessage = saleResponse.message;
        if(this.errorMessage.includes('card')) this.focusOnCardNumber();
      });
  }
}

这里是 Cart.placeOrder():

placeOrder() {
  // braintreeHostedFieldsTokenize() is a wrapper to return new Promise for their callback-based API
  return this.braintreeHostedFieldsTokenize(this.hostedFieldsInstance)
    .then(this.postOrderInformation.bind(this));
}

和Cart.postOrderInformation()

postOrderInformation(payload) {
  const orderInformation = {
    nonceFromClient: payload.nonce,
    purchaser: this.purchaser,
    recipient: this.recipient,
    cartItems: this.cartItems
  };

  return this.$http
    .post('/api/order', orderInformation)
    .then(orderResponse => {
      this.confirmation = orderResponse.data;
      if(!orderResponse.data.success) throw orderResponse.data;
      return this.confirmation;
    });
}

关于我可能在哪里出错需要使用 $timeout 的任何想法?我的假设是 $http.post 的 then() 会 运行 自身的摘要循环,因为它是 AngularJS。提前致谢。

我建议使用 $evalAsync 而不是 $timeout。检查文档 (https://docs.angularjs.org/api/ng/type/$rootScope.Scope) and this link: AngularJS : $evalAsync vs $timeout

我的想法是 Cart.placeOrder().then 方法是在 Angular $q 服务 [=24= 外部的承诺 library/queue 上执行的].尝试使用 $q.when:

将其移动到 $q 服务
placeOrder(form) {
  if(form.$valid) {
    //return this.Cart.placeOrder()
    var promise = this.Cart.placeOrder();
    return $q.when(promise)
      .then(saleResponse => {
        // Page has {{ $ctrl.pageName }} but won't update without digest cycle
        this.pageName = 'Order Confirmation'; // displays confirmation
        form.$setPristine(); // treat the fields as untouched
        form.$submitted = false; // reset submitted state

        // Force a digest to run. Why is this needed?
        // this.$timeout(() => this.pageName);
      })

braintreeHostedFieldsTokenize() 返回的承诺不是 $q 服务承诺,因此未与 Angular 摘要周期集成。

$q.when

Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted.

-- AngularJS $q Service API Reference - $q.when