17

I am trying to access the form from the modal controller (Plunkr) but myForm doesn't seem to be accessible. How to get alert call to work:

angular.module('plunker', ['ui.bootstrap']);
var ModalDemoCtrl = function ($scope, $modal, $log) {
  $scope.open = function () {
    var modalInstance = $modal.open({
      templateUrl: 'myModalContent.html',
      controller: ModalInstanceCtrl          
    });       
  };
};

var ModalInstanceCtrl = function ($scope, $modalInstance) {
  $scope.submit = function() {
    // How to get this?
   alert($scope.myForm.$dirty);
  };

  $scope.ok = function () {
    $modalInstance.close();
  };

  $scope.cancel = function () {
    $modalInstance.dismiss('cancel');
  };
};

And template:

<div ng-controller="ModalDemoCtrl">
    <script type="text/ng-template" id="myModalContent.html">
        <div class="modal-header">
            <h3>I'm a modal!</h3>
        </div>
        <div class="modal-body">
          <form name="myForm" novalidate>
          <input type="email" value="hello">
          </form>
        </div>
        <div class="modal-footer">
            <button class="btn btn-primary" ng-click="submit()">OK</button>
            <button class="btn btn-warning" ng-click="cancel()">Cancel</button>
        </div>
    </script>

    <button class="btn" ng-click="open()">Open me!</button>
    <div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
cyberwombat
  • 38,105
  • 35
  • 175
  • 251

4 Answers4

18

Angular-UI modals are using transclusion to attach modal content, which means any new scope entries made within modal are created in child scope. This happens with form directive.

You can try to attach form to parent scope with (Angular 1.2.16):

<form name="$parent.userForm">

The userForm is created and available in modal's controller $scope. Thanks to scope inheritance userForm access stays untouched in the markup.

<div ng-class="{'has-error': userForm.email.$invalid}"}>
gertas
  • 16,869
  • 1
  • 76
  • 58
17

This was an known bug in ui-bootstrap. So injecting $modalInstance works fine now.

Workaround is to pass form instance to the submit function explicitly:

<form name="myForm" novalidate ng-submit="submit(myForm)">
  <div class="modal-header">
    <h3>I'm a modal!</h3>
  </div>
  <div class="modal-body">
    <input type="email" value="hello">
  </div>
  <div class="modal-footer">
    <button class="btn btn-primary" type="submit">OK</button>
    <button class="btn btn-warning" ng-click="cancel()">Cancel</button>
  </div>
</form>
var ModalInstanceCtrl = function ($scope, $modalInstance) {
  $scope.submit = function(myForm) {
   alert(myForm.$dirty);
  };
};
Micros
  • 5,966
  • 2
  • 28
  • 34
Stewie
  • 60,366
  • 20
  • 146
  • 113
2

In your controller add at the top:

$scope.form = {};

In the html template:

<form name="form.yourFormName">

Validation on html elements:

<div ng-class="{'has-error': form.yourFormName.email.$invalid}"}>

See also:

AngularJS modal dialog form object is undefined in controller

Community
  • 1
  • 1
Zymotik
  • 6,412
  • 3
  • 39
  • 48
  • Nice work-around - prevents angular from creating the form object on the transcluded scope, because it has already been inherited from the parent. – Dan King Apr 01 '16 at 09:25
  • 1
    Hmm - except if your controller's scope is also inheriting from a parent scope, then you might be overwriting an already-inherited form. I think this would be better: `$scope.form = $scope.form || {}` – Dan King Apr 01 '16 at 09:37
  • I meant "hiding", rather than "overwriting" of course - not likely to be a problem in most cases, but you never know... – Dan King Apr 01 '16 at 09:52
0

In the end I went with the answer given by gertas, but the following is another way of resolving this.

//place a method on modal controller scope

        $scope.setFormReference = function (myForm) {
            $scope.myForm = myForm
        };

//call this using an angular expression in your modal template

       {{ setFormReference(loginForm)}}
Kildareflare
  • 4,590
  • 5
  • 51
  • 65