【问题标题】:AngularJS digest cycle not firing during $http.post.then()AngularJS 摘要循环在 $http.post.then() 期间未触发
【发布时间】:2017-05-09 23:40:23
【问题描述】:

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

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

Place Order 按钮提交一个表单,其 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。提前致谢。

【问题讨论】:

    标签: angularjs angular-promise es6-promise angularjs-digest


    【解决方案1】:

    我的想法是 Cart.placeOrder() 的 .then 方法正在 Angular $q 服务库/队列外部的承诺库/队列上执行。尝试使用 $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

    将可能是值或(第 3 方)then-able 承诺的对象包装到 $q 承诺中。当您处理的对象可能是也可能不是 Promise 时,或者当 Promise 来自不可信的来源时,这很有用。

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

    【讨论】:

    • 谢谢 - 你的回答帮助我找到了这个。虽然 this.Cart.placeOrder 的 then() 调用了一个使用 $http 的方法,但 braintreeHostedFieldsTokenize() 返回了新的 Promise。所以我用“$q”替换了“new Promise”,这样就不需要我使用 $timeout 实现的解决方法了。
    • 顺便说一句,我用 new Promise 代替了 $q 因为我“认为”它是 ES6 的一部分会更有效,但显然它不知道摘要循环,而 $q 不是。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2016-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-15
      • 1970-01-01
      • 2016-10-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多