Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular UI Bootstrap Modal doesn't work with ng-include

Live example: http://plnkr.co/edit/wWS3UFB3IZ0cAI4u2x04?p=preview

When "Open Modal 1" is clicked, the following error is thrown:

Error: Dialog.open expected template or templateUrl, neither found. Use options or open method to specify them.

However, Modal 2, which doesn't use ng-include, works fine.

Also, if ui-bootstrap-tpls-0.1.0.js is included instead of ui-bootstrap-tpls-0.2.0.js, all works fine.

Any ideas?

like image 717
Misha Moroshko Avatar asked Dec 15 '22 13:12

Misha Moroshko


2 Answers

I believe that this issue is a result of changing the modal directive to be terminal. This means that other directives (e.g. ng-include) will not be processed along with modal. Here's the commit that made this change:

https://github.com/angular-ui/bootstrap/commit/ec796ec2299d03ddfb821e97047c0329f11ab962#src/modal/modal.js

I honestly don't know enough about this to know exactly why this directive should be terminal, but one easy solution is just to use ng-include as a child of modal, rather than as a second directive acting on the same element. Here's what I mean:

<div modal="opened1">
    <ng-include src="'modal1.html'"></ng-include>
</div> 

Updated live example: http://plnkr.co/edit/KBBOn2T8cbeLfB0Su9jp

like image 180
jncraton Avatar answered Dec 26 '22 17:12

jncraton


I don't know what version of Angular-ui that was but the documentation for the modal windows remains confusing. While you can indeed use the ngInclude directive as part of showing a modal window, it is not necessary as shown below. In the case below, the modal html and script are in separate files and modal.open() is used to reference and display them. For some reason, I was only able to effect an updatable model when it was passed as a object property of the $scope..(see 'vm.' in code)

ModalView.html snippet

<!-- html elements reference the ModalViewCtrl decorated $scope -->
<input ng-model='vm.email' type='email' placeholder='Email address' autofocus />
<input ng-model="vm.password" type="password" class="form-control" placeholder="Password" />
<label class="checkbox">
    <input ng-model="vm.rememberMe" type="checkbox" />
    Remember me
</label>

ModalViewCtrl.js snippet

 angular.module('app')
   .controller('ModalViewCtrl', function($scope, $modal, parms) {

      /* decorate the $scope and/or preset the $scope.vm object
         as needed with parms.parm1, parms.parm2, ....
      */

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

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

   });

SourcePageCtrl.js snippet

 angular.module('app')
   .controller('SourcePageCtrl', function($scope, $modal, ...) {

      $scope.open = function() {
         var modalInstance = $modal.open({
            templateUrl: 'path_literal_to_ModalView.html'
            ,controller: 'ModalViewCtrl'
            ,resolve : {
                parms : function() { return {
                   parms1 : value1
                  ,parm2 : value2
                  ,...
                }}
            });

         modalInstance.result.then(
            function (vm) { 
                $scope.result = vm;
            } , function () {
                ... 
            }
         );

      });
   });

If you do want to use include, however, there are two gotchas.

  1. The 'templateUrl' must refer to the Id of the modal elements contain tag, such as the Id of the ngInclude itself as oppose to the URL of the template file.
  2. Because angular evaluates attribute values, if a literal is provided to the src attribute of path the element it must be in quoted inside the already quoted string:

like image 38
2 revs Avatar answered Dec 26 '22 19:12

2 revs