1

I wrote an AngularJS directive with a form. The form has a required text field as well as two other forms. Each of them child forms has another required text field.

The difference between the 2 child forms is how I create them:

  1. The first child form is compiled and appended to a div.
  2. The second child form is directly included in the template of the directive.

If the second child form is invalid, the whole outter form becomes invalid. This is what I expected. However, if the first child form (the one I compiled manually) becomes invalid, it has no influence on the outter parent form. Why?

enter image description here

var app = angular.module('plunker', []);

app.component('generator', {
    template: "<ng-form name=\"outterForm\">" + 
                  "<input name=\"out\" ng-model=\"$ctrl.out\" ng-minlength=\"5\" ng-required=\"true\" type=\"text\" />" + 
                  "<div id=\"component-container\"></div>" +
                  "<my-text></my-text>" +
                  "<div>Valid outterForm: {{outterForm.$valid}}</div>" +
              "</ng-form>",
    controller: function($compile, $scope, $document) {
        var componentContainer = $document.find('#component-container');
        var template = "<my-text></my-text>";
        var childScope = $scope.$new();
        var result = componentContainer.append(template);
        $compile(result)(childScope);
    }
});

app.component('myText', {
    template: "<ng-form name=\"innerForm\"><input name=\"name\" ng-model=\"$ctrl.name\" ng-minlength=\"5\" ng-required=\"true\" type=\"text\" />Valid innerForm: {{innerForm.$valid}}</ng-form>"
});

Here's the running Plunker:

https://plnkr.co/edit/YfBRY4xPvKgqDtWXFMUi

Thomas Uhrig
  • 30,811
  • 12
  • 60
  • 80

1 Answers1

1

That's because $$parentForm of sub-form's formController hasn't been set after you compile that sub-form. And I don't know why, it needs more deep knowledge I suppose.

I tried to $compile()() in different compilation stages (preLink, postLink) and had same result. However I almost achieve the goal with two methods:

  • First is to assign $$parentForm directly like this childScope.innerForm.$$parentForm = scope.outterForm;. Here is my plunker example (notice I changed components to directives, cause they are more flexible).
  • Second is to recompile parent form (but this makes useless manual sub-form compilation). Here is the second plunker example.

But! In both methods there is one huge problem - setting sub-forms names and models dynamically (it should be so, cause you want to use one directive on multiple sub-forms).

In first method there is no errors, but one bug: when you change model of the second sub-form it changes model of the first one (it stops when you once adjust model of the first sub-form).

In the second method everything seems to work fine, but at backstage there are a lot of errors occurs each time you change model.

GProst
  • 9,229
  • 3
  • 25
  • 47
  • Thanks a lot for your explanation! I also discovered one more thing: If you put a normal HTML form around everything, this form behaves as expected and only becomes valid if all child forms are valid. Here's the Plunker if your're interested: https://plnkr.co/edit/YfBRY4xPvKgqDtWXFMUi – Thomas Uhrig Jan 20 '17 at 10:04
  • If you change your new outer form to `ng-form` it will work too =) I think the thing is to have child directives to be compiled before parents in order to work correctly. All sub-forms have been already compiled before the outer one starts to. – GProst Jan 20 '17 at 10:15
  • `ngForm` is a dynamic form part and needs a parent `
    ` tag, isn't a form itself. Nest `ngForms` will work too, due to the nature of this directive, which looks for a reference to belong to, but the lower reference, being a `ngForm` too, will need a parent reference too. So, the relation between them only work because they can belong to a parent. The correct way to use is setup a form, nest its `ngForm` parts conditionally and even manually compiled ones will work. But, just wondering: is it just an experiment? Why do you need to compile something like that manually?
    – Mateus Leon Jan 20 '17 at 15:58
  • 1
    @MateusDuartePoncedeLeon I try to build an application which generates a big form based on an external configuration which comes as JSON from the backend. That's the background of my question :) – Thomas Uhrig Jan 23 '17 at 15:18