Search code examples
javascriptmeteoriron-router

Two collections displayed in the URL via iron:router?


I have two collections:

var Books = new Meteor.Collection("books");
var Chapters = new Meteor.Collection("chapters");

The Chapter collection has a propetry called bookId. So each chapter has a book and each book has many chapters.

This is the router:

Router.map(function() {
  this.route("bookList", {
    path: "/",
    data: function() {
      return Books.find({});
    }
  });
  this.route("bookPage", {
    path: "/books/:_id",
    data: function() {
      return Books.findOne(this.params._id);
    }
  });
});

So now when I open a book I get and URL like:

http://localhost:3000/books/TS23MTKrdpja2tCwq

But now I don't know how to modify the code so I can open a book's chapter and end up with an URL like:

http://localhost:3000/books/TS23MTKrdpja2tCwq/chapters/stwtwfd5tsrstfw

Any idea?

EDIT:

chapters/chapter_page.js:

Template.chapterPage.helpers({
  chapters: function() {
    Chapters.find({
      bookId: this._id
    }, {
      sort: {
        position: 1
      }
    });
  }
});

chapters/chapter_item.html:

{{#with chapter}}
  <h4><a class="open-chapter" href="{{pathFor 'chapterPage'}}">{{title}}</a></h4>
{{/with}}

Solution

  • You have to define a chapter route with two parameters.

    The _id in the chapter route obviously references the chapter, and the bookId property name must be the same as in the chapter collection for this to work.

    This will allow for something like :

    {{#with chapter}}
      {{! 1.0.0-pre2 syntax}}
      {{pathFor route="chapterPage"}}
      {{! 0.9.3 syntax}}
      {{pathFor "chapterPage"}}
    {{/with}}
    

    To compute automatically the chapter URL given a chapter document.

    Given that chapter is referencing a chapter document : our data function exposes a chapter property that is indeed a chapter document.

    EDIT :

    Your chapters is probably wrong because this._id probably references nothing at all (would need to use something like this.chapter.bookId or this.book._id). I would include the chapters as a property in the data result like this :

    this.route("chapterPage", {
      path: "/books/:bookId/chapters/:_id",
      data: function() {
        var chapter=Chapters.findOne(this.params._id);
        var book=Books.findOne(this.params.bookId);
        var chapters=Chapters.find({
          bookId:this.params.bookId
        },{
          sort:{
            position:1
          }
        });
        return {
          chapter:chapter,
          book:book,
          chapters:chapters
        };
      }
    });