Opening the same dialog multiple times with $dialog

Problem

I created this plnkr when answering this question 'AngularJS - open controller in a dialog (template loaded dynamically)'.

All the example app does is launch a dialog box based on a template, with it's own controller. The first time the dialog launches, everything works as expected. However, if I try and re-launch the dialog, after dismissing it, the modal backdrop is shown but no dialog. In the javascript console you can see that the then method on the promise returned by $dialog.open() is called immediately, but the backdrop isn't removed and no errors are reported. I'm completely baffled.

The dialog can be opened and closed repeatedly on the angular-ui bootstrap documentation page.

Where did I go wrong?

HTML:

<!DOCTYPE html>
<html ng-app="plnkr">

  <head>
    <link data-require="bootstrap-css@*" data-semver="2.3.2" rel="stylesheet" href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" />
    <script data-require="angular.js@1.0.7" data-semver="1.0.7" src="http://code.angularjs.org/1.0.7/angular.min.js"></script>
    <script data-require="ui-bootstrap@0.3.0" data-semver="0.3.0" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.3.0.min.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>
    <div ng-view></div>
  </body>

</html>

JS:

app.controller("DemoCtl", ["$scope", "$dialog", function($scope, $dialog){
  $scope.launch = function() {
    var d = $dialog.dialog({
      backdrop: true,
      keyboard: true,
      backdropClick: true,
      templateUrl: "dialog.html",
      controller: "DialogCtl"
    });

    d.open().then(function(result) { console.log("d.open().then"); });
  };
}]);
Problem courtesy of: Jason

Solution

I've found the issue. It has to do with using an <a> tag to open the dialog. Clicking on the <a> tag causes a location change to be fired. The dialog handles location change by closing itself as you can see below.

  this.handleLocationChange = function() {
    self.close();
  };

I'm not sure why this doesn't happen on the first click of the <a> tag, but it definitely happens on all subsequent calls.

You can see in this plunker that if you use a button, it opens correctly each time.

Hope this helps! I'll try to figure out why it doesn't break on the first time.

EDIT

The location change is actually really bad. It appears to be looping, to what I believe is the angular maximum of 10 digests. Still not sure why it doesn't do a location change on the first click.

Solution courtesy of: Mark Meyer

Discussion

It looks like if you put "javascript:;" in the href, then it works fine for the <a> tag.

Like this:

<a href="javascript:;" ng-click="launch()">Open the dialog</a>

Also, the <a> tag issue seems to be browser related.

Discussion courtesy of: Max Weng

The trouble is indeed with the tag. Jason mentioned that he expected that the angular directive would stop the location change. This is so, but it needs the href to be blank. the plunker was

<a href="javascript:;" ng-click="launch()">Open the dialog</a>

and should have been

<a href="" ng-click="launch()">Open the dialog</a>

When I changed the plunker to that effect everything seemed okay

Discussion courtesy of: SystemsGuy

This recipe can be found in it's original form on Stack Over Flow.