5.2 The Conversation Component
For our first nested route-and-component, we'll write a conversation component, which will display a list of messages to the user.
1.Introduction5 lessons, 29:28
2.The Projects List6 lessons, 39:35
3.The Users5 lessons, 31:28
4.The New Project Form4 lessons, 30:48
5.The Project Page4 lessons, 49:46
6.Conclusion2 lessons, 04:08
5.2 The Conversation Component
Now that we've got a page for viewing our individual projects, let's talk about viewing these individual conversations that we have here. As you can see, we already have the URLs set up correctly. If I hover over one of these, you can see in the lower left hand corner of chrome, we have projects/5/conversation/6. So we have both the project ID and the conversation ID showing up successfully there. So that's pretty great. So what we need to do is create a component to display one of our conversations. However, you'll remember that I said we want the conversation view to be nested in this page. And so we can do this with Angular 2 by using nested routes or child routes. So let's see how this might work. We're gonna start here In our project component, and we're going to export another object. Currently, we're just exporting this class, but let's go ahead and export a constant that we're going to call projectChildRoutes. And this is going to be an array of routes, just like we have in our app module page. Let's compare that in the app module file. Here, we have our routes as you can see, and we just need to give them a path and a component basically. We're gonna do the same thing here. First of all, let's give it a route component which is going to be the project component here itself. So we'll set the path equal to blank string, and then the component is going to be equal to the project component. Then let's add another path here which is going to be conversations/:conv_id, and the component for this is going to be the conversation component. And of course we're going to have to import that here, so let's import the conversation component from conversation.component. And of course we'll be building that component in this very lesson, but now that we have these child routes we need to come over here to app module, and let's see where we import project component. We will also import the project child routes, and then down here where we use the project component right here component project component. Let's add children, and this is just going to be project child routes, just like that. Okay, and so now any child routes that we want projects going to have can go in this routes array. So, let's go ahead and create that conversation component. So, in the app directory, we will create conversation.component.ts. Okay, so what we're gonna import, of course, start with, of course, we will get component, and on a NIT. Now, because we need some information from the route, we're also going to get The ActivatedRoute, and Params classes. We're going to need to import the off service, and let's also import the conversation class that we created. We'll start by calling the component decorator, the selector is going to be conversation, and the templateUrl is going to be 'templates/conversation.component .html. And finally, let's do export class ConversationComponent and we'll implement OnInit. Now let's create our constructor, so we can inject a couple of things here. We'll need to inject the auth service of course, so we'll have AuthService and we will also need the route, and that is, of course, the activated route object. And this time we're actually gonna do something inside of our constructor. What we're gonna do here is create a couple of observables. First, we're going to create a conv_id, observable whereby we can get the conversation ID. And this is just going to map our route observable. So say, this.route. Since we're inside the constructor, we could just say route, route.params.map and we'll map the params. And we will just get params, and ['conv_id'] to get that parameter. And that will give us the conversation Id. We also want an observable that is the user name. So will do auth.currentUser to get that observable, and then we'll map that user to just be the username. Okay, so couple of observables for us to use, that's nice. Now let's do an ngOnInit function, all right. So now inside of ngOnInit, we can use these observables that we've created, and the reason I've done this is just to show you how we can create observables and pass them around just to get you thinking in a more observable way. Cuz, that's really useful when you're using Angular. Our username observable we will save for another lesson, but this conversation id we can use to get a conversation. Now we don't actually have our project service here, so we can't get our conversation. So let's go ahead and import ProjectsService, we can't forget to add that as a provider, and of course we will inject that here into our constructor. Now even though we have our project service here we don't actually have the function we need in that service. So let's go ahead and open up the projects.service, and at the bottom here let's add a getConversation, and this is going to take an id: string, and it's gonna return an observable with a conversation inside of it. Now do we have a conversation class in here? Right now we just have projects. So let's go ahead and import conversation, and this is going to be almost exactly like getting an individual project. Let's return this dot http dot get slash Api/conversations/ and then we'll throw in that ID, and then we can map the result to this.extractdata. Okay, so now we have a way to get an individual conversation. So in here, let's do this.conversation ID, and we will flatten app that observable. We have the ID, and actually instead let's do it this way, let's do this.service.getconversation.bind to this.service. It's actually a lot longer way, but it's another way we can do it, so why not give it a try? Then let's do .subscribe, because remember flat map will unwrap one level of observable. So, it returns an observable that wraps our conversation object. So, we will subscribe to our conversation. And if we'd like we could actually use type scripts to make sure that it is a conversation, and now we can say this.conv, and let's just use the short form conv in this case just to make it a little easier to spell equals the conversation. And I'll just add that conv property over the top here. Conversation is a conversation. All right. And now, we have the first part of our conversation component which is just fetching that conversation. So we'll in our temples directory, we will create conversation.component.html, and let's create an md here. Remember we have to be ready to render this both with and without the conversation object because of the asynchronous nature of observables. So we will have a *ngIF, if conv is there, then we will use that. Let's also have a class here, and this class is going to be conversation or conv-full. This is just going to display this md-card as if it was a modal text box on our screen. So that's good. Okay, so what do we put inside this md-card? Well, let's see, we have an md-card title which is going to be conversation.name, and then we have the md-card content element. And in here,we're going to use another material design element, the md-list. An md-list is a great way to show a conversation which is exactly what we need to do here. What we're going to do is loop over our conversation messages and display md-list-item elements for each one of these. So, let's create an md list item, and on the opening tag for this, we will say *ngfor let message of conv.messages. And in here we're going to do a couple of things. Let's have an image, and we'll give this to the directive Md list avatar and then we'll bind to the source attribute here and we will do message.avatar. And you might wonder why does the message have an avatar property? Well, I've done a little bit of data denormalization just to make it a little bit easier to display a conversation. Each message will have an Avatar and a username property as well as a text property just to make it easier to display a list of messages. So underneath that, let's have an H3 with the md-line attribute, and we will display message.username. And then underneath that, we'll have a paragraph with an md-line, and we'll say message.text, and close off the paragraph and that should display our conversation. All right, so everything looks good here in the conversation component, everything seems to be in place, and app.module we have imported our project child route. So we don't actually need to import conversation component here, do we? Yes, actually we do. So let's go ahead and import the ConversationComponent, and the reason we need it here is cuz we need to throw it into our declarations. Conversation component in our declarations list, and now I think we're good to go. So if we had back to the browser, we can view an individual project. Let me click one of our conversations here, and look at that. We can successfully view a conversation. We have that conversation title up at the top, we have avatars and user names, and the text of their messages showing up here. Excellent. So we can view a list of conversations. And notice of course also that the URL has changed to projects/ ID/conversations/ID. So this is great. Of course what we can't do here is contribute to this conversation. In fact this is exactly what it should look like if this were a read only project. But we should be allowed to message with our users here. And so in the next lesson, we'll look at adding some new messages to a conversation.