• Meteor

Routing with Parameters

So far, our app has been pretty simple. We only have one route for the root URL. What I'd like to do is to create another route so that when we click on a To Do, we go to a Details page for that To Do. And the Details page can allow us to edit the To Do, but also to have comments from other users.

So to start off, I'll create another route. And this time, the route is going to have a parameter in it that we'll use to get the ID for the particular To Do that we're on. So I'm going to do this by hand this time. And I'll create a route by calling the route method.

And this time, the URL is going to be To Dos and then a parameter. So parameters always start with this colon. And that way, we can reference this parameter by name later. And the actual value in the URL will be the ID of the particular To Do that we're working with. We can give this route whatever name we want, but I'm going to give it To Dos Detail, a name of To Dos Detail. And we'll create a new controller for it called To Dos Controller.

You can organize this however you'd like, but I'm going to put all the To Dos related stuff moving forward into this controller. The function we'll call on the controller will be called Details. And just for documentation purposes, we'll explicitly say that this is a client side route.

Next step, I will use Iron Scaffolding to create the controller itself. I'm going to call this To Dos controller. So if we come over up into the Controllers folder, we now have this To Dos controller, and we can set it up. So in the Action function, I'm going to change that to Details. And what we're going to render is To Dos Detail. And then we can clean up this class a little bit.

OK. Let me just double check. It was To Dos detail. Let's just rename this to Detail. It will make more sense. And then we just need to create this template, To Dos Details. So I'll use the Iron Scaffolding tool again, and we'll generate a template under the To Dos folder called To Dos Detail.

Now when we navigate to this route, this function will get called, and the To Dos detail template will get rendered. Let's just make sure it got created properly. So we'll go into the Client folder under To Dos and refresh, and there we go.

Next up, we need to actually make these To Dos link so that we can navigate to the page. So let's open up the To Do Item Template, make this a bit larger. And what we can do is to make this subject a clickable link. We can use a special block helper that you get with Iron Router called Link To. And that will create a link for the given data context to a particular route.

So we can say link to route equals, and then the name of the route. So it's going to be To Dos Detail. And it will automatically grab the current data context, which in this case is the To Do item, and create the proper link. Let's go over and make sure that it did what we expected it to do. So you can right click on one of these To Dos and click Inspect Element. And make this as large as you need to.

And take a look at the URL in the Anchor tag. And notice that this parameter has been replaced with the actual ID of the To Do data item. So when we click on this link, we should be taken to the To Dos Detail page.

Next up, we have to actually fill in this To Do Details template. And just like we did before, we're going to start with the data for the page that we need. Now, if you go down into the console and check what data we have available to us-- so I'll just do a Find All on the To Dos collection, and then we'll fetch to grab the array. Notice that there's no items in it.

Now, we've gone to a different route. And because of that, the items have been removed. We've unsubscribed from the previous subscription. So since we've decided to segment our app by route, we have to set up a new subscription for this page that we're on.

So let's come back to the HTML. I'm actually going to clean this up just a little bit. And what we need to do is to grab the data for this particular item. So first, we'll publish it out. So we'll go to Server and open up the published JS file and create a new Publish function called To Do. We could call it To Do Detail if we want. But I'll just call it To Do. And let's get it into the page here.

And what we're going to do is return a cursor for the particular To Do for the ID that was passed up. Now, we're not going to use Find 1 here, and that's because we want real time updates to be published out to the client. And in order to get that, we need to return a cursor here, not just a document. And also, I'm not putting a user ID query in here, because I want other users to be able to see tasks from other users in order to comment on them. So we'll just grab whichever task has this ID.

Next up, we need to subscribe to this data. And the place that we can do that is in the controller. So if we go to the To Dos controller, right inside the subscriptions here, I can say this.subscribetodo. And this time, we need to pass up a parameter. And so we can grab the parameter from the URL by saying this.params and then the name of the parameter. So this time, it's going to be _ID. And we don't use the colon here.

Once I save that and the page refreshes, just go down into the console and make sure that we did this correctly. So you can say find, fetch. And we should have one document in there, but we don't. So we're going to have to debug this a little.

When you're not getting data and you expect to get data, the first thing I do to debug is I click on the Network tab and see what DDP messages have been sent back and forth. So you can click on WebSockets and then WebSocket and take a look at the Frames tab. And just scroll through the messages and see if you can spot any errors, particularly that are coming from the Publish functions.

So in this case, we've subscribed to a particular To Do right here. And if we scroll up a little bit-- or scroll down, sorry, towards the later messages, notice this error here, the 500 error. And it gives us a reason, that there's an internal server error. So that tells us that we're getting something on the server, some kind of problem. And if we go look at the server log, you can see this reference error here. So our code, we had a mistake in it, and it's saying that To Do is not defined in our Publish file on line 12.

So we can go and fix that pretty easily. We'll just open up the publish.js file, go to line 12. And here, we've mistakenly said To Do instead of To Dos. Once that's saved, we can go back to the console and double check that we have the item. I'll refresh again. This time, we get an object in our array, as we expect. So we're getting the proper data now, and now all we need to do is to wire it up to the user interface.

Let's head over to our template and the client's To Dos folder down in To Dos Detail. And we can start off by putting the subject here and saving this file. And when this refreshes, we're actually going to get a blank page. And that's because we haven't set a data context yet for this template. So it doesn't know where to find this subject property. We don't have any document defined as the data context for this page.

So we need to go back to the home controller. And let me set it up as a separate window here so we can see it. I'm going to say open up the To Dos controller. And we can set up a data context in two places. We can either do it globally for all the actions in this controller, or we can set it as a property in the render function.

Since we only have one action, I'm just going to do it right here globally. And what this function should do is to return whatever the document is that's going to be the data context for this page. In this case, I can use a Find 1, and that will be reactive, because we're on the client.

So we're going to find the To Do where the ID is equal to the 1 and the parameters. And we can get the parameters just like we did in the above subscriptions function using the this.params object. When we press Save, we should be able to see a subject now at the top, and we do. So everything is working properly.