4

I'm very new to AngularJS, and new to client side programming.

Context:

I'm implementing a contact form with support for multiple phone numbers and addresses.

It look like this:

<form name="contactInsertForm" ng-controller="contactInsertController as contactCtrlr" ng-submit="contactInsertForm.$valid && contactCtrlr.save()">
    <input type="text" name="name" />
    <phones-editor></phones-editor>
    <addresses-editor></addresses-editor>
    <input type="submit" />
</form>

phonesEditor and addressesEditor are custom Angular directives which implement support for adding, removing and editing phones and addresses. The controllers and modules look like this:

Addresses:

(function () {
    var app = angular.module("AddressesEditorModule", []);
    app.directive("addressesEditor", function () {
        return {
            restrict: "E",
            templateUrl: "/addressesEditorTemplate.html",
            controller: function ($scope) {
                this.addresses = [
                    // this will hold addresses.
                ];

                // ...
            }
        }
})();

Phones:

(function () {
    var app = angular.module("PhonesEditorModule", []);
    app.directive("phonesEditor", function () {
        return {
            restrict: "E",
            templateUrl: "/phonesEditorTemplate.html",
            controller: function ($scope) {
                this.phones = [
                    // this will hold phones.
                ];

                // ...
            }
        }
})();

And the templates:

Addresses:

<!-- list already added addresses -->
<div ng-repeat="address in addressesEditorCtrlr.addresses">
    <p>{{address.address}}</p>
    <p>{{address.city}}</p>
</div>
<form name="addressInsertForm" ng-submit="addressInsertForm.$valid && addressesEditorCtrlr.add()">
    <!-- inputs for each of the address fields -->
    <input type="submit" value="Add" />
</form>

Phones:

<!-- list already added phones -->
<div ng-repeat="phone in phonesEditorCtrlr.addresses">
    <p>{{phone.number}}</p>
    <p>{{phone.areaCode}}</p>
</div>
<form name="phoneInsertForm" ng-submit="phoneInsertForm.$valid && phonesEditorCtrlr.add()">
    <!-- inputs for each of the phone fields -->
    <input type="submit" value="Add" />
</form>

As you may have noticed, the generated at the browser HTML looks like this:

<form>
    <input type="text" name="name" />
    <phones-editor>
        <!-- list already added phones -->
        <div ng-repeat="phone in phonesEditorCtrlr.addresses">
            <p>{{phone.number}}</p>
            <p>{{phone.areaCode}}</p>
        </div>
        <form name="phoneInsertForm" ng-submit="phoneInsertForm.$valid && phonesEditorCtrlr.add()">
            <!-- inputs for each of the phone fields -->
            <input type="submit" value="Add" />
        </form>
    </phones-editor>
    <addresses-editor>
        <!-- list already added addresses -->
        <div ng-repeat="address in addressesEditorCtrlr.addresses">
            <p>{{address.address}}</p>
            <p>{{address.city}}</p>
        </div>
        <form name="addressInsertForm" ng-submit="addressInsertForm.$valid && addressesEditorCtrlr.add()">
            <!-- inputs for each of the address fields -->
            <input type="submit" value="Add" />
        </form>
    </addresses-editor>
</form>

The problem:

I have two form's inside a form. The nested forms work correctly, adding and validating values it should be doing, and refusing to add invalid phones/addresses.

But when I click the submit button at the outer form, it will interpret the inner forms input fields and will raise errors if these fields have invalid values.

How can I use AngularJS form handling and avoid this situation? Is this possible at all?

3 Answers3

2

you would need a directive if you want child form as isolate form. Have a look at answers from this SO question. please have a look at fiddle attached in this answer. I am putting the fiddle link here for you to js-fiddle to see it in action.

putting below code just because SO doesnt accept only fiddle links...

<form name="parent">
    <input type="text" ng-model="outside"/>
    <ng-form name="subform" isolate-form>
        <input type="text" ng-model="inside"/>
    </ng-form>
</form>
Community
  • 1
  • 1
harishr
  • 17,807
  • 9
  • 78
  • 125
2

Working on Angular 1.6

const isolatedFormDirective = () => {
    return {
        restrict: 'A',
        require: '?form',
        link: ($scope, $element, $attrs, ctrl) => {
            ctrl && ctrl.$$parentForm && ctrl.$$parentForm.$removeControl(ctrl);
        }
    }
}

app.directive('isolatedForm', isolatedFormDirective);
Disfigure
  • 720
  • 6
  • 19
1

This article has exactly what you are looking for.

The basic gist is that you want to use the ngForm directive inside your form tag.

<div ng-form="outerForm">
  <input type="text" ng-model="main.outerFormText"/>
  <div ng-form="innerForm">
    <input type="text" ng-model="main.innerFormText" required/>
    <button type="button" ng-click="main.submit('innerForm')"
      ng-disabled="innerForm.$invalid">Inner Submit</button>
  </div>
  <button type="button" ng-click="main.submit('outerForm')"
    ng-disabled="outerForm.$invalid">Outer Submit</button>
</div>

Example plnkr

Brocco
  • 62,737
  • 12
  • 70
  • 76