Yeats
Yeats

Reputation: 2065

Why do I need to call a dynamic route ":_id" and not whatever I want?

Here's a rather standard way to set a route in Iron Router:

Router.route('/posts/:_id', {
  name: 'postPage',
  data: function() { return Posts.findOne({_id: this.params._id}) }
});

Experimenting around a little, beginner as I am, I tried:

Router.route('/posts/:whatever', {
  name: 'postPage',
  data: function() { return Posts.findOne({_id: this.params.whatever}) }
});

This works well, up to a point. True, whatever will scoop up whatever is after /posts/ as its value, and the data context will indeed be the same as before... but linking to specific posts now won't work!

So,

<a href="{{pathFor 'postPage'}}">{{title}}</a>

simply won't work doing it "my" way (linking to nothing at all).

I can't fully wrap my head around this, and I'm too much of a novice to grasp the source code for Iron Router, so my hope is that someone here can explain it in a manner that even a beginner like me can comprehend.

Preferably like something like this:

  1. First {{pathFor 'postPage'}} looks inside the routes to find the one named postPage.

  2. It sees that this route corresponds to /posts/ followed by something else.

  3. Looking inside the data context it finds that only one post is returned, namely the one with the same _id as whatever comes after /posts/.

  4. It understands that it should link to this post, cleverly setting the url to /posts/_id.

This is wrong, most likely, and it doesn't explain why it would work when whatever is turned into _id. But it would help me immensely to see it parsed in a similar fashion.

Edit: Cleaned up my question so it is easier to grasp.

Upvotes: 0

Views: 76

Answers (1)

stubailo
stubailo

Reputation: 6147

There's a simple set of circumstances that together lead to confusion:

  1. The Posts.findOne issue is explained by the fact that the first argument can be either a selector or a document _id. So it's not really a shortcut but rather a documented feature.
  2. As you found, putting :something in the iron:router URL causes that value to be reported as this.params.something inside the route function. This also registers something as an parameter to that route, which brings us to how pathFor works.
  3. The pathFor helper takes two inputs: first the name of the route (in this case 'postPage') and second an object of parameters, which can come either from the second argument as in {{pathFor 'postPage' params}} or from the data context like so: {{#with params}}{{pathFor 'postPage'}}{{/with}}.

Now, here's why passing in a document from the database works if you call the parameter _id but not if you call it whatever: the post object that you retrieved from the database _has an _id field, but it doesn't have a whatever field. So when you pass it into pathFor, it only passes along the correct _id if the parameter to the route also happens to be called _id.

Let me know if that makes sense, I agree that this is somewhat confusing and that this "shortcut" hides what exactly pathFor and params actually do.

Upvotes: 1

Related Questions