1

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?

2
  • Do you have a submit button? Commented Jan 23, 2014 at 12:24
  • @Jayram Yes, clarified now. Commented Jan 23, 2014 at 12:32

5 Answers 5

2

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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.

6 Comments

Add a name attr to form like ie. <form name="myForm" ... > Then in controller $scope.myForm is your form that you simply POST using http to the correct URL.
I didn't know named forms ended up in the scope. Anyhow, the FormController does not have a method to submit itself? (And again, I cannot use $http to POST, as I need to redirect the browser)
You can redirect in the success handler of the POST. You can point the browser to any URL or switch it to any view/path that is local to your app. Is there a problem i am missing?
and on a general note, posting forms and reloading pages is definitely not Angular way. In doc:"Since the role of forms in client-side Angular applications is different than in classical roundtrip apps, it is desirable for the browser not to translate the form submission into a full page reload that sends the data to the server. Instead some javascript logic should be triggered to handle the form submission in an application-specific way. For this reason, Angular prevents the default action (form submission to the server) unless the <form> element has an action attribute specified."
Ok. Try plain old javascript then. Locate form and submit when ready. document.getElementById("myForm").submit(); No need to engage angular into that at all, other than use some ajax infrastructure then.
|
0

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.

1 Comment

I need to do a server API call (with some of the data from the form), to get the value of the field I need to send externally ("foo"). By preventing the form submit, I am effectively stopping the request for good.
0

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

3 Comments

I need to POST the actual form to the action specified, as I need to redirect the user. A POST using $http will not cut it.
So you would $location.path("/new-route") afterwards. I changed it in my answer.
It won't work. Note that I have to send the user to an external service, which accepts a single POST, and redirects the user back afterwards. I need a good old-fashioned form submit after I've gotten the data I need.
0

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.