user445670
user445670

Reputation: 179

Why is form object not available during controller initialization in angular?

Consider the following html

<div ng-app="myApp" ng-controller="myController">
    <form name="myForm"></form>
</div>

and controller file

(function () {
    'use strict';

    angular
        .module('myApp')
        .controller('myController', myController);

    myController.$inject = ['$scope', '$interval'];

    function myController($scope, $interval) {
        var myFormDetector = $interval(function() {
            if ($scope.myForm) {
                console.log('form exist');
                $interval.cancel(myFormDetector);
            } else {
                console.log('form not exist');
            } 

        }, 200)
    }
})();

I observe that form not exist at least prints once?

This is very curious as I thought that the order of rendering is

compile
controller
link

so by the time controller is intialized, compile should render the html and inject the $scope?

Am I getting anything wrong?

Upvotes: 0

Views: 127

Answers (1)

Dan
Dan

Reputation: 10538

The controller of the parent element will be created and linked before the child element. If you want the parent element to know about the child form, you probably want to do something like this:

<div ng-app='myApp' ng-controller='myController'>
  <form name='myForm' ng-init='myController.onInit()'>
  </form>
</div>
function MyController($scope) {
  this.$scope = $scope
}

MyController.prototype.onInit = function onInit() {
  this.$scope.myForm....
}

This isn't very sustainable though, and it's considered bad practice to use ngController like this. This pattern is common though, so common in fact that Angular has bindings for components for it (Angular 1.5+)

<div ng-app='myApp'>
  <x-parent-component>
    <form name='ngForm'>
    </form>
  </x-parent-component>
</div>
angular.module('myApp', [])
  .component('xParentComponent', {
    controller: XParentComponentCtrl,
    transclude: true,
    template: '<div ng-transclude></ng-transclude>'
  })

function XParentComponentCtrl($scope) {
  this.$scope = $scope
}
XParentComponentCtrl.prototype.$postLink = function $postLink() {
  this.$scope.myForm...
}

Are you sure you want to do this though? It probably indicates high coupling if your parent element talks to child elements like this. You should probably consider having the communication be the other way around; the child components tell the parent component about changes.

Upvotes: 1

Related Questions