- Overview
- Transcript
4.4 List the Games
Now that we have created game records in our database, we're ready to list them. We've got a few different types of games to think about, and we'll list them all in this lesson.
1.Getting Started3 lessons, 11:39
1.1Introduction00:39
1.2Application Demo05:23
1.3Application Setup05:37
2.First Steps4 lessons, 19:19
2.1Organizing Your Code05:44
2.2Set Up a Router07:24
2.3Add User Accounts03:39
2.4Collections02:32
3.The User List Page3 lessons, 23:41
3.1List Users12:38
3.2Making Friends04:57
3.3Write a First Meteor Method06:06
4.The Game List Page4 lessons, 39:05
4.1Waiting for Data08:15
4.2New Game Form08:35
4.3New Game Method09:42
4.4List the Games12:33
5.The Game Page10 lessons, 1:28:25
5.1Get the Game Data04:53
5.2Display the Game: Prep Work11:40
5.3Display the Game12:00
5.4Style the Chess Board02:50
5.5Making Moves: The Event Handler16:54
5.6Making Moves: The Meteor Method10:00
5.7Listing the Moves06:48
5.8Chat Between Users11:56
5.9Reviewing the Game09:29
5.10Deploy the Application01:55
6.Conclusion1 lesson, 00:44
6.1Conclusion00:44
4.4 List the Games
So now that our users can create new games, they of course need to be able to get to them. So let's add a list of games to our games page. Now, before we do that, I want to create a new helper function which I know we're going to find pretty useful on our games page. So I've opened up our lib/helpers.js file. And we're going to create a new helper function called getUsername. And this is a function that's going to take a user ID. And we're just going to return the user name for that user. So this is really simple, we can just do return Meteor.users.findOne and the find one function takes a user id as its parameter that will return the user object, and then we can just say, .username. This is just something I found myself doing quite a few times in a couple of the templates that we are about to create. And so, I just put it into a helper function, and that way, we can save ourselves a bit of typing. Okay. So this is what our games page looks like right now. And we're going to have two lists showing up underneath this. We're going to have a list of the current games that are being played. And we're also going to have a list of archived games or games that they have already completed. So before we can actually display these games, we have to find them. So let's go ahead and open up our games.js file. Right now the game's template only has one function, possible opponents. So let's add another one here. Let's add currentGames. Now this is actually pretty simple. All we have to do is return Games dot find where the result is equal to null. And we already did this in our possible opponent's function. So you're familiar with exactly what this does. When a game is finished. We're going to set result to be the ID of the winner. And so current games of course, will be all the games where there is no result yet. All right. Now what about archive games? This is going to be pretty much as simple. We can just say return Games.find where the result is and I'm going to pass an object to result. And we're going to say where it is not null, right? So this is the not syntax for Mongo DB. And if you've used Mongo DB before, you're familiar with this. And so this will just return all of the games that this user is a part of. Where the result has been set to something other than no. However I want to modify this list a little bit. So let's go ahead and call the map function, I will point out here that what we're returning is not an actual array. Games.find returns among the db cursor and that cursor has a map function so don't think that this is an actual array. But it acts a lot like an array in this case. So we're going to take a game and in here I want to change the value of game.result. Because of the game ended in one of the player's winning. Results will be that user id. However if it was a draw result will just be draw. So what I want to do here I say if the game is not a draw then let's change game.result and we're going to change it to get username which is our first usage of that helper function we just made and we'll passing game.result. So we'll get their username. And then we'll just add the text. One. To the end. So if Andrew one for example we'll say Andrew won. So we'll just get their username and then say that they won. And then of course since this is map. We'll just go ahead and return the game. All right so there is our set of archived games. Okay so now let's go ahead and list these games in our games template. So I'll open up the game's template. We're going to put this underneath our possible opponents if block and let's start with the archived games because this is much simpler. So we'll say archived games. And underneath this, we'll create an ordered list. And then in here, let's do an each loop over archived games. And I'll close the each loop. And then in here, we're going to have a list item. And inside of that of course we will have an anchor element, which will link to the game and the href for this will be, /games/ and then we will interpolate underscore id. Which is the id attribute of the game that we're looping over of course and then, in here we wanna have the name of the first player. And then we'll say versus the name of the second player and then. In parentheses we'll have the result. Well, we already know how to get the results. I can just say result. And get it off the game object. However, how do we get the names of the players? Well, we know from when we created our games object. That a game will have a b field and a w field for the black and white user ids. So we need a way to convert those user ids from their id to the actual name. Well, let's jump back toward JavaScript for a second here and let's create a username function. And we'll just reference the getUsername function we created earlier. Great. And so now we can just say username and we'll pass it w for white. We don't actually have to use parentheses when we are calling functions this way. And then we'll say versus and we'll set username black. Now unfortunately we don't have any archived games yet so nothing is going to show up in this list. However if we come back to the browser you can see that the heading is appearing. All right so now let's do current games and that is gonna go above archived games. So let's add an h2 here for current games. And the current games are going to be a little bit trickier because there are kind of three states to a current game. The game might be already in progress, which is just kind of the usual state, if you will, but then there are two special cases. We could be waiting for the game to be confirmed by either the logged in user or by the opponent that they are trying to play against. We'll start, as we did in archived games, with our unordered list. And then let's do an each loop and we'll loop over Current Games. Now of course everything in here will go inside of a list item. And now inside this list item the first thing we should do is check to see if our game needsConfirmation. Now this isn't a function we're calling. This is the needs confirmation property that we have on game objects. So if our game has a needs confirmation Value, then we also need to check to see does it need to be confirmed by us or by someone else. We can say if it needs confirmation, then let's check to see if it needs confirmation byMe we'll say and will say me of course to mean the currently logged in user. Me might not be the most accurate pronoun but I think it will work in this case. Now we don't have this byMe helper function yet. So let's go ahead and add that. Underneath user name here will create byMe and this will be very simple we can say Will return this dot needs confirmation. And at this point in our code where by me is called. Because we're calling it inside of our each block. The value of this or the data scope will be set to the current game. So we can say if we have the dot needs confirmation and this dot needs confirmation Is equal to Metor.userId which is of course the id of the currently logged in user. Okay so in here if the confirmation is needed by me, then we know that this user needs to do the confirmation. So let's take the simpler case first and we'll say else and in the else part here we know that this user created the game. Therefore, we're waiting by. And therefore, we're waiting on the other user for confirmation. So in here, we could just say, game between. And we'll say username w, and username b and then in parentheses after this. We can say, waiting for confirmation by and then we'll say, username and we can say, needs confirmation. Because remember that is the idea of the user who needs to confirm it. The next easiest case, of course, is if the game doesn't need confirmation. So let's do that next. We can add another else to our outer if block here and if the game doesn't need confirmation, let's add an anchor element that will go to /games/, and then will an interpolate the _ id and in there. Why don't I just copy this text from above or copy the text game between white and black. So I'll just paste that in here. All right. So now we have the two easy cases but what happens if this user needs to perform the confirmation. Well then let's say Game request from, and we need the user name of the user that created this game. Now if this user the one logged in is the one that needs to confirm the game, then we know that if they are playing black. Then it's the white player who requested the game. And if the currently logged in player is playing white, then it's the black player who requested the game. So we can't really just say the username of White or the username of Black here because we don't know which color this player is playing. So let's create another function here called opponent, all right. So if we hop back to our JavaScript let's create one more helper function here and we'll call this opponent and this will be really simple. We'll just return and we'll use a ternary expression here will say this.white if that is equal to Meteor.userId() Then we'll return this dot black which will be the id of the opponent otherwise were returned to dot white. Okay, and we're going to include two buttons here. One to accept it. And one to reject it. So let's create a button. And we'll give it the text accept and we do have to give this button a couple of classes will give it BTN and BTN dash XS. For extra small and btn-success, to make it green. Let me duplicate this and it will have the same classes, except we'll have btn-warnings. So we'll get a yellowy orange button instead of green and we will have a text decline and just to make this easier to access from the JavaScript. Why don't we add some IDs here? We'll have a button with the ID accept, and a button with the ID decline. So if we come back to the browser, you can see that our current games list is showing up here. And we have a game request from Paul. And I can either accept it, or I could decline it. So let's go ahead and write the functions that will handle those clicks. So, of course this will be done in games dot JS and down here we already have one events function, let's add two more. We'll add a click on hash Hash accept. And let's see what do we want to do when the click is accepted? Well we'll do Meteor.call. And we will call acceptGame. And we'll pass in this._id which will be the ID of the game. Which will be the idea of the game they are accepting. And remember this will be the right context because we are still within our current games each loop here. Now, I'm going to copy this function and paste it beneath. And will change this to click.decline. And we'll do a meteor call to decline game. And of course we'll pass in that ID. All right this means we need to write those two meteor methods. And since those are super small, we'll do it right here. And now, let's jump to the bottom of our methods file. And we have accept game. And it takes a game ID. This will be really simple, we can just do games dot update. And we can pass the game ideas are query. And let's just do unset. And we're going to unset Needs Confirmation. And that we do have to give it a value there. The value doesn't really mean anything but. It's just because of the object syntax that Mongo DB uses. All right so we'll just unset needs confirmation which means that property will no longer exist. Then we need to create the declineGame function. This function also takes the gameID as we saw. And in here let's do Games.remove and we'll pass that gameID in. And that will just delete the games, so that it no longer exists. And therefore it will be removed from the list. All right, we should be able to see this in action now. So let's head back to the browser and I will pop open my console just in case we get some errors. And if I click accept you can see that the game switches from being the acceptance and decline buttons to a link to the actual game. And if I click that you can see we get the error that there is no route for that path which is fine we haven't created that yet. All right. Now if I create a new game here with Cameron. You can see that we have a game between Andrew and Cameron. And I am waiting for confirmation by Cameron. So let me open up another browser window here. And let's actually sign in as Cameron. And you can see that Cameron has actually two game requests. One from Paul. One for Andrew. Let me accept the one from Paul. That turns to a game link. And let me split my window here so that we can see this happen in both windows at once. We have in Andrew's window here waiting for confirmation by Cameron. Over here in Cameron's window, we have the game request. If Cameron declines it, it disappears here in Cameron's window and it also disappears here in Andrew's current game list. And notice that because Andrew is no longer playing a game with Cameron, that the new game form reappears and he could create a new game with Cameron. So if I decide to create a new game with Cameron, I have this in my list now. Cameron has a new game request right away, and we can accept it. All right. So now we are successfully listing our games. It looks like we're ready to start creating our game play templates.