Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ember.js: How to refresh parent route templates in a nested route scenario?

Tags:

ember.js

My page layout (application template) looks like this (simplified):

Ember page layout

I use it for different routes (offer list + offer detail, customer list + customer detail). Lists are shown in the sub-navigation outlet.

My router's code:

App.Router.map(function () {
    //...
    this.resource('offers', function () {
        this.resource('offer', { path: '/:offer_id' });
    });
}

My Routes:

App.OffersRoute = Ember.Route.extend({
   model: function () {
       return App.Offer.find();
   },
   renderTemplate: function (controller, model) {
       this.render('offer-list', { 
           into: 'application', outlet: 'sub-navigation', controller: 'offers' });
       this.render('offer-list-title', { into: 'application', outlet: 'page-title' });
       this.render('offer-list-content', { into: 'application' });
   }
});

App.OfferRoute = Ember.Route.extend({
   model: function (params) {
      return App.Offer.find(params.offer_id);
   },
   renderTemplate: function () {
      this.render('offer-title', { into: 'application', outlet: 'page-title' });
      this.render('offer-content', { into: 'application' });
   }
});

Now this works so far.

http://.../#/offers

shows the list and the title "Offer summary" and static html content. I click on one of the offers in the list, going to

http://.../#/offers/23

all okay: it still shows the list of offers in the sub-navigation area and the correct title and the content of the offer.

Now my problem:

If I return to the

http://.../#/offers

page (using a #linkTo helper on a menu), then the {{outlet}} / content area becomes empty (not the static html from before) and the title is still the title in {{page-title}} of the offer/23 route.

How can I let my app "re-render" the template as defined in the OffersRoute renderTemplate()?

P.S.: I'm using Ember.js 1.0.0-RC.3

like image 263
splattne Avatar asked May 02 '13 16:05

splattne


1 Answers

Using the built-in Index routes and maintaining the ApplicationRoute -> OffersRoute -> OfferRoute hierarchy will solve your issue.

If you turn on the router transition logging you will see that when navigating to Offers you are actually entering the Offers.Index route:

App = Ember.Application.create({
  LOG_TRANSITIONS: true
});

This means that you can set your static Offers title and set the static Offers content in OffersIndexRoute and it will be correctly set the first time and set again if you link back to it from inside of an offer detail page. For this to work you also must preserve the ApplicationRoute -> Offers -> Offer {{outlet}} hierarchy by not directly rendering everything into the ApplicationRoute's {{outlet}}. The reason you must preserve this hierarchy is that by rendering the child (Offer template) directly into the Application template you remove the Offers template and when you try to go back to the OffersRoute its template has been removed and it shows nothing.

Index route

Use OffersIndexRoute to fill in the ApplicationRoute's {{outlet}} and the {{outlet page-title}}.

JS:

//this renders the title and the main content for Offers
App.OffersIndexRoute = Ember.Route.extend({
  renderTemplate: function (controller, model) {
    this.render('offer-list-title', { into: 'application', outlet: 'page-title' });
    this.render();
  }
});

App.OffersRoute = Ember.Route.extend({
   model: function () {
       return App.Offer.find();
   },
   renderTemplate: function (controller, model) {
     this.render('offer-list', { 
         into: 'application', outlet: 'sub-navigation', controller: 'offers' });
     
     // render this in OffersIndexRoute instead
     //this.render('offer-list-title', { into: 'application', outlet: 'page-title' });
     
     this.render('offer-list-content', { into: 'application' });
   }
});

Handlebars:

<script type="text/x-handlebars" data-template-name="offer-list-content">
  {{outlet}}
</script>

<script type="text/x-handlebars" data-template-name="offers/index">
  Offers content
</script>  

The outlet in the offers-list-content will be filled in by the OffersIndexRoute or by the Offer template, depending on what the current route is.

Maintaining {{outlet}} hierarchy

Allow the OfferRoute to render it's content template into the OffersRoute template instead of forcing it into the ApplicationRoute.

App.OfferRoute = Ember.Route.extend({
   model: function (params) {
      return App.Offer.find(params.offer_id);
   },
   renderTemplate: function () {
     this.render('offer-title', { into: 'application', outlet: 'page-title' });
     
     // preserve the hierarchy and render into the Offers {{outlet}}, which is the default
     //this.render('offer-content', { into: 'application' });
     this.render('offer-content');
   }
});

Working JSBin example

like image 200
CraigTeegarden Avatar answered Sep 25 '22 03:09

CraigTeegarden