Search code examples
ember.jsember-router

Ember.js Redirect to Template


I have a list of matches, and when I click one, I want to display the match. I know that I can do a Master-Detail style page, where when I click one, I can see the outlet somewhere on the same page, but that is not what I want.

I want it so that when I click on a link, it goes to an entirely new page for the match. I'm not really sure how to go about doing that.

Here is my route for #/matches (in coffeescript)

App.MatchesRoute = Ember.Route.extend(
  model: ->
    App.Match.find()
)

Here is my matches.handlebars

<div id="matches">
  {{#each match in controller}}
    {{#linkTo "match" match class="panel six columns"}}
      Match between {{match.player.name}} and {{match.opponent.name}}
    {{/linkTo}}
    <br />
  {{/each}}
</div>

// I know that if I have this outlet, it will render `match.handlebars`
// right here, but I want it to be it's own page.
// {{outlet}}

I've only been working with Ember for a few days, and all of the examples I've found use Master-Detail views.

Please let me know of any other information I can provide from my code.


Solution

  • <Edit date="March 11th 2013">

    I've pushed a this repository in GitHub. This is a conceptual app that uses renderTemplate somewhat the way you're describing.

    </Edit>

    In your child route, use the renderTemplate hook in order to tell your application to render a specific template in a specific {{outlet}}. Example:

    Source Fiddle

    App.Router.map(function() {
        this.resource('matches', { path: 'matches' }, function() {
            this.route('match', { path: 'match/:match_id' });
        });
    });
    
    App.MatchesRoute = Em.Route.extend({
        model: function() {
            return App.Match.find();
        },
        setupController: function(controller, model) {
            model = App.Match.find();
            controller.set('content', model);
        },
        renderTemplate: function() {
            this.render('matches', {
                into: 'application'
            })
        }
    });
    
    App.MatchesMatchRoute = Em.Route.extend({
        model: function(params) {
            return App.Match.find(params.match_id);
        },
        setupController: function(controller, model) {
            controller.set('content', model);
        },
        renderTemplate: function() {
            this.render('match', {
                into: 'application'
            })
        }
    });
    

    This MatchesMatchRoute is setup to render its template (matches/match) into the application template. And since there is only one {{outelet}} this template (see handlebars below), we don't have to specify anything:

    <script type="text/x-handlebars">
        <h1>App</h1>
        {{outlet}}
    </script>
    
    <script type="text/x-handlebars" data-template-name="matches">
        <h2>Matches</h2>
        <ul>
        {{#each match in controller}}
            <li>
                {{#linkTo matches.match match}}
                    {{match.title}}
                {{/linkTo}}
            </li>
        {{/each}}
        </ul>
    </script>
    
    <script type="text/x-handlebars" data-template-name="match">
        <h3>{{title}}</h3>
        <p>{{description}}</p>
    </script>
    

    If you have a scenario with multiple outlets, you have to hame them, like in the handlebars below:

    <script type="text/x-handlebars">
        <h1>App</h1>
        {{outlet main}}<br />
        {{outlet nested}}
    </script>
    

    Then your routes will have to specify the outlet as well. Example:

    Source Fiddle

    [...route code...]
    renderTemplate: function() {
    
        this.render('content', {
            into: 'application',
            outlet: 'main'
        });
    
        this.render('buttons', {
            into: 'application',
            outlet: 'nested'
        });
    
    }
    [...route code...]