• Meteor

Generating Templates

Next up, we're going to build out the user interface for the application. So we're going to create a bunch of templates. And so let's start off by creating the main template, which is going to be the list for our todos. So we'll list the todos and also be able to create new ones and see how many have been completed versus ones that are outstanding.

So to create the main viewables, I'll use an Iron Generator called a template. And we'll create a template under the Todos folder called Todos List. Now, this creates a couple of folders and files for us. And if you look up in the directory tree here, we have a folder called To Dos, and within that a Todos list folder that contains the files for the template.

So we'll start off with an HTML, JavaScript, and style sheet file. And inside the HTML file is where we'll find the template HTML. So for now, I'm just going to say Create an H1 tag and say Todo List. And from our home template, we can just go ahead and render out this Todos List, because that's going to be our main template. Or we could go into the controller and make the Todos list the main template. But since we might want to put some other things on the home page, I'm just going to go ahead and do it this way.

OK. So together, let's build out the HTML for this template. I'll close the menu so we can get the full screen here. And we'll create a wrapper class here called Todos panel, so we can style this appropriately. And right up on top, I'm going to render out another template called Create Todo Item. We'll create that in a minute. But that's going to be the text box that allows us to create a new todo item.

Next, I'll have an unordered list. And we'll give it a class name of Todos List for Styling. And inside of this, we'll loop over all of the items that we have. I'm going to call these Todos. And we'll go and we'll create each of these helpers and other templates in a sec.

OK, inside of this iterator, for each item that we have, I'm going to create a list item with a class of Todo Item. And then I'm going to create a dynamic class. So we'll use a helper here that will give this an extra class if the task is done. And so if the todo is done, we want to apply a class that will put a strike-through indicating-- or a line through the task indicating that it's complete.

And inside of the list item, we'll render out another template called Todo Item. And this just lets us separate the logic or the UI of our app into multiple different templates, just to organize it. OK. One of the things we can do within each block is we can provide an else part. And this block will get rendered if there's no todo.

So if this returns null or it has an empty zero count, then this part of the block will get printed out. And so we can create a todo list item here with an extra class of empty. And I'll just write "no todos yet."

And then underneath this, let's render out one more template that will show us the count for completed todos over the entire set of todos that we have. Now when I save this, I should get some error, because we haven't created these templates yet. So next up, let's come down to the console and create templates for each one of the child templates that we're going to use in the above list.

So I'll say Iron generate template. And we'll create another one called Create Todo Item. And then another one for todos count. And then finally, one for the todo item itself. OK, so these are all the templates that we should need. And now the app is working again, but we're seeing the boilerplate HTML being printed in each of the child templates.

Now, before we move on, let's go to the JavaScript for our list, for our todos list, and fill out the helpers for this main list here. We're going to have two helpers that we created, or that we're using in the HTML. The first is the todos list itself. So this is what we're iterating over in our each block. And for this, we want to return all of the todos for the current user. So where the user ID is equal to the currently logged in user.

And I want to sort those by the created at date in descending order. So the negative one will give me descending order. And then we have this dynamic is done class. So what we're going to do with this is if the task is done-- so this will be the current data context for the document or the todo item itself. And we'll say, if the is done property is true, then return a string called done. And this'll be a CSS class like it's applied called done if the task is done. Otherwise, just return an empty string.

All right. I think the next template that makes the most sense to do is the todo item itself. And that's because that's the main template that gets rendered out for each todo item that we have. So what we can do is go into the new todo item template that was created here and start filling out the HTML for this.

So I'll start off by creating an input of type checkbox. And the value, or the name, will be the name of the attribute on the document itself. So we'll call that Is Done. And then we need a dynamic helper here that's going to check the box if the todo is done and leave it unchecked if it's not done.

And the next div will be for the subject of the todo. And then finally, the action where we can click on the todo and go to a particular link, which we'll create a bit later. So let me save that. And hopefully our list should have something in it. So over on the right now, you can see the first todo that we created earlier.

So here's our todo, and I've opened up the elements HTML debugging pane down at the bottom so we can see the dynamic classes being applied when we check this todo is finished. Now, we need to wire up the event handler to handle that case, so let me clear this. And what we'll do is go over to the todo item JavaScript file and fill out the event handler.

So there's only going to be one event handler here, and it's going to be for when we click on the input with a name of is done. When we do that, we're going to check and see whether or not the checkbox is checked. And if it's checked, we'll say that the todo is done. And if it's not checked, we'll say it's not done.

Now, let's also grab the ID for the current task so we can update the right document. Again, this will point to the current todo in the list. And then we can just simply call the update method on the todos collection. We'll update the document with an idea of the one for this current data record. And then we'll use the set modifier, and we'll set is done to the value that we get from the checkbox.

And then one last thing we need to do is create a helper called is done checked. And this is how we're going to determine whether or not to check the checkbox based on the value of the data. So we'll say if the current todo is done, then return checked. Otherwise, just return an empty string. And you'll see this in action in a second in the elements area of the debugger.

All right. I want you to keep your eyes trained down here at the list item and watch as I check and uncheck this todo item here. Watch the HTML dynamically change. So you see that CSS class that's just being applied and then taken away depending upon whether the checkbox is checked or not? And that's because the underlying data is being updated because of the event handler that we added over on the left. And then the done class is being applied if the todo is done. And that's what creates this nice strike-through here that we're able to get from that CSS styling.

All right. Next up, let's fill out the Create Todo Item template so that we can create new todo items directly from the user interface. So I'll jump up here to the Create Todo Item and pull up the HTML for that. And then down below it, I can open up the corresponding JavaScript so that we can see both at once.

All right. In the Create Todo Item template, we're going to use a form. And we'll just give it a class of Create Todo so that it looks nice. And we're going to handle two different cases here. One is going to be if the user is logged in. And the other's going to be if they're not. So if the user's logged in, so if there's a current user, else will do something else.

And if there's a current user, we'll go ahead and provide the text box. And we'll give it a placeholder that says create a new todo. And if they're not logged in, we'll just prompt them to log in. So the placeholder in this case will be Sign In to Create a Todo, or Todos. And I'll give it the read only flag. And that'll tell a browser that this should be read only.

Now, when I save this, we should get a nice text box. And since we're logged in, it should say Create New Todo. But if I log out, that should dynamically change, or reactively change, to sign in to create new todos.

OK. Let's sign back in. And now we need to create an event handler for submitting this form and creating a new todo in the database. So I can handle the event submit form. And the first thing I like to do in event handlers is at the very top, if I don't want the browser to use the default behavior, then call the prevent default method on the event object. And this way, if an error gets thrown somewhere in this function, we're still preventing the default, and so the form doesn't get submitted to the server.

Then we'll go ahead and grab the subject. So I'll find the element that's of type input, and we'll grab its value. And we'll do a simple insert into the mini Mongo collection. With the subject that we just got, we'll give it a Created at timestamp. We'll say, by default, it's not done. And the user ID will be the currently logged in user.

Then finally, we'll find the form that we just submitted and reset it. That will clear the values, or clear the text box. All right. Let's go over here and try to create a new todo. And I'm going to keep the console open so that I can get a sense of if there's any errors. So we'll create a second todo and then press the Enter key. That will submit the form, and there we have it. We have a second todo at the top of our list.

We can make sure that it's wired up correctly by clicking and making sure that it completes the update and we get a strike-through. And everything looks like it's working OK. All right. We have one last template we need to complete for this page, which is the todos count. So let's come back over to our code and clean this up a bit, and head over to the todos count HTML.

This template will be pretty straightforward. We're going to create a wrapper div around this with a class of todos count for some styling. And then we'll create two helpers. One will be the total number of tasks that have been completed. And that will be divided by the total number of tasks. And so we'll say that we finished one or two or three out of two todos completed.

And let's open up the todos count JavaScript file and actually add these helpers. So let's start off with the completed count. So we'll use a mini Mongo query here, and we'll search for any todos for the current user where is done is true. And then we'll call a count method on the resulting cursor.

So when I refresh that, we should see that two tasks are completed. But we don't have the total yet, so let's get the total count. And that will just be the total number of tasks, whether it's done or not. And now it shows two out of two todos completed.

And what we should see is this is reactively updating if we change one of these todos to be not complete. So now it's one out of two, and now it's zero out of two. So this completes the homepage for the Todos app.