4

The layout of my UI is a list (outlet "sub-navigation") / detail (outlet "outlet") as described in one of my previous questions.

The details sometimes contains a read-only version of the model and sometimes there's a "edit" data version rendered in the main outlet.

Ember page layout

One of my router's resources is a nested one:

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

Before I list the source code of my routes, let me explain my problem.

All works fine: I can open open the page with no offer, just the list. I view an offer and the offer is shown. I click on "edit offer" and I can edit and save the changes. After saving, in my controller I redirect (back) to the offer (read-only) page:

// in the save function:
var offer = this.get("content");
// ...
offer.on('didUpdate', function () {
    controller.transitionToRoute("offer", offer);
});
// ...
store.commit();

But the next page, which should be the offer detail, is empty. The page-title section still contains the template from the edit route and the main outlet is empty.

How can I let Ember re-render the OfferRoute template?

Here my routes which contain the various renderTemplate calls:

App.OffersIndexRoute = Ember.Route.extend({
    renderTemplate: function () {
        this.render('offer-list-title', { into: 'application', outlet: 'page-title' });
        this.render('offer-list-content', { into: 'application' });
    }
});

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

App.OfferRoute = Ember.Route.extend({
    setupController: function (controller, model) {
        controller.set('content', model);
        controller.set('offerTemplates', App.OfferTemplate.find());
        controller.set('contentBlockTemplates', App.ContentBlockTemplate.find());
    },
    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' });
    }
});

App.OfferEditRoute = Ember.Route.extend({
    renderTemplate: function () {
        this.render('offer-edit-title', { into: 'application', outlet: 'page-title', controller: 'offer' });
        this.render('offer-edit', { into: 'application', controller: 'offer' });
    }
})

UPDATE (solution)

With the help of the two answers below and a lo of try/error and debugging I got it working. I basically added an OfferIndexRoute, but I also had to define the model using this.modelFor("offer").

I don't know if this is the most elegant solution, but it works. So here is the routes code I'm using now:

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

App.OfferIndexRoute = Ember.Route.extend({
   model: function () {
      return this.modelFor("offer");
   },
   renderTemplate: function () {
      this.render('offer-title', { 
         into: 'application', outlet: 'page-title' });
      this.render('offer-content', { 
         into: 'application' });
   }
});

App.OfferEditRoute = Ember.Route.extend({
   renderTemplate: function () {
      this.controllerFor("offer").set("editMode", true);
      this.render('offer-edit-title', { 
         into: 'application', outlet: 'page-title', controller: 'offer' });
      this.render('offer-edit', { 
         into: 'application', controller: "offer" }); //
   }
})
Community
  • 1
  • 1
splattne
  • 102,760
  • 52
  • 202
  • 249

2 Answers2

2

Keep the model and setupController inside offerRoute and move the renderTemplate alone to offerIndexRoute.


    App.OfferRoute = Ember.Route.extend({
        setupController: function (controller, model) {
            controller.set('content', model);
            controller.set('offerTemplates', App.OfferTemplate.find());
            controller.set('contentBlockTemplates', App.ContentBlockTemplate.find());
        },
        model: function (params) {
            return App.Offer.find(params.offer_id);
        }
     });
    App.OfferIndexRoute = Ember.Route.extend({
    renderTemplate: function () {
        this.render('offer-title', { into: 'application', outlet: 'page-title' });
        this.render('offer-content', { into: 'application' });
    }
    });
Hyder
  • 1,463
  • 9
  • 14
  • Thanks for the suggestion. I had tried that before, but didn't work - I event get an empty offer page when loading the offer detail route (/#/offers/1234). Perhaps the root of the problem is that I use the OfferController also for edit (see the last line of my code)? – splattne Jun 08 '13 at 17:49
1

Render your offer (read-only) template in the App.OfferIndexRoute... Since App.OfferRoute is a resource (acts as parent for its nested routes), transtioning from OfferEditRoute to OfferRoute will be redirected to OfferIndexRoute...

App.OfferIndexRoute = Ember.Route.extend({
renderTemplate: function () {
    this.render('offer-title', { into: 'application', outlet: 'page-title' });
    this.render('offer-content', { into: 'application' });
}
});

Here is the one i tried out with just transitioning ... http://jsbin.com/uxojek/12/edit

selvagsz
  • 3,852
  • 1
  • 24
  • 34
  • Thank you very much for your effort putting together an example on jsbin. I haven't got much time to test it. I get an exception if I simply rename my OfferRoute to OfferIndexRoute. The model doesn't seem available when rendering the offer-content-template. Also, I'm not sure where I have to put the model (App.Offer.find(params.offer_id);) function etc. I'll take a closer look at it tomorrow. – splattne Jun 06 '13 at 19:13
  • With your solution I have a problem getting the model for rendering the content. I can't move the model function to the OfferIndexRoute because I won't get the params object which contains the "offer_id". – splattne Jun 07 '13 at 07:35
  • 1
    @ splattne Will update you after trying an example with models – selvagsz Jun 07 '13 at 14:10
  • I've accepted your answer, because it lead me to the solution. See my updated post for all the details I had to add. Thanks again! – splattne Jun 10 '13 at 09:18