Next lesson playing in 5 seconds

  • Overview
  • Transcript

3.1 List Users

Now that we have the meteor collections in place, we're ready to start displaying and working with all of this data. So let's start by displaying our list of users. If you recall our application has a page that lists all of the user's in our application so that the logged in user can pick and choose who to be friends with. Now, the first step is to publish some data. Although we have a users collection, because we've removed the auto publish package, the collection of users is not automatically published to the client. This means the server doesn't automatically tell the client when new data to that collection is added. So publishing is something we have to do on the server. This is how we decide what data will be sent from the server to the client. Now we already have a Server Directory. So let me go ahead and create server/main.js. So we're gonna go ahead and do meteor.publish. And we're gonna call this call this publication users. Then we will pass in a function here and this will decide what data is sent to the client when the client subscribes to users. So of course in this case we're going to get data from the meteor users collection. So we can return Meteor.users. And this is the MongoDB collection that holds all of our users. So we'll say users.find. And we wanna find all of the users. So let's just have an empty query object. And for our fields object let's say that we only want to publish username and profile. And if you're not familiar with MongoDB this query basically says find all of the records in the user's collection. And only return their username and profile fields. Now the profile field is a sub object. In the user object and media recommends that any user specific data that you wanna store in this user object is stored within the profile object. So we're gonna have a profile.friends as our array of friends. In this case, we don't actually need profile for other users but we'll include it just in case you want to extend the application later. Believe it or not, this is all we have to do to publish our list of users from the server to the client. Now whenever a new user is created, the fresh data will be published to the client. And the client will always automatically have whatever new data matches this query. So now that we have this data being published on the server, we need to subscribe to it from the client. Now sometimes you'll see Meteor applications that have all of the subscriptions in a single file. However, we're going to follow one of the best practices that is listed in the Meteor guide. And I'll have a link to the Meteor guide underneath this video. The best practice is that it's best to place the subscription as close as possible to the place where the data from the subscription is needed. So instead of subscribing in a single file with a list of all our subscriptions, we're gonna subscribe when the user's template is instantiated. Of course we don't have a user's template yet, so we have to go ahead and create one. So I'm going to create a folder. And some of our higher level templates, the more important ones, are each gonna have their own folder to go with the template and the JavaScript. So in the client directory, let's create a user's directory. And then back in the editor here, I'm gonna open client/users and let's create a users.html file. All right so now let's create a template and we're going to name it users. And in here we're going to create an un-ordered list and let's give it a class name of list-group. And for now let's just create a list item in here and in here we're going to use the syntax {{#each. And we're gonna do a for each loop over the users object. And we can close this each loop by doing {{/each. And in here, for now, let's just put a list item. And let's do double curly braces and in here we'll have username. Now there's something you need to know about loops like this in spacebar. And a spacebar is Meteor's name for its templating library, very similar to handle bars. When we loop like this and say each users, inside this loop, the context or the value of this becomes the item that we're looping over. So basically when we say username here, this is similar to saying this.username in actual JavaScript. If we actually wanted to give a name to this context, we could say, each user in users.username and then we could say, user.username. However will go with the shorthand syntax here, we'll use that longhand syntax somewhere else maybe. So for each user just show their user name. All right so now we have a template to show a list of users. However we never actually set a value for this users value here. So let's create a JavaScript file, client/users, and we'll say users.js. And this is going to be the file where we subscribe to the publication that we set up. So in here we can do Template.users. And this refers to this user's template that we created here. We'll say Template.users and we can say .onCreated. And this function is going to be called predictably when the user's template is created or instantiated for viewing on the page. So in here we can say this.subscribe and it's important that we use this here and I'll tell you why in a second. In here in this does refer to our template instance that we're creating. So we'll say this.subscribe and we'll subscribe to users. And notice the important part here is that the name that we used here to subscribe to is of course the same name that we published. So we are subscribing to a list of all the users in the database, their usernames and their profile objects. So why is it important that we use this.subscribe and why are we subscribing in this way instead of doing something you may see more often which is meteor.subscribe in a subscriptions file or something like that? Well, the benefit of subscribing this way is twofold. First of all, every template will have the data that it needs clearly defined within that template file. So it's very obvious where we can go to look at what data is being used and if we ever need to change that, we know where to change it. Also, when we use this.subscribe instead of meteor.subscribe, Meteor will automatically stop the subscription at the right time. And in our case that means when this template is not being shown. So when the user is viewing the users page that we're creating right now and people are continually signing up, those new names will be added to that list because the data is coming from the server to the client because we are subscribed to that data stream. However, when we navigate away from the user list, we're no longer going to be receiving that data because we'll unsubscribe when we no longer need it. Now, what we've created so far is not quite enough. But we're almost there. To review, we're publishing the data from the server. We're subscribing to that data stream here in template.users. But there is one missing piece. We need to actually set some data from that data stream to be our user's array that's being looped over in this actual template. So this is a job for the helpers. So we'll say template.users.helpers and we'll pass our object in here. And this is where we create that array of data. So we'll say users. And we have our function here. And in here, we will return Meteor.users. Which is of course the name of that collection. Now remember, just like with the collections we created, the Meteor.users collection has a counterpart both here on the client and here in the server. So we're publishing from the actual Mongo collection here in the server and the mini Mongo instantiation on the client is going to receive that data. So then we can filter from the collection on the client. We can say Meteor.users.find. And we wanna find a subset of all this data because there's actually one user that we do not want to show. And if you think about it you know exactly what user that is. It is the user that is currently signed in. So we want to find everything where the username property is not a given name. Now the way the $not operator in Meteor works is we set the field and then we pass it another object and $not is the key named there. And we wanna say it's { $not: Meteor.User()_} }) and Meteor.user is a function we call to get the current user. So we can say Meteor.user().username, all right, but we do have a bit of a problem here. What happens if nobody is logged in? Well, then we may well just show the list of all users, however, Meteor.user will return null and then we'll get an error for trying to get null.username. So let's do this, let's just put some parenthesis here in Meteor.user. And then we can say Meteor.user or an empty object. So if Meteor.user returns null, the expression within parenthesis will return this object and then .username is just gonna be undefined. And so no users will be removed from the list. Okay so this should be all we need to actually display our users template. There's one more piece to this puzzle and that is in the router. Currently we have a route to find here which is our main route, but we need to add another one. So let's say FlowRouter.route. And we're gonna say /users, and we have our options object here. Let's just give this a name. Let's give it a name of users, and then I'm just gonna copy our action function from up above. Let's paste this down below, and we'll just change the child name here to users instead of main. So, we're still rendering our layout. It's just we're rendering users. And one of the benefits of Blaze layout, is that it will only change the child template. It won't actually re-render our navigation or other parts of our layout if we had a more complex layout. So it will keep the rendering to a minimum. Okay, I think we can go see this in action now. So if we come back to the client you can see we actually have an error here, and it says the template.users.helper is not a function. And if we come back to our code you can see that I said users.helper, that should be users.helpers. So if I go ahead and change it, come back here, you can see that Chrome is automatically gonna refresh and we have no errors. That's great. So let's click find some friends. And you can see that we are taken to our page. And we have a list of our two users. We can see if our filter is working by signing in. If I sign in as andrew, you can see that the list automatically filters to just show cameron. If I go ahead and sign out, you can see that it changes to show both andrew and cameron. Now this is nice, but these aren't exactly displaying with the Twitter Bootstrap list group that we decided to use. And I think that's because we forgot a class name on the actual list item itself. However, instead of just adding it to the list item right here, let's actually create another template here. Because we're going to need to have some extra functionality on this list item, right? Because we want to be able to have a button there to either add or remove a user from the user's friends lists. So let's say template name is going to be user and let's go ahead and move this list item into here. And let's go ahead and add the class list-group-item to our list item. And now let's give ourselves a little bit of space here. The username will be at the bottom, and above this, we want to put a button that the user can click on to either add or remove them from their list of friends. However, if nobody is logged in we don't wanna show this button. So let's wrap it in an if block and we'll say, if current user. This is a variable that Meteor gives us to get a reference to the currently logged in user. If this is null, of course, there's no user logged in. So this button that we're gonna put in here won't be shown, however if the user is logged in CurrentUser would be that user object. So we could say something like CurrentUser.username if we ever needed that. So in here let's put a button. We'll give it a class of btn and btn-default. And we'll also give it a class of add which we will use to find that button in our event handler. And this button is going to be the button to add or remove our users, and I'm gonna change that text later, but for now let's just make sure our button is showing up correctly. Now, we're not actually using this template yet, so up here in the unordered list, let's go ahead and use the syntax to render a sub template or render another template. We'll use the curly braces, and then we have the greater than sign. And we can just say user, which is the name of the template. Now, usually, when you wanna use a sub-template like this you have to pass in the data that you want to use. So we could pass in some data here. For example, if we were saying, each u in users, we would have to pass in u. So that u would be the data context for this new template. However, because we're not passing anything, the context for this template will be this and we already know from our each block that this refers to the current user so saying username will work just fine. Okay, let's check this out in Meteor and as you can see these are now being displayed in the Twitter Bootstrap styling. We don't have any buttons showing yet. However, if I go ahead and sign in as andrew, you can see that andrew is removed and we have a button here for adding or removing. Okay, so in this lesson we have actually displayed this list. In the next lesson we'll begin to wire up the event handlers that will add or remove a user from the friend list.

Back to the top