178

I have this AngularJS app. Everything works just fine.

Now I need to show different pop-ups when specific conditions become true, and I was wondering what would be the best way to proceed.

Currently I’m evaluating two options, but I’m absolutely open to other options.


Option 1

I could create the new HTML element for the pop-up, and append to the DOM directly from the controller.

This will break the MVC design pattern. I’m not happy with this solution.


Option 2

I could always insert the code for all the pop-ups in the static HTML file. Then, using ngShow, I can hide / show only the correct pop-up.

This option is not really scalable.


So I’m pretty sure there has to be a better way to achieve what I want.

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Bruno
  • 5,961
  • 6
  • 33
  • 52
  • numerous ways, controller for html defintiely not good way, look at UI Bootstrap Modal http://angular-ui.github.com/bootstrap/#/modal – charlietfl Apr 04 '13 at 13:28
  • 1
    AngularJS's docs explain a bit how to manage popups, under '[Understanding Transclusion and Scopes](http://docs.angularjs.org/guide/directive#understandingtransclusionandscopes)' section. Hope this helps. – Ivan Ferrer Villa Jul 01 '13 at 20:18
  • If you really want to scale with popups then check out [popscript](http://popscript.relfor.co). – Raj Nathani Apr 01 '14 at 01:50

5 Answers5

88

Based on my experience with AngularJS modals so far I believe that the most elegant approach is a dedicated service to which we can provide a partial (HTML) template to be displayed in a modal.

When we think about it modals are kind of AngularJS routes but just displayed in modal popup.

The AngularUI bootstrap project (http://angular-ui.github.com/bootstrap/) has an excellent $modal service (used to be called $dialog prior to version 0.6.0) that is an implementation of a service to display partial's content as a modal popup.

skeletank
  • 2,880
  • 5
  • 43
  • 75
pkozlowski.opensource
  • 117,202
  • 60
  • 326
  • 286
  • 10
    $dialog is now $modal – Sangram Singh Oct 10 '13 at 14:46
  • 1
    @pkozlowski.opensource I like ui-bootstrap's approach however I can't seem to transclude content with the modal. I've researched it some and see other folks have this issue as well. – jusopi Jul 11 '14 at 15:43
  • 2
    http://weblogs.asp.net/dwahlin/building-an-angularjs-modal-service I found this artical very useful. – RasikaSam Aug 11 '14 at 00:28
  • Just to mention, a service should not be accessing the DOM. A directive is the place for this. – superluminary Aug 18 '14 at 10:31
  • 1
    @superluminary this is indeed a good general rule to follow, but it is also god to know _why_ a certain rule is in pace and understand when such a rule can (or even should!) be broken. I believe that modals / tooltips and the like are exception to the rule. In short: one need to know rules but also understand the context where those apply / not apply. – pkozlowski.opensource Aug 18 '14 at 10:38
  • Interesting. I take it back. – superluminary Aug 18 '14 at 10:50
  • Hey this is great solution for creating modals. However I want to be able to also change the url when the modal is opened so that when I write that url in the address bar, the modal is opened with all the content in behind. How can I do this in addition to your answer? Any ideas ? – Dejan Bogatinovski Jun 02 '15 at 03:21
29

It's funny because I'm learning Angular myself and was watching some video's from their channel on Youtube. The speaker mentions your exact problem in this video https://www.youtube.com/watch?v=ZhfUv0spHCY#t=1681 around the 28:30 minute mark.

It comes down to placing that particular piece of code in a service rather then a controller.

My guess would be to inject new popup elements into the DOM and handle them separate instead of showing and hiding the same element. This way you can have multiple popups.

The whole video is very interesting to watch as well :-)

Jayantha Lal Sirisena
  • 21,216
  • 11
  • 71
  • 92
Bart
  • 17,070
  • 5
  • 61
  • 80
  • 2
    Misko is angular's seed! (bwa haha). Seriously tho. Regard his words as _the_ definitive source for angular. – deck Sep 06 '13 at 03:32
14
  • Create a 'popup' directive and apply it to the container of the popup content
  • In the directive, wrap the content in a absolute position div along with the mask div below it.
  • It is OK to move the 2 divs in the DOM tree as needed from within the directive. Any UI code is OK in the directives, including the code to position the popup in center of screen.
  • Create and bind a boolean flag to controller. This flag will control visibility.
  • Create scope variables that bond to OK / Cancel functions etc.

Editing to add a high level example (non functional)

<div id='popup1-content' popup='showPopup1'>
  ....
  ....
</div>


<div id='popup2-content' popup='showPopup2'>
  ....
  ....
</div>



.directive('popup', function() {
  var p = {
      link : function(scope, iElement, iAttrs){
           //code to wrap the div (iElement) with a abs pos div (parentDiv)
          // code to add a mask layer div behind 
          // if the parent is already there, then skip adding it again.
         //use jquery ui to make it dragable etc.
          scope.watch(showPopup, function(newVal, oldVal){
               if(newVal === true){
                   $(parentDiv).show();
                 } 
              else{
                 $(parentDiv).hide();
                }
          });
      }


   }
  return p;
});
Ketan
  • 5,861
  • 3
  • 32
  • 39
  • $watch instead of 'watch'. also shdn't it be 'popup' instead of 'showPopup' in `scope.watch(showPopup, function(newVal, oldVal){` ? – Sangram Singh Oct 10 '13 at 16:02
14

See http://adamalbrecht.com/2013/12/12/creating-a-simple-modal-dialog-directive-in-angular-js/ for a simple way of doing modal dialog with Angular and without needing bootstrap

Edit: I've since been using ng-dialog from http://likeastore.github.io/ngDialog which is flexible and doesn't have any dependencies.

Nik Dow
  • 584
  • 4
  • 10
  • 1
    I just did a quick sprint with this approach only to realize that this is great for a single popup/modal approach, however think of this particular UX: Say a customer is ordering an item, and the UI presents a confirm order popup (so we've 'occupied' Adam's popup with content). Now we click send or buy or whatever from that popup, and there is an error whereby the user needs to amend that order in the previous screen. I want to display that error in another popup at the top level. This approach doesn't facilitate this I don't believe. – jusopi Jul 11 '14 at 15:39
  • 3
    True but I think more than one popup might be a poor UI. – Nik Dow Oct 16 '15 at 14:20
  • well the plugin is the answer i was looking for! – Andres Felipe Oct 01 '16 at 16:51
7

Angular-ui comes with dialog directive.Use it and set templateurl to whatever page you want to include.That is the most elegant way and i have used it in my project as well. You can pass several other parameters for dialog as per need.

user2203937
  • 181
  • 1
  • 8
  • 5
    angular-bootstrap 0.6 onwards has replaced $dialog with $modal. That means you need to change all code that is using $dialog as it is deprecated and write it in $modal – Mohammad Umair Khan Sep 27 '13 at 06:27