Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ember.js: Back button doesn't refresh index view when using nested routes

Tags:

ember.js

http://jsfiddle.net/bugsinamber/xjvYk/6/

Setup

I have an index view with a list of stories. This gets rendered into the application outlet. When I click on each story, a story view gets rendered into the same outlet (replacing the index view). I'm using nested routes.

Issue

When I click on "all stories" to go back to index view from story view, it works fine. But if hit the browser back button to go back to the index view, the path changes to "/stories" correctly and yet the index view doesn't render. I have to hit the back button one more time for the index view to render.

The template

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

<script type="text/x-handlebars" data-template-name="stories">
    <p>Stories Index Page</p>    
    {{#each story in controller}}
    {{#linkTo "story"}}
    {{story.title}}
    {{/linkTo}}
    {{/each}}   
</script>

<script type="text/x-handlebars" data-template-name="story">
   {{#linkTo "index"}}Back to all stories{{/linkTo}}

   {{title}}    
    <p>Story test page</p>
</script>

The app.js

App = Ember.Application.create({});

App.Router.map(function() {
    this.resource("stories", function() {
        this.resource("story", {path: ':story_id'});
    }); 
});

App.StoriesRoute = Ember.Route.extend({
  model: function() {
    return App.Story.find();   
  }
});

App.StoryRoute = Ember.Route.extend({
  model: function(params) {
    return App.Story.find(params.story_id);
  },  
  renderTemplate: function() {
      this.render('story', {   // the template to render
          into: 'application' // the template to render into
      });   
  }
});

App.IndexRoute = Ember.Route.extend({
  redirect: function() {
    this.transitionTo('stories');
  } 
});

What I know so far

This works correctly if I don't use nested routes. Apparently I shouldn't use nested routes if I'm not nesting my views, but that limits the design needs. Logically, I should be allowed to use nested routes in this case.

I'm nesting the routes because I need to access "stories" from the story controller like shown below. If I don't nest the routes, then when I load the story view first (without loading the index view yet), then "posts" doesn't return anything.

App.StoryController = Ember.ObjectController.extend({
    needs: "stories", 
    previousPost: function() {
        return this.advancePost(1);
    },
    nextPost: function() {
        return this.advancePost(-1);
    },
    advancePost: function(delta) {
        var index, length, posts;
        posts = this.get('controllers.stories');
        length = posts.get('length');
        index = (posts.indexOf(this.get('content')) + delta + length) % length;
        if (index >= 0 && index < length) {
            return this.transitionToRoute('story', posts.objectAt(index));
        }

    }
});

Thanks in advance.

like image 294
bugsinamber Avatar asked Apr 30 '13 16:04

bugsinamber


1 Answers

Your routes should be nested according to your UI. stories and story template are not nested, so just do:

App.Router.map(function() {
  this.resource("stories");
  this.resource("story", { path: ':story_id' }); 
});

If you want the story URL to include stories, you can do:

  this.resource("story", { path: 'stories/:story_id' }); 

Next, you want to access all the stories in App.StoryController. That does not mean that it needs to be nested inside the stories resource, or that you need to use App.StoriesController.

You want to access the data, so get the data and set it in App.StoryController:

App.StoryRoute = Ember.Route.extend({
  setupController: function(controller, model) {
    controller.setProperties({
      model: model,
      stories: App.Story.find()
    });
  },
  model: function(params) {
    return App.Story.find(params.story_id);
  }
});

And keep the App.StoriesRoute route the same, as a separate route, that is not related to App.StoryRoute.

App.StoriesRoute = Ember.Route.extend({
  model: function() {
    return App.Story.find();   
  }
});
like image 116
Teddy Zeenny Avatar answered Nov 15 '22 15:11

Teddy Zeenny