AngularJS modal dialog form object is undefined in controller AngularJS modal dialog form object is undefined in controller angularjs angularjs

AngularJS modal dialog form object is undefined in controller


I had the same issue and could solve it by defining the form object in the scope of the modals controller. To get your code working put, for example, $scope.form = {}; in the beginning of your controller and change your form tag to <form name="form.invitation">. Afterwards $scope.form.invitation.$invalid should be filled.


Update Nov 2014: starting from angular-ui-bootstrap 0.12.0 transclusion scope is merged with the controller's scope. There is no need to do anything.

Before 0.12.0:

To put invitationForm directly in your parent controller scope you need to bypass transcluded scope this way:

<form name="$parent.invitationForm">

Above will automaticaly create form object in your parent controller. No need for pre-initialization stuff, long object paths or passing by event. Just access it with $scope.invitationForm once modal is opened.


The answer to the question of "Why?" is "scoping". tl;dr you created a new scope with the modal dialog which hid the scope's form object from your controller.

If we simplify your code, we roughly get the following:

<div ng-ctrl="organizeCtrl">  <modal-dialog>    <form name="invitationForm">      <input type="email" ng-model="invitation.email" placeholder="Enter email..." />      <input type="submit" ng-click="sendInvitation()" text="Invite!" />      <input type="button" ng-click="cancel()" text="Cancel  :(" />    </form>  </modal-dialog></div>

(This is a very simplified version which should still have all of the core components.) Now, let's look at where scopes are created and what is injected in them.

<div ng-ctrl="sendInvitationController"><!-- scope created above with "invitation" and "sendInvitation" from sendInvitationController -->  <modal-dialog>  <!-- scope created above for the modal dialog transclude -->    <form name="invitationForm">    <!-- add "invitationForm" to the modal dialog's scope -->      <input type="email" ng-model="invitation.email" placeholder="Enter email..." />      <input type="submit" ng-click="sendInvitation()" text="Invite!" />      <input type="button" ng-click="cancel()" text="Cancel  :(" />    </form>  </modal-dialog></div>

Here, you can see that there is a new child scope created at the <modal-dialog> element and that is where the invitationForm object is actually added. That is why you can't see the object in the sendInvitationController but you can see it on the buttons for ng-disabled. If you want to be able to access the form construct outside of the <modal-dialog> element (e.g. in the sendInvitationController) you will need to pass that in the function call:

<div ng-ctrl="organizeCtrl">  <modal-dialog>    <form name="invitationForm">      <input type="email" ng-model="invitation.email" placeholder="Enter email..." />      <input type="submit" ng-click="sendInvitation(invitationForm)" text="Invite!" />      <input type="button" ng-click="cancel()" text="Cancel  :(" />    </form>  </modal-dialog></div>

With the controller accepting the invitation form as a parameter to the sendInvitation function:

app.controller('sendInvitationController', ['$targetOrganisationId', '$scope', ...,  function ($targetOrganisationId, $scope, ...) {  $scope.invitation = {    targetOrganisation: {      id: $targetOrganisationId    }  };  $scope.sendInvitation = function (form) {    if (form.$invalid) {      return false;    }    // send the invitation...  };}]);

@Robin identified the other solution, specifically to create an object rooted in the scope of the sendInvitationController and then attach the form directly to that object, relying on Angular's scope traversal mechanism to find the form object on the scope outside of the <modal-dialog> and attach the form object to that. Note that if you did not specify $scope.form = {} in the sendInvitationController, Angular would have created a new object for form on the scope for the <modal-dialog> and you still would not have been able to access it in the sendInvitationController.

Hopefully this helps you or other people learning about Angular scoping.