28

I have a subform that is shared among multiple views in my app. In one view, this subform is displayed alone with a back/continue button at the bottom that leads the user to the next subform. In another view, the subform is displayed on the same page as other subforms (basically one long form).

Since the html of the subform is 100% identical in both views, I separated it into a partial and am using ng-include to render it. In the view that displays only the subform with the back/continue buttons, I render the back/continue buttons within the parent's HTML.

Visually, everything works fine, and I'm able to access all of the data entered in the form (user.email, user.password, user.etc...).

The problem is that I'm enabling/disabling the "continue" button based on whether or not the user has completed the form correctly, and this does not work in the "subform-only" variation because the parent scope doesn't seem to be able to access the form's status. If I stick the buttons in the partial, it works, but I don't want to do that because the buttons don't belong there in every instance that this partial is being used.

JSFiddle Example

Notice in my example that the submit button within the red border is disabled until something is typed in the box and the "Form Invalid?" value updates, while the button within the blue border is always enabled and the "Form Invalid?" value is blank.

How can I access the value of myForm.$invalid from the parent scope?

Michael Moussa
  • 4,207
  • 5
  • 35
  • 53
  • 1
    Forms can nest in angular, and child form becoming invalid should make the parent form invalid. But you don't seem to have an outer form surrounding your ng-included form... – jpsimons Apr 05 '13 at 03:08
  • Nesting
    tags is not valid HTML: http://stackoverflow.com/questions/4519485/can-i-nest-form-tags-in-other-form-tags. Though it technically works in the fiddle, it will behave unpredictably depending on the browser (example: Chrome just eats the inner form and gets rid of all the styling).
    – Michael Moussa Apr 08 '13 at 20:03

2 Answers2

25

The child scope created when you use ng-include is hiding the form functions from the parent.

In addition to using a directive, you can also add an object in the parent, but it's important to set the name of the form to an object with a property like so:

<form name="myFormHolder.myForm">

and in the parent controller

$scope.myFormHolder = {};

then the following should work:

$scope.myFormHolder.myForm.$pristine

This way when the form is evaluated, myForm.$valid will get set on the parent. I believe I asked this same question: Why form undefined inside ng-include when checking $pristine or $setDirty()?

Community
  • 1
  • 1
Scott Driscoll
  • 2,869
  • 2
  • 23
  • 22
  • 1
    this seems more like the acceptable answer. very helpful thanks! – gabereal Jul 23 '15 at 20:18
  • This fixed my issue perfectly. I have html templates populated via a directive connected to a ng-repeat, each a child scope of the main. This was a great solution to get validation to show up. – mortey Dec 09 '15 at 20:52
  • This is pretty clean way to do it. – Skrew May 23 '17 at 15:57
15

If it's a sub-form you can just move the form-tag from the sub-form and into the main-form: updated JSFiddle

You could also nest your forms using the ngForm-directive:

In angular forms can be nested. This means that the outer form is valid when all of the child forms are valid as well. However browsers do not allow nesting of elements, for this reason angular provides ngForm alias which behaves identical to but allows form nesting.

The result is a bit messy imo. I'd rather create a 'myForm'-directive with a new scope to avoid using $parent - something like:

myApp.directive('myForm',function(){
    return{ 
        restrict:'E',
        scope:{model:'='},
        templateUrl:'/form.html',
        replace:true
    }
});

- see this JSFiddle example

joakimbl
  • 18,081
  • 5
  • 54
  • 53
  • 3
    The first option won't work for me because it's a multi-page form where each "subform" needs to be validated independently. However, nesting with the `ng-form` directive in attribute form (instead of nesting actual `
    ` tags) works perfectly! The `$parent` part was just a bad example - I have an actual object that it binds to. Here is a better example with the complete solution I'll be using: [JSFiddle](http://jsfiddle.net/BLVcG/2/). Thanks!
    – Michael Moussa Apr 09 '13 at 14:29
  • Aha... but what if your form is inside a modal dialog box and you can't have an outer form? – Ian Warburton Aug 21 '13 at 19:46
  • 2
    I think this a real weakness in Angular. They've put the validation on the form elements and not the model. So if you want to define multiple forms for the same model you've got to repeat all of the validation logic. – Ian Warburton Aug 21 '13 at 19:54