2
votes

So I am trying to figure out how best to put modals on a route, such that you can navigate to them via the url.

application.hbs

{{outlet}}

{{outlet modal}}

There is a discussion here and emberjs cookbook provides another example but nothing covers how you can have modals on a specific route.

The closest thing I have seen is this Stack Overflow question but it suffers from two problems:

  1. When the modal route is visited, the view in the main outlet gets destroyed. So in your UI, things underneath the modal get wiped out.
  2. history.back() is that you essentially revisit that route causing that view to be redrawn and feels very hackish.

This is where I feel a solution would exist but not sure what exactly:

App.MyModalRoute = Ember.Route.extend({

renderTemplate: function(controller, model) {

  /**
   * When my modal route is visited, render it in the outlet
   * called 'modal' but somehow also persist the default outlet.
   **/
   this.render({ outlet: 'modal' });   
} 

});

2

2 Answers

8
votes

Here is how we handle it:

In the route you use a render piece similar to what you described:

App.UserDeleteRoute = Ember.Route.extend({
  renderTemplate: function() {    
    this.render({
      into: 'application',
      outlet: 'modal'
    });    
  },

  actions: {
    closeModel: function() {
      this.transitionTo('users.index');
    }
  },
  deactivate: function() {
    this.render('empty', {
      into: 'application',
      outlet: 'modal'
    });
  }  
}

Clearing out outlet on the "deactivate" hook is an important step.

For the main template all you need is:

{{outlet}}
{{outlet "modal"}}

This does not override the default outlet.

One thing you may want to do for all your modals is implement a layout:

App.UserDeleteView = Ember.View.extend({
  layoutName: 'settings/modals/layout',
  templateName: 'settings/modals/user_delete'
});

Another gotcha is that there needs to be a parent route rendered into the main outlet. If whatever is in that outlet is not the parent of your modal, then the act of moving away from that route will remove it from the outlet.

working JS bin

2
votes

You've got several options here:

  • make modal route child of route you want to persist - than either render modal nested in application template, like in example you mentioned, or put it inside its own template id="myModal"
  • add modal outlet inside persisted route's outlet and render it in renderTemplate method

    renderTemplate: function(controller, model) {
        this.render();   //render default template
    
        this.render('myModalTemplate', { //render modal to its own outlet
            outlet: 'modal', 
            into: 'myModal', //parent view name. Probably same as route name
            controller : controller
        });
    }
    

Besides, you can render template with modal in named outlet any moment(on action f.e.), by just calling render method with proper arguments