1

我了解 Angular 的主要原则之一是:

你不应该从你的控制器中引用你的 DOM。

我正在尝试处理信用卡付款,这需要以下步骤:

  • 用户填写表单,然后单击提交按钮
  • 该表格的一部分被发送到我们的服务器,它开始与支付网关的交易
  • 我们服务器的响应会更新表单中的值,然后必须通过表单 POST 将其直接提交到支付网关。
  • 其他事情发生。

在这种情况下,我该如何:

  • 更新表单中的数据(不从控制器引用表单)
  • 获取要提交的表单?

该表单绑定到我的控制器上的模型,所以我尝试了类似以下的方法:

<form action="{{paymentModel.urlFromTheResponse}}">
    <input type="hidden" name="accessCode" value="{{paymentModelaccessCodeFromResponse}}" />
    <button ng-click="startTransaction(paymentModel)"></button>
</form>

// in my success handler
.success(function(data) {
     paymentModel.urlFromTheResponse = data.url;
     paymentModel.accessCode = data.accessCode;
     $scope.apply();
}

这里的理论是,如果我可以通过数据绑定立即使表单进入正确的状态,那么我可以做一些事情来提交表单。但是,这会引发错误:

已在进行摘要

支持这种类型的流程的 Angular 方式是什么?看来我需要直接与 DOM 交互,这违背了控制器的本质。

4

3 回答 3

1

正如其他人所说,您不需要调用 $scope.$apply() 因为表单应该已经通过在每个字段上设置 ng-model 属性来绑定到角度。

但是,有时需要调用 $scope.$apply() 来更新显示,当数据是从 angular 之外的其他来源拉入时...

在这些情况下,我很幸运:

  // This method will be inherited by all other controllers
  // It should be used any time that $scope.$apply() would
  // otherwise be used.
  $scope.safeApply = function(fn) {
    var phase = this.$root.$$phase;
    if(phase == '$apply' || phase == '$digest') {
      if(fn && (typeof(fn) === 'function')) {
        fn();
      }
    } else {
      this.$apply(fn);
    }
  };

我把它放在我最外层的控制器中,所以页面上的所有其他控制器都继承了它的函数。每当我发现我需要调用 apply 时,我都会调用 $scope.safeApply() 如果没有,它将调用 apply已经在进行应用或摘要,否则,这些更改将已被当前运行的应用/摘要拾取。

在你的代码中我会改变这个:

<input type="hidden" name="accessCode" value="{{paymentModelaccessCodeFromResponse}}" />

对此:

<input type="hidden" name="accessCode" ng-model="paymentModel.accessCode" />

我可能还会删除表单操作,而是在控制器中添加类似这样的内容:

$scope.$watch('paymentModel.accessCode', function() {
  // Fire off additional form submission here.
})
于 2013-01-28T19:57:45.307 回答
0

生成错误是因为您的成功回调已经“在 Angular 内部”,因此 $scope.apply() 将自动为您调用。

如果您在表单元素上使用 ng-model(而不是 value),那么您可以在成功回调中修改 model/$scope 属性,并且表单将自动更新(由于通过 ng-model 进行的双向数据绑定)。然而,与其尝试提​​交表单,为什么不直接使用控制器中的 $http 或 $resource 服务来调用 Web 服务呢?(这就是为什么我问用户是否需要参与我的评论。)

于 2013-01-21T22:58:37.410 回答
0

假设您使用的是 $http 之类的东西,您已经在角度范围内,不需要手动调用 $scope.apply(); 因为您已经在角度执行中。

您应该能够放弃 $scope.apply() 并简单地拥有一个

.success(function(data) {
     paymentModel.urlFromTheResponse = data.url;
     paymentModel.accessCode = data.accessCode;
 $http.post("/finalstep",paymentModel).success(function(data)
{
// other stuff
});
}
于 2013-01-22T13:04:40.157 回答