Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the right way to enter and exit modal states with Ember router v2?

I can't figure out the correct way to handle modal states/views with the new Ember router. More generally, how do you handle states that you can enter and exit without affecting the "main" state (the URL)?

For example, a "New Message" button that is always available regardless of the current leaf state. Clicking "New Message" should open the new message modal over the current view, without affecting the URL.

Currently, I'm using an approach like this:

Routes:

App.Router.map(function() {
   this.route('inbox');
   this.route('archive');
});

App.IndexRoute = Em.Route.extend({
  ...
  events: {
    newMessage: function() {
      this.render('new_message', { into: 'application', outlet: 'modalView' });
    },

    // Clicking 'Save' or 'Cancel' in the new message modal triggers this event to remove the view:
    hideModal: function() {
      // BAD - using private API
      this.router._lookupActiveView('application').disconnectOutlet('modalView');
    }
  }
});

App.InboxRoute = Em.Route.extend({
   ...
   renderTemplate: function(controller, model) {
     // BAD - need to specify the application template, instead of using default implementation
     this.render('inbox', { into: 'application' });
   }
});

App.ArchiveRoute = ... // basically the same as InboxRoute

application.handlebars:

<button {{action newMessage}}>New Message</button>
{{outlet}}
{{outlet modalView}}

I've obviously left out some code for brevity.

This approach 'works' but has the two problems identified above:

  1. I'm using a private API to remove the modal view in the hideModal event handler.
  2. I need to specify the application template in all of my subroutes, because if I don't, the default implementation of renderTemplate will attempt to render into the modal's template instead of into application if you open the modal, close it, and then navigate between the inbox and archive states (because the modal's template has become the lastRenderedTemplate for the IndexRoute).

Obviously, neither of these problems are dealbreakers but it would be nice to know if there is a better approach that I'm missing or if this is just a gap in the current router API.

like image 407
Nick Ragaz Avatar asked Jan 14 '13 22:01

Nick Ragaz


People also ask

How to generate route in Ember?

Basic Routes. The map() method of your Ember application's router can be invoked to define URL mappings. When calling map() , you should pass a function that will be invoked with the value this set to an object which you can use to create routes.

Can you transition in Ember?

A Transition is a thennable (a promise-like object) that represents an attempt to transition to another route. It can be aborted, either explicitly via abort or by attempting another transition while a previous one is still underway. An aborted transition can also be retry() d later.


1 Answers

We do kind of the same thing but without accessing the private API. I don't know if our solution is a best practice, but it works.

In the events of our RootRoute I have an event (same as your newMessage), where we create the view we need to render, and then append it.

events: {
    showNewSomething: function(){
        var newSomethingView = app.NewSomethingView.create({
            controller: this.controllerFor('newSomething')
        });
        newSomethingView.append();
    }
}

This appends the modal view into our app. On cancel or save in the newSomethingView we call this.remove() to destroy the view and removing it from the app again.

Again, this doesn't feel like a best practice, but it works. Feel free to comment on this if someone have a better solution.

like image 91
TommyKey Avatar answered Sep 19 '22 23:09

TommyKey