mmjmanders
mmjmanders

Reputation: 1553

angularjs form action after service call

I want to POST data from a html form to the default action url but one hidden input depends on the data returned from a service call. When I use ng-submit the $scope doesn't get updated after the service call before the POST is done. I can't use an Ajax POST because I get an HTML page after the POST.

The form looks like this:

<form name="payment" role="form" class="form-inline" ng-show="!loading" method="POST" action="{{paymentUrl}}" ng-submit="createOrder()" novalidate>
   <input type="hidden" id="responseUrl" name="responseUrl" value="{{postPaymentUrl}}"/>
   <input type="hidden" id="orderNumber" name="orderNumber" value="{{orderNumber}}"/>
   <select class="form-control" id="paymentMethodBrand" name="paymentMethodBrand">
      <option ng-repeat="paymentMethod in paymentMethods | orderBy:'method'" value="{{paymentMethod.method}}">{{paymentMethod.method}}</option>
   </select>
   <button type="submit" class="btn btn-default" translate="BUY"></button>
</form>

The url in the action field gets filled correctly.

The createOrder function in the controller is this:

$scope.createOrder = function () {
  Payment.start($scope.selectedProduct)
    .then(function (response) {
          $scope.orderNumber = response.data.orderNumber;
  });
};

The problem is that the hidden input orderNumber doesn't get filled before opening the actual action URL. Therefore the data that gets posted is incorrect.

Any thoughts on how to approach this? I'm using angularjs 1.2.16.

Upvotes: 1

Views: 1365

Answers (1)

jdmcnair
jdmcnair

Reputation: 1315

The issue is that Payment.start is setting $scope.orderNumber asynchronously on the resolution of a promise, but the form submit happens immediately. Normally you'd prevent the default action in an Angular based form by omitting the action attribute on the form, given that Angular is designed for a client-based application. But in your case you want the normal http post to take place, and that's unusual. That takes us on a trip outside "best-practices" land.

So, acknowledging that this is an unusual usage case, I'm going to offer a solution that's a little hackish. You could omit the action attribute from the form, then add it when the promise is resolved from Payment.start, and only then trigger the form submit:

$scope.createOrder = function () {
  Payment.start($scope.selectedProduct)
    .then(function (response) {
          $scope.orderNumber = response.data.orderNumber;
          var form = $('#form-id');
          form.attr('action', $scope.paymentUrl);
          form.submit();
  });
};

This is untested, but I think it should work for you.

Upvotes: 3

Related Questions