0

I'm trying to get modals woking with angular bootstrap. I can launch the modal just fine, but I'm having some scope issues dismissing the modal.

When I launch the modal, I can specify a controller that I can call functions from, which works, but it seems to be a copy of the controller without a $parent and without any controller-local variables.

I need access to the return value of $uibModal.open() in order to close the modal, so I'm trying to store it in var modalInstance, which works fine when I'm within the scope of the controller, but the copy of the controller passed into the $uibModal service doesn't have the local variable modalInstance set.

I can get around this by storing the return object in the $rootScope, but that seems like a bad idea. Am I wrong? What's the best way to get access to modalInstance from the click handler passed into the $uibModal service? Can I avoid using the $rootScope?

var app = angular.module('main', ['ui.bootstrap']);

app.controller('MainCtrl', function($scope, $rootScope, $uibModal) {
  var modalInstance;

  $scope.launch = function() {
    console.log('launch');
    modalInstance = $uibModal.open({
      template: '<div>Modal Content - <a ng-click="close()">Close</a></div>',
      controller: 'MainCtrl',
    });

    // Wouldn't need to do this if I could access modalInstance in close handler
    $rootScope.modalInstance = modalInstance;
  }

  $scope.close = function () {
    console.log('close');
    console.log(modalInstance);

    // Works, but should I be using $rootScope like this?
    //$rootScope.modalInstance.close();

    // Doesn't work, modalInstance is undefined
    modalInstance.close();
  }
});

1 Answer 1

2

Angular instantiates a new instance of a controller whenever it is used, and it is the same for modal. So when you specify controller: 'MainCtrl' you're telling angular you want to instantiate one of those for your modal, which is rarely what you want.

Instead you should create a separate controller for the dialog, which can return values on closing using the $uibModalInstance service.

var app = angular.module('main', ['ui.bootstrap']);

app.controller('MainCtrl', function($scope, $rootScope, $uibModal) {
  var modalInstance;

  $scope.launch = function() {
    console.log('launch');
    modalInstance = $uibModal.open({
      template: '<div>Modal Content - <a ng-click="close()">Close</a></div>',
      controller: 'DialogCtrl',
    });
    ....

  }

});

app.controller('DialogCtrl', function($scope, $uibModalInstance) {
  $scope.theThingIWantToSave = [];
  $scope.cancel = function () {
    $uibModalInstance.close($scope.theThingIWantToSave);
  };
});
Sign up to request clarification or add additional context in comments.

4 Comments

This is a simplified example, but I have a bunch of functionality in the MainCtrl I want to reference from within the modal, which is why I want to use this controller instead of making a new one for the modal. Assuming I have scope functions in MainCrtl that I need to reference, what's the best way to handle this? Can I cross-reference some functions from MainCtrl, or am I better off with my original solution?
If you have functionality that you want to use outside of a controller you should really put that in a service. Controllers should only really provide bindings for the UI and handle UI events, everything else (data and logic) should belong in services.
Interesting, I find this a little counter intuitive, but I think I see what you're getting at. Do you know of any articles that go over the idea of wrapping general functionality in services?
Think of controllers as small disposable widgets that get glued to sections of the DOM, the real work happens in factories/services. Angular's concept guide is a good intro: docs.angularjs.org/guide/concepts Angular's docs can be difficult to navigate but it's really worth spending your time browsing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.