- Overview
- Transcript
5.8 Chat Between Users
We'd like our users to be able to exchange messages while they're playing, so we'll add a chat box 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
5.8 Chat Between Users
We've known all along that we have this conversations collection which is supposed to allow our users to chat during a game. However we haven't built any of the UI for that. So in this lesson that's what we're going to do. Over here on the right hand side we're going to have a chat box. So here in our game.htm file I'm gonna create another column and so this is just gonna be another div with a class of col-sm-4 and in here let's insert another template, and this is going to be the chat template. Now we've already got a lot of stuff going on in the game.html and in the game.js files. So why don't we create another folder for our chat code. And again, remember, because Meteor will compile everything, it doesn't matter that we're referencing the chat template from one file and creating it in another. All of that is all right. So let me go ahead and make another directory client/chat. And now I'll open a new file client/chat/chat.html. And let's create a template named chat. And this is actually going to be pretty simple. Let's start with our if block and we'll say if Template.subscriptionsReady just as we have before. And then in here, we're going to have a div with a class of chat. Now, I'm adding the class 'chat' here so that we can style this. There's a fair amount of CSS needed to style our chat box here, so we're not going to go over that at all in this lesson because CSS isn't really the main focus of this course. You'll be able to download the code for this project and you can look over the CSS on your own, if that's something you're interested in. So then inside of this div we're going to have an unordered list. And this is going to be a list of all of our messages. So we could actually throw in our each block already. We could say each m in messages. And then of course in here we're gonna have a list item. That seems pretty straightforward. For this list item we want to give it a class name and inside our braces here we're going to actually call a function called getClass and we're going to pass this m.name. Now you might remember we have a few system messages that we've created already. For example when the game begins or when the game ends or when someone is in check. And we know that each one of those message objects has a name property which in our case has been system, but in other cases is going to be a user name. And then we also have m.text which is the actual text of our message. So inside this list item, we'll have m.text. And then we'll use a getClass function, which we'll write in a second here. And it's gonna take the name and it will decide what the right class is. And this is just so that we can style the different speakers in a different color. Ok, so underneath are a list item. Let's have an input tag here. We'll give it a type of text and we will give it an ID, of message. And that is all we need for our chat template. So now let's go ahead and create a client/chat/chat.js file. And in here we'll start as we have before with template.chat.onCreated. Now this reminds, me we haven't actually published any of our conversations yet. So let's go ahead and open up our server/main file and let's add one more publication. So we'll say Meteor.publish. And we'll publish, we'll just call this chat for short. And this will have to take a gameId as its parameter, right? And then we'll return Conversations which is the name of our collection, .find and we'll find where the game field equals the gameId that we've passed in. Okay, so now that we have that conversation, from within here, we can do this.subscribe. We can subscribe to chat. And we're going to need the gameId as our second parameter here. Now we're gonna do something, again, a little bit different here, just so I can show you a few different techniques. And in this case, we're going to make a function called vista ID and we'll just use an arrow function. And we'll say this is going to return FlowRouter.getParam ( 'id' ) and so then in here we can say subscribe to chat and we're going to pass in this.id and we go ahead and call that function. Now, the reason we've done this is because we've just added a function onto our template instance. And this means that later on, we can actually use this function. And you can use this technique for different types of functions, not just for getting parameters from the router. And you'll see where we might use this inside of our helpers so let's go ahead and create some of our helpers. So we have template.chat.helpers. And let's see if we look back at our chat here, there are two real helpers we need. We need our list of messages and we also need this getClass function. Okay, so messages should be pretty straightforward. Let's do messages and let's just return Conversations.findOne. And we will find one where the game equals Template.instance. Now Template.instance is a function that we can call to get the current instance of our Template.chat template. So I can say Template.instance call that and that returns this instance here which is the same thing that is this within our onCreated callback. So now I can just call our id function like that and I have access to our FlowRouter.getParam. All right so we go ahead and we get the whole conversation and then let's just return the messages list. All right so that gives us our messages. Next we need the getClass function. And as we know this is going to take a name, which is the name of the user that made the comment. All right so there are really a couple of things we might have here. If the name is equal to system then we know it's one of our system comments. So we'll just return the class system. If the name is equal to Meteor.user().username, well then we know this is the current user, the one that's logged in right now who made this comment. And so we will just give it the class me, otherwise we'll return the class them. And I've written so CSS so that these classes will make the appropriate styling. So although we haven't been able to make any chat messages up until this point we know that we do get a default message when the game is created. So let's go back over here to our browser. And if I refresh the page, let's see, well, we have our chat box kind of taking shape here, but we don't actually have any messages showing up. So let's see if we can figure out why that might be. If we come back to our code here, everything looks good. We get our conversation instance and then we ask for the messages property. I wonder if something's wrong in the database. We can check out the database. By running the command Meteor Mongo in a new terminal tab here and let's look at d.b.conversations and I'll say .find. Here we have a list of all of our conversations and it looks like we do have a bit of a problem. First of all you can see our array here is actually just called message not messages. So it looks like we lost an s on the end there when we were originally creating it. But also if we look down at the bottom one here we do have a bit of a problem. Instead of inserting our name and our text into the messages array as we wanted to when the game was over, it looks like they just got inserted as properties of their own. So, we have a bit of cleanup to do here. Okay. And both both of those things take place in Meteor methods. So here in Meteor.methods in the createGame function, if we come down here to where we first create our conversation, let's change this property to messages with an S. That way that will be named as we would expect. And then down here in make move right here where we have our push we actually want to push into messages and once I add another set of curly braces there, okay, so we're pushing into messages. And this is the object that we're pushing in. Okay so that is exactly what we want now. Unfortunately this means that what we currently have stored in our database is wrong. So let's just do db.games.remove and will delete all our records there and db.conversations.remove and we'll delete all of our records there. Okay so now we have a clean database and we can give this a fresh try. So if we come back to our board here, let's create a new game with Cameron. We have to wait for Cameron to confirm. So let me open up a new window here. Cameron will accept the game and then let's see. Okay great. You can see if I open this game that our first message is showing up successfully so the game was started at this time. All right. Of course, we could go ahead and make some moves. But what we can't do at this point is actually add a new message. Right? So let's go ahead and make this chat box work. As you might expect, this is going to be an event. So let's do Template.chat.events and then in here let's look for a keypress on that input text box. Now, we don't want every key press, we just want to know if evt.keyCode is equal to 13 because 13 is the enter key so if it's not equal to 13 Let's wrap this in an if block here. If it's not equal to 13, then they're typing some other character and we don't care, we'll just return. Otherwise, if it is 13, let's call a Meteor method so we can call the addMessage method. We'll pass in evt.target, which is the text box, .value. And then we want to pass the game Id as another parameter. But remember, we have this function up here that we can use to get the game ID very easily. Now, you might think we need to do template.instance.id, but actually, Meteor handily passes the instance as a second parameter to our event functions. So I can just add instance as a second parameter there, and then say instance.id() and call the function like that. All right, and in the last thing I'm doing here is set evt.target.value equal to an empty string. Okay, so let's go ahead and write this addMessage function. This should be pretty simple. So we'll go ahead and, at the bottom of our methods.js file, we'll add the addMessage. And we have a message, and we have a gameId. This will be pretty basic as you might expect. We'll say Conversations.update. The query object will be where the game equals the gameId. That was passed in. And then let me just copy our push update query from up above here. Paste that in down below. And then all we have to change is the name will be Meteor.user.username right whoever is currently logged in and the message will of course be the message that is passed in right up above, excellent. So this should work just fine. Okay so let's see this in action. If we come back to our browser here Andrew can say Hi. And as you can see it shows up right there. If we flip over to Cameron's window you can see it displays as well. And he can say Hi yourself. All right. So let's see if we can get a check to actually show up. It's Andrew's turn so I'll flip back to his window and let's see. Let's bring the queen out here. And then if we go back to Cameron's window why don't we take the pawn. Will bring out our bishop here. Obviously, if this was a real game, I would take the queen but we're not gonna do that here. Instead, let's bring up a backup pawn and now if our bishop here comes down here, it's check and this is Andrew who just made this move. So we're checking the king and notice that we have a message in our chat box here. Check by Andrew. That's great. Okay, now notice we don't actually need this message to let them know it's in check because in the movies list we have this plus sign at the end. And this is the algebraic notation for check. But that's just something that could be handy. If you're scrolling back through your chat later you might see why you said something at a particular point in time. Okay, and we could keep playing this game, but it looks like we actually have a chat feature that's working. I'll say, good game here, and you can see that the chat box can just continue even after we've had these special messages by the system. All right. So, that brings us to the very last feature that we want to create which is allowing a user to review old games. And we'll look at that in the next lesson.