Home:ALL Converter>AngularJS : What's the Angular way to interact with a form?

AngularJS : What's the Angular way to interact with a form?

Ask Time:2013-01-22T06:29:53         Author:Marty Pitt

Json Formatter

I understand one of the key principals of Angular is:

Thou shalt not reference thy DOM from withinst thou's controllers.

I'm trying to process a credit card payment, which requires the following steps:

  • User fills out a form, and clicks a submit button
  • A portion of that form is sent to our servers, which starts a transaction with the payment gateway
  • The response from our servers updates values in the form, which must then be submitted directly to the payment gateway, via a form POST.
  • Other stuff happens.

In this scenario, how do I:

  • Update the data in the form (without referencing the form from the controller)
  • Get the form to submit?

The form binds to a model on my controller, so I've tried something like the following:

<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();
}

the theory being here that if I can immediately get the form into the correct state via databinding, I can then do something to submit the form. However, this throws an error:

Digest already in progress

What's the Angular way to support this type of flow? It seems I'm required to interact directly with the DOM, which goes against the nature of controllers.

Author:Marty Pitt,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/14448386/angularjs-whats-the-angular-way-to-interact-with-a-form
Will Vincent :

As others have stated, you shouldn't need to call $scope.$apply() because the form should already be tied to angular by setting ng-model attributes on each of the fields.\n\nHowever, occasionally it is necessary to call $scope.$apply() to update display when data is pulled in from some other source outside of angular...\n\nIn those cases, I've had great luck with this:\n\n // This method will be inherited by all other controllers\n // It should be used any time that $scope.$apply() would\n // otherwise be used.\n $scope.safeApply = function(fn) {\n var phase = this.$root.$$phase;\n if(phase == '$apply' || phase == '$digest') {\n if(fn && (typeof(fn) === 'function')) {\n fn();\n }\n } else {\n this.$apply(fn);\n }\n };\n\n\nI place that in my outermost controller, so all other controllers on the page inherit the function from it.. Any time I find I need a call to apply, I instead call $scope.safeApply() which will call apply if there is not already an apply or digest in progress, otherwise, those changes will already be picked up by the currently running apply/digest.\n\nIn your code I would change this:\n\n<input type=\"hidden\" name=\"accessCode\" value=\"{{paymentModelaccessCodeFromResponse}}\" />\n\n\nTo this:\n\n<input type=\"hidden\" name=\"accessCode\" ng-model=\"paymentModel.accessCode\" />\n\n\nI would probably also remove the form action, and instead add something like this in the controller:\n\n$scope.$watch('paymentModel.accessCode', function() {\n // Fire off additional form submission here.\n})\n",
2013-01-28T19:57:45
Mark Rajcok :

The error is generated because your success callback is already \"inside Angular\", so $scope.apply() will be called automatically for you.\n\nIf you use ng-model (instead of value) on your form elements, then you can modify the model/$scope properties in your success callback and the form will automatically update (due to two-way databinding via ng-model). However, instead of trying to submit the form, why not just use the $http or $resource service inside your controller to call the web service? (That's why I asked if the user needed to be involved in my comment.)",
2013-01-21T22:58:37
yy