0

I have an index page with different courses. From that index page you can navigate to a specific course by a link-to. When I navigate to a course everything works fine but when I refresh the page or go to that URL directly the model is empty.

This is how my code looks like:

index.hbs ---------------------------------------
<div class="row">
<div class="col-md-6 col-md-offset-3 text-center">
    <h1>Become a Tjuna Fish</h1>
    <img src="http://placehold.it/500x300">
    <p>Leer met de technieken werken die bij Tjuna worden gebruikt en ontwikkel    jezelf tot een echte Tjuna Fish!</p>
   </div>
  </div>

  <div class="row">
    <h1 class="text-center">Cursussen</h1>
    {{#each}}
        <div class="col-md-4 text-center">
        <div class="row">
            <img {{bind-attr src="img"}}/>
        </div>
        <div class="row">
          {{#link-to "course" this}}{{title}}{{/link-to}}
        </div>
    </div>
    {{/each}}
    </div>

scripts ---------------------------------------
BecomeTjunaFish.Router.map(function () {
// Add your routes here
 this.resource('index', {path: '/'});
 this.resource('course', { path: ':url'});

});

BecomeTjunaFish.IndexRoute = Ember.Route.extend({
 // admittedly, this should be in IndexRoute and not in the
 // top level ApplicationRoute; we're in transition... :-)
 model: function () {
    return this.store.find('course');
 }

});

BecomeTjunaFish.CourseRoute = Ember.Route.extend({
 // admittedly, this should be in IndexRoute and not in the
 // top level ApplicationRoute; we're in transition... :-)
 model: function (params) {
    return this.store.find('course', params.id);
 }

});

BecomeTjunaFish.Course = DS.Model.extend({
 title: DS.attr('string'),
 img: DS.attr('string'),
 goal: DS.attr('string'),
 targetGroup: DS.attr('string'),
 prerequisites: DS.attr('string'),
 url: DS.attr('string')
});

BecomeTjunaFish.Course.FIXTURES = [
 {
  id: 1,
  title: 'Tjuna Basis',
  img: 'http://placehold.it/200x200',
  goal: 'kunnen werken met de basis tools en opmaaktalen die Tjuna gebruikt',
  targetGroup: 'frontend developers in wording',
  prerequisites: 'geen',
  url: 'basis_cursus'
 },
 {
  id: 2,
  title: 'Tjuna Frontend',
  img: 'http://placehold.it/200x200',
  goal: '',
  targetGroup: '',
  prerequisites: '',
  url: 'frontend_cursus'
 },
 {
  id: 3,
  title: 'Tjuna Backend',
  img: 'http://placehold.it/200x200',
  goal: '',
  targetGroup: '',
  prerequisites: '',
  url: 'backend_cursus'
 }
];

2 Answers2

1

You need to specify the dynamic segment as :id in your router. What happens is,

  1. When you transition via {{link-to}}, you pass the entire model object. Hence while retrieving the course model(this.store.find('course', params.id);) in route#model , you have the id with you and thereby fetching the model with no trouble.

  2. When you hit back or refresh the course page, all you have is the course url in the address bar URL. This course url (note the entire course object) will be passed to the course route#model hook where you try to retrieve using the id. Hence it blows up

So make your dynamic segment as id in the router to make it work. You can also fetch the records with name.

Working Jsbin

selvagsz
  • 3,852
  • 1
  • 24
  • 34
  • Great it works! This is exactly what I was looking for. I changed this.resource('course', { path: ':url'}); to this.resource('course', { path: ':id'}); Do you also know how to make the urls nested and dynamic without nested templates? Example: domain/#/:course/:lesson/:topic I looked at http://stackoverflow.com/questions/17012806/idiomatic-emberjs-for-nested-routes-but-non-nested-templates but couldn't figure out how to make it work for my app. – Alvin Vogelzang May 23 '14 at 15:06
0

As selvagsz explained, I had to change :url to :id in the router.

I also wanted to have nested URL's without nested templates. Something like this:

this.resource('index', {path: '/'});
this.resource('course', { path: ':course_id'}, function(){
  this.resource('lesson', {path: ':lesson_id'}, function(){
    this.resource('topic', {path: ':topic_id'});
  });
});

Problem with this is, when I go to course/lesson url the lesson template will only render when I have an outlet in the course template. I want the course template to be replaced with the lesson template but keep the same nested url.

I fixed this by using the renderTemplate function of Ember like this:

BecomeTjunaFish.LessonRoute = Ember.Route.extend({
  model: function (params) {
   return this.store.find('lesson', params.lesson_id);
  },
  renderTemplate: function() {
  this.render('lesson', { into: 'application'})
  }
});

This works great but when I navigate back, for example to course, it is not working anymore. Instead of only have a courseRoute I also needed a courseIndexRoute which uses the same model as courseRoute and place the renderTemplate in the CourseIndexRoute (same for LessonIndexRoute). Example:

BecomeTjunaFish.CourseRoute = Ember.Route.extend({
 model: function (params) {
    return this.store.find('course', params.course_id);
 }

});

BecomeTjunaFish.CourseIndexRoute = Ember.Route.extend({
 model: function () {
  return this.modelFor('course');
 },
 renderTemplate: function() {
   this.render('course', { into: 'application'})
 }

});

To me it seems to be a lot of code and I don't know if this is the right way to do this. At the moment this is good enough for me, it's working :) But I would appreciate it to have feedback on it and would like to know if there are other / better ways to fix this.

*I used this question as inspiration: Redirecting from edit to parent resource doesn't (re)render template

Community
  • 1
  • 1