Question

How can I prevent submitting a form in Angular until I receive a callback?

I have something along these lines:

<form method="post" action="http://example.com/external" ng-submit="submit()">
  <input type="hidden" name="foo" value="{{bar}}" />
  <input type="submit" />
</form>

Before submitting the form, I need to get the {{bar}} value from a local API call (using $http), and place it in the scope before allowing the actual form to submit (not POSTed using $http). How can this be done?

Was it helpful?

Solution

The form directive in Angular will wrap it in a formController and intercept it. You can still run your asynchronous code but you will need to reference the DOM form to submit it. I have an example fiddle with the solution - basically it sets up a button to submit the form, asynchronously sets the hidden field, then posts it.

Here is the relevant code:

MyController = function ($scope, MyService) {
            $scope.boo = "";
            $scope.submit = function () {
                MyService.getAsync().then(function(result) {
                    $scope.boo = result;
                    document.myForm.action = "http://example.com/";
                    document.myForm.submit();
                });
            };            
        };

If you run a fiddle you will see the hidden field is populated:

http://jsfiddle.net/jeremylikness/T6B2X/

The "ugly" part of the code is the direct reference to:

document.myForm

If you wanted to clean this up, you could write your own directive that allows you to place an attribute on the form and interacts with a service to manipulate it. I.e. MyFormService and then I could do MyFormService.setAction(url) and MyFormService.submit() - that would be more cleaner and reusable but time wouldn't permit me to set that up for you.

OTHER TIPS

As docs for ng-submit state:

Additionally it prevents the default action (which for form means sending the request to the server and reloading the current page) but only if the form does not contain an action attribute.

So remove that action attribute and handle it directly yourself in the submit() handler on the scope. Make yours http call and in then success handler submit the form manually.

Can you not just use the submit button's onClick event to call a function that returns false if the submit is not allowed?

i.e. onClick='return CheckIfFooPopulated();'

Then in that function return false is foo as not yet been set or true if it OK to submit.

The problem is that ng-submit doesn't work with an action attribute, as stated in the docs.

Then, you can do whatever you want inside of submit() in your controller. However, I would use ng-model for the form input fields because it gives you better control over the model.

You would use this $scope.formModel to bind the input fields to the scope.

You could implement submit like that:

$scope.submit = function() {
  $http.get("URL").success(function(data) {
    $http.post("URL2", { model: $scope.formModel, bar: data.bar }).success(function() {
       $location.path("/new-route");
    });
  });
}

There many possibilityes, but a less risky is to use ng-switch.

ng-switch do not load DOM if not needed.

    <span ng-switch on="barNotEmpty">
      <span ng-switch-when="true">
        <form method="post" action="http://example.com/external" ng-submit="submit()">
          <input type="hidden" name="foo" value="{{bar}}" />
        </form>
      </span>
      <span ng-switch-default>
        <form>
          <input type="hidden" name="foo" value="{{bar}}" />
        </form>
      </span>

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top