Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angular-ui bootstrap $modal service using directive instead

The examples I see of using angular-ui/bootstrap's $modal always look something like this:

    $modal.open({
        templateUrl: 'modaltemplate.html',
        controller: function($scope) {
            ...
        }
    });

What if I want to use a directive, instead? Like this:

    $modal.open({
        template: '<my-modal-directive></my-modal-directive>'
        // no "controller" property; use directive's controller
    });

The markup for my-modal-directive renders fine, and I've moved the controller property into the my-modal-directive definition object, but now getting this error from the my-modal-directive:

Error: [$injector:unpr] Unknown provider: $modalInstanceProvider <- $modalInstance

Can anyone point me to an example where $modal uses a directive where that directive defines the controller?

For example, this works, where I've replaced the templateUrl with a directive:

http://plnkr.co/edit/YrGaF83GH6bzZPRR55GK?p=preview

But when I move the controller from $modal.open() into the directive, that's when the error happens:

http://plnkr.co/edit/aLBT239EpL004DRh4jll?p=preview
like image 689
core Avatar asked Feb 18 '15 16:02

core


2 Answers

The problem is that $modalInstance can only be injected in the controller that you provide to $modal.open. Check out the sources here:

$modal.open = function (modalOptions) {
    ...
    var modalInstance = {
        ...
    };
    ...
    if (modalOptions.controller) {
        ...
        ctrlLocals.$modalInstance = modalInstance;
        ...
        ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
        ...
    }
    ...
}

In essence when you try to add $modalInstance as a dependency to your controller AngularJS looks for a registered global provider named $modalInstanceProvider. Now the trouble is, if you understood the code above, that $modalInstance is not a globally registered provider. It only "exists" as a dependency for the controller you pass to $modal.open.

If you read the rest of the code you'll notice that $modal.open returns modalInstance, maybe you can use that.

Something like this:

function SomeController($modal) {
    $scope.modal = {
        instance: null
    };

    $scope.modal.instance = $modal.open({
        template: '<my-modal-directive modal="modal"></my-modal-directive>',
        scope: $scope
    });
}

function MyModalDirective() {
    scope: {
        modal: '='
    },
    link: function($scope) {
         // here you can access $scope.modal.instance
    }
} 
like image 120
Sergiu Paraschiv Avatar answered Sep 22 '22 06:09

Sergiu Paraschiv


The issue you have is that you are trying to inject values which are not available for injection. Only values registered with the injector can be injected.

The logic of you code is also flawed, you are creating the modal in your main controller but trying to close it in the directive. Ideally, the modal should be triggered by the directive (via it's link function), and then you can ok/cancel it from there.

See my http://plnkr.co/edit/3p1rXAymd7BilyklgxKy?p=preview for one possible approach, I have kept the code that closes and cancels the modal in the main controller.

    angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
angular.module('ui.bootstrap.demo').directive('myModal', function() {
    return {
        restrict: 'E',
        templateUrl: 'myModalContent.html',
        controller: function ($scope) {
          $scope.selected = {
            item: $scope.items[0] 
          };
        }
    };
});
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $modal, $log) {

  $scope.items = ['item1', 'item2', 'item3'];

  $scope.open = function (size) {
    var modalInstance;
    var modalScope = $scope.$new();
    modalScope.ok = function () {
            modalInstance.close(modalScope.selected);
    };
    modalScope.cancel = function () {
            modalInstance.dismiss('cancel');
    };      

    modalInstance = $modal.open({
      template: '<my-modal></my-modal>',
      size: size,
      scope: modalScope
      }
    );

    modalInstance.result.then(function (selectedItem) {
      $scope.selected = selectedItem;
    }, function () {
      $log.info('Modal dismissed at: ' + new Date());
    });
  };
});
like image 35
thedoctor Avatar answered Sep 20 '22 06:09

thedoctor