9

I'm invoking a bootstrap modal dialog through a link.

I want to start a timer in the angular controller when the dialog pops up. How do I detect the dialog open event in the angular controller to start the timer?

If I start timer in the scope like this,

app.controller('myctrl',
    ['$scope', '$window', '$timeout', 'svc',
    function ($scope, $window, $timeout,  svc) {

        $scope.countdown = 10;

        $scope.runCounter = function () {
            $scope.countdown -= 1;
            if ($scope.countdown > 0)
                $timeout($scope.runCounter, 60000);
       }
        $scope.runCounter();
    }]);

the timer starts when the application starts. I want the timer to start only when the dialog opens. Thanks.

user2793135
  • 163
  • 1
  • 2
  • 8

4 Answers4

78

Check this out.

var modalInstance = $modal.open({...});
modalInstance.opened.then(function() {
    alert("OPENED!");
});

The $modal.open() returns an object that, among other properties contains the opened promise, to be used as above.

Nikos Paraskevopoulos
  • 39,514
  • 12
  • 85
  • 90
  • 6
    This is the correct answer, should be the accepted answer. Ashish's answer above is really more of a hack – Michael Manoochehri Sep 15 '14 at 05:12
  • What if it's not opened ? It'll give 'TypeError: Cannot read property 'opened' of undefined' ? Do you have a solution for that ? – Sampath Jan 26 '15 at 13:08
  • 1
    If there is a chance the modal will not open, just add an `if( modalInstance )` before the line. – Nikos Paraskevopoulos Jan 26 '15 at 13:12
  • I wanted to use this to focus on the element in the modal, but it looks like even the `opened` event is not late enough, so i hacked it by setting a 200 ms `$timeout` in the opened event – Michael Feb 25 '15 at 15:22
  • I have a similar issue. At `opened`, I have no access to any `$("myfoo")` inside the modal yet. – Giszmo Mar 10 '15 at 19:03
  • 4
    Use the `rendered` event rather than `opened` if you need access to the DOM inside the modal dialog. – jammycakes Nov 30 '15 at 16:33
  • Ok, but what if I want to do some stuff on any modal open. How do I register a global 'opened/rendered' promiss? – user1278890 Oct 16 '16 at 23:15
4

I assume that you are using modals from http://angular-ui.github.io/bootstrap/.

If you look closely you will see that the component expose a promise that will be resolved when the dialog is opened. Which is what you will need to use. You can do something like that in the controller where the modal is created:

$scope.runCounter = function () {
  $scope.countdown -= 1;
  if ($scope.countdown > 0)
    $timeout($scope.runCounter, 60000);
}

//Creating the dialog
var modalInstance = $modal.open({
  templateUrl: 'myModalContent.html',
  controller: ModalInstanceCtrl
  }
});

//Add a function for when the dialog is opened
modalInstance.opened.then(function () {
  $scope.runCounter 
});

See working plunker here

Nicolas ABRIC
  • 4,925
  • 28
  • 18
  • Tried the same. But $modal is not opening the dialog. Isn't it possible to call $modal from an angular service? $modal.open({ template: "

    {{countdown}}

    ", controller: 'myctrl' }); controller is instantiated but dialog not opening.
    – user2793135 Nov 15 '13 at 13:01
0

 var modalInstance = $modal.open({
                templateUrl: '../augustine_app/templates/program_purchase_popup.html',
                backdrop: 'static',
                controller: function ($scope, $modalInstance) {
                    $scope.cancel = function () {
                        $modalInstance.dismiss('cancel');
                    };
                }
            });

            

            if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
                modalInstance.opened.then(function () {
                    var modal;
                    var getModalInterval = function () {
                        modal = document.getElementsByClassName('modal')[0];
                        if (modal) {
                            clearInterval(getModal);
                            modal.style.marginTop = window.screenTop + 'px';
                            modal.style.height = 'auto';
                            modal.style.position = 'absolute';
                            modal.style.overflow = 'visible';
                        }
                    };
                    modal = document.getElementsByClassName('modal')[0];
                    if (!modal) {
                        var getModal = setInterval(getModalInterval, 2000);
                    }
                });
            }
        };

Unfortunatly the open.then(func) runs before the freaking modal is actually in the DOM. Hence the setInterval.

here is some non jQuery angular code.

0

For my case, I need to be able to detect when modal is opened inside the modal controller itself.

At first opened promise was resolved even though the modal hasn't been loaded in the DOM yet. By wrapping the call inside a $timeout, opened promise is now resolved after the modal is loaded to the DOM.

$modal.open({
  templateUrl: 'modalTemplate.html',
  controller: 'modalCtrl'
});

// inside modalCtrl
angular.controller('modalCtrl', ['$modalInstance', '$timeout', function($modalInstance, $timeout) {
  $timeout(function() {
    $modalInstance.opened.then(function() {
      //do work
    });
  });
}]);
chy600
  • 175
  • 3
  • 8