Search code examples
ember.jsember-router

Emberjs Modal as a route


I am trying to figure out how to convert a route into a modal, such that you can navigate to it via any other route WHILE preserving underlying(previous) template.

For example:

http://example.com/site/index goes to index.hbs

http://example.com/site/page2 goes to page2.hbs

http://example.com/site/article/1234 goes to article.hbs if user comes from another domain(fresh start)

BUT http://example.com/site/article/1234 opens up article.hbs inside the "article-modal" outlet if user comes any other route.

Here is the router.js

Market.Router.map(function() {
this.route('index', { path: '/' });
this.route('start', { path: 'start' });
this.route('article', { path: 'article/:article_id' });
this.route('404', { path: '*:' });
});

here is application.hbs

<div class="main-container">{{outlet}}</div>
{{outlet "article-modal"}}

and here is article.js route Alternative case #1

Em.Route.extend({
beforeModel: function(transition, queryParams) {
    if(!Em.isEmpty(this.controllerFor('application').get('currentRouteName'))) {
        this.render('article', {
    into: 'application',
    outlet: 'article-modal'
  });
        return Em.RSVP.reject('ARTICLE-MODAL');
    }
},

model: function(params) {
    return this.store.find('article', params.id);
},

actions: {
error: function(reason) {
        if(Em.isEqual(reason, 'ARTICLE-MODAL')) { // ARTICLE-MODAL errors are acceptable/consumed
            //
            return false;
        }
        return true;
}
}
});

and here is article.js route Alternative case #2

Em.Route.extend({

renderTemplate: function() {
    if(!Em.isEmpty(this.controllerFor('application').get('currentRouteName'))) {
        this.render({into: 'index', outlet: 'article-modal'});
    } else {
        this.render({into: 'application'});
    }

},

model: function(params) {
    return this.store.find('product', params.id);
},
});

Problem with case #1 is that browser address bar does not reflect current route. If user goes from index route to article route the browser address bar still shows /index.. So if he presses back button app breaks.

Problem with case #2 is that it discards the contents of index.hbs because the article route is not nested.

Is it possible to even have such functionality with Ember?

Thanks :)


Solution

  • This is my second answer to this question. My original answer (https://stackoverflow.com/a/27947475/1010074) didn't directly answer OP's question, however, I outlined three other approaches to handling modals in Ember in that answer and am leaving it there in case it's helpful to anyone else.

    Solution: define multiple routes with the same path

    While Ember doesn't usually allow you to define two routes that use the same path, you can actually have a nested route and an un-nested route with the same effective path, and Ember works with it just fine. Building off of option 3 from my original answer, I have put together a proof of concept that I think will work for you. Here's a JS Fiddle: http://jsfiddle.net/6Evrq/320/

    Essentially, you can have a router that looks something like this:

    App.Router.map(function () {
        this. resource("index", {path: "/"}, function(){ 
            this.route("articleModal", {path: "/article"});    
        });
        this.route("article", {path: "/article"});
    });
    

    And within your templates, link to the index.articleModal route:

    {{#link-to "index.articleModal"}}View article!{{/link-to}}
    

    Since articleModal renders inside of index, your index route isn't un-rendered. Since the URL path changes to /article, a reload of the page will route you to your regular Article route.

    Disclaimer: I am unsure if this is exploiting a bug in current Ember or not, so mileage here may vary.