19

I'm building a form that generates an invitation when submitted. The invitation has several fields, one of which is an email address input with an 'add' button, which when clicked should add that address to a list of email addresses that should receive the invite.

This can be done with a single form, however if the user hits the enter key while typing an email then it triggers submit on the whole form. I'd like to have the enter key result - when the email input field is focused - have the same effect as clicking the 'add' button. I expected that the proper way to solve this would be to nest an email entry form within the invitation form, something like this:

    <ng-form ng-submit="sendInvite()">
        <input type="text" placeholder="Title" ng-model="invitation.title"/>

        <ng-form ng-submit="addInvitee()">
            <input type="email" placeholder="Title" ng-model="inviteeEmail"/>
            <button class="btn" type="submit">add</button>
        </ng-form>

        <button class="btn" type="submit">Send</button>
    </ng-form>

With the following javascript in the controller:

    $scope.addInvitee = function() {
        $scope.invitation.emails.push($scope.inviteeEmail);
        $scope.inviteeEmail = '';
    }

    $scope.sendInvite = function() {
        //code to send out the invitation
    }

My problem is that having nested the forms (and in doing so converted from <form> to <ng-form>, submitting either one no longer works.

Plunker here

6
  • validate form and or provide a prompt ..."You are submitting ...." with a chance to cancel if they aren't done Commented Apr 10, 2013 at 22:12
  • Thanks, that's certainly a way to mitigate the issue but it's not ideal behavior. Commented Apr 11, 2013 at 13:20
  • could also prevent enter default when field in focus. Bind key handler to field and unbind on blur. Can't nest forms Commented Apr 11, 2013 at 13:26
  • A key handler might be the way to go. But what makes you say "can't nest forms"? ngForm was created specifically for that purpose. Commented Apr 11, 2013 at 14:11
  • my bad... was unaware of nesting capabilites of ng-form. New concept in html Commented Apr 11, 2013 at 16:02

3 Answers 3

8

I've similar requirement - wizard driven multi-step form. When user clicks 'Next' button, I've to validate the current step form.

We can trigger validation by firing '$validate' event on the scope bound to the form.

isFormValid = function($scope, ngForm) {
    $scope.$broadcast('$validate');
    if(! ngForm.$invalid) {
      return true;
    }
}

When ever I want to check if the form values are correct, I'll call isFormValid with the scope & form instance.

Working code: Plunker link

It is also useful to have few additional logic in isFormValid (included in the above Plunker) which makes the form & form fields $dirty as we would be showing/hiding validation messages based on their $dirty state.

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

2 Comments

Based on the plunker code I would recommend also toggling the $pristine state as it doesn't automatically shift when you set the $dirty field. Good work, thanks for the solution!
At the time of writing (AngularJS < 1.2), doesn't have an easy way to reset the $pritine state. We could reset the $pristine state of a particular control, or a form. But we also need to propagate that change if any of the other controls in it's form or it's parent form are also $pristine. This involves much more. From 1.2, there is a method for that: $setPristine(..).
8

You can use one of the following two ways to specify what javascript method should be called when a form is submitted:
* ngSubmit directive on the form element
* ngClick directive on the first button or input field of type submit (input[type=submit])
-- form docs

<ng-form>
   <input type="text" placeholder="Title" ng-model="invitation.title"><br>
   <ng-form>
     <input type="email" placeholder="Title" ng-model="inviteeEmail">
     <button class="btn" ng-click="addInvitee()">add</button><br>
   </ng-form>
   <ul class="unstyled">
     <li ng-repeat="invitee in invitation.invitees">
        <span>{{invitee.email}}</span>
     </li>
   </ul>
   <button class="btn" ng-click="sendInvite()">Send</button>
</ng-form>

Plunker

5 Comments

Thanks, this is an improvement from what I had but it doesn't respond to the enter key event at all. After some fiddling, it would appear that <form> and <ng-form> elements aren't as identical as the docs claim. I forked your Plunker to experiment with different form, ng-form and ng-submit configurations to no avail. Do you have an idea of how I could get the conditional response to the enter key event that I described originally? (Other than a key handler or custom directive)
@JamieA, sorry I missed the part about the enter key (I pulled up your Plunker and modified it, but I only tested clicking the buttons). I think you'll need to create a directive to get the functionality you want.
The inner submit is doing nothing here. It works due to the ng-click. Angular doesn't seem to want to work with submits on inner forms. A properly working submit can take advantage of ng-submit. The inner submit can not.
I wanna down vote this answer but i don't have enough points, like Marc said submit isn't doing anything it only works because of the ng-click.
I edited the answer and removed the type="submit" attributes from the two button elements.
0

When the form is submitted, you can find all nested forms using some thing like below

forms = []
forms.push(form)
nestedForms = _.filter(_.values(form), (input) -> (input instanceof form.constructor) and (input not in forms))

Here, form is the outer form controller which was submitted. You can hook this code on ur onsubmit, and find all nested forms and do whatever you have to.

Note: This is coffeescript

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.