Building Awesome Web Apps with Angular 2 Challenge 5: Solution
This course has been updated! We now recommend you take the Angular 9 Fundamentals course.
Transcript from the "Challenge 5: Solution" Lesson
>> Lukas Ruebbelke: So the question is how many container components can we have? If we can have as many as we wish, should we organize the ones into modules? And how two components on a different module can interact? So that's actually three questions, it appears like. So the answer is, you want as few container components as possible.
[00:00:28] And you want as many presentational components as possible. So the reason for that is a container component contains state. And what you want to do is you want to reduce complexity in your application by reducing state. So the idea is that you want as few container components as possible, and as many presentational components as you can get.
[00:00:55] My rule of thumb is I generally have a container component for a feature. So for instance we have items that gets its container component. We have widgets, that gets a container component. The reason being is you need to basically get the state from somewhere. So you basically have to have something that gets enough state to satisfy the visual requirements of that feature.
[00:01:26] As well as, you need the ability to actually convey events back up to a service to handle business logic. And so, for me, I generally try to have a Smart component, or a Container component, for every feature. Now I have seen for various reasons, that you'll have a Smart component that may have additional Smart components.
[00:01:52] So, you can have as many as you want, but really make sure that the architecture necessitates that. The fundamental reason, is that a Container component means that you are consuming state. To then feed into your presentational components. You want to reduce that as much as possible.
>> Lukas Ruebbelke: With that said, the next question is, should you break it out, your container components into modules?
[00:02:20] I personally do not do that. Where I would break it into a module is if it needed to be abstracted out into a lazy route. Or it need to be a lazy loaded component or I needed to move it somewhere else. From there the next or third question is how do two components and two different modules communicate?
[00:02:42] Well they essentially share a same top level component that they are now aware of each other. And they communicate as if they were in the same module, if that makes sense. So if you have two components in two separate modules. You need to actually import one or the other or you can import them into the top level module.
[00:03:07] And then, that serves as the mechanism to communicate from there.
>> Lukas Ruebbelke: Next question.
>> Lukas Ruebbelke: All right, are we ready to see the solution?
>> Lukas Ruebbelke: Okay.
>> Lukas Ruebbelke: So what we need to do is extract the widgets collection to a widgets service. And then essentially make it so that we can consume it.
[00:03:42] Or expose it, then consume it.
>> Lukas Ruebbelke: So we'll hop into here,
>> Lukas Ruebbelke: And I'm just going to get rid of this user's,
>> Lukas Ruebbelke: Stuff here.
>> Lukas Ruebbelke: Since I don't actually need that. Let's go ahead and delete this. So I'm just cleaning up this component,
>> Lukas Ruebbelke: All right, so let's go ahead and create our widgets service.
[00:04:26] So we'll go in our shared folder, we'll go widgets.service.ts
>> Lukas Ruebbelke: And while we're here, let's go ahead and do widget.model.ts. I'm pretty sure that the widget interface is identical to the item.
>> Lukas Ruebbelke: And then within our widget service, let's go ahead and start to build this out. So export class widgets service, and then from here, Injectable().
[00:05:21] Now remember this is a method, so we have to put the parentheses in there. And then from here, let's go into our component and let's chop this out and get it out of here.
>> Lukas Ruebbelke: So now what we'll do as well.
>> Lukas Ruebbelke: Let's go ahead and type this so this is now an array of widget objects.
[00:05:54] Reason being is that it lines up with our interface.
>> Lukas Ruebbelke: And so from here, let's go ahead and expose this. Let's do it through the barrel roll.
>> Lukas Ruebbelke: So just,
>> Lukas Ruebbelke: Exporting the service and the interface or the model. And then, let's go here. And now, we can attach this to our module.
[00:06:55] Any questions what I've done so far? I've just created a class, injectable, then I've added to the barrel roll.
>> Lukas Ruebbelke: And from here I've just imported it to the app module, and added it to providers.
>> Lukas Ruebbelke: Now let's go here, yes?
>> Speaker 2: That right there, I was just curious how you would set that typed collection, okay.
>> Lukas Ruebbelke: So you can do this another way as well. For some reason I just prefer this way. I think you can go array.
>> Speaker 2: Widget, widget.
>> Lukas Ruebbelke: Yeah, widget. So you can do this as well. So there are a couple of ways to type this, I just, I keep wanting to do, there we go.
[00:07:41] To me, this just reads better, a little more concise.
>> Lukas Ruebbelke: Now let's consume this. So if we go to our widget's component.
>> Lukas Ruebbelke: Go to private widgetsService.
>> Lukas Ruebbelke: That's what I'm looking for, right there. And one thing we are missing, actually let's do this. We'll set this to widget.
[00:08:16] And we'll set widgets to an array of widget objects.
>> Lukas Ruebbelke: And then from here, so we've injected this into our constructor. Then we can go this.widgets = this.widgetsService.widgets.
>> Lukas Ruebbelke: And just to make sure, and we are indeed consuming this. Let's go back here.
>> Lukas Ruebbelke: Boom.
>> Lukas Ruebbelke: So does anybody have any questions about what I've done here?
[00:09:21] Does this makes sense?
>> Speaker 3: I'm gonna have to do it a handful of times.
>> Lukas Ruebbelke: Yeah. Yes.
>> Speaker 2: I have a question. If I imported my widget service already in the module.
>> Lukas Ruebbelke: Mm-hm.
>> Speaker 2: And it's injectable. Why do I have to import it [INAUDIBLE] component?
>> Lukas Ruebbelke: So-
>> Speaker 2: It seems redundant to-
>> Lukas Ruebbelke: It does.
>> Speaker 2: Import it everywhere.
>> Lukas Ruebbelke: So I think actually. Let me just delete this real quick.
>> Lukas Ruebbelke: Did this not get picked up?
>> Lukas Ruebbelke: So it's under the impression, that we should put it in the module.
>> Lukas Ruebbelke: Was there, but,
>> Lukas Ruebbelke: That may not be the case.
>> Lukas Ruebbelke: Let's refresh this, oops.
>> Lukas Ruebbelke: Think about it. Okay, there it is.
>> Lukas Ruebbelke: It's interesting, I think obviously components are fine. But, hold on. So this is again what we have with language level modules and framework level modules. Is that prior to this, what you had to do prior to module.
[00:11:17] Is actually, at the Angular level, you had to inject it in. And so there are kind of some moving pieces here. It's how dependency objection works, is you're defining the dependencies, you're supplying the dependencies. And then you also can define how the dependencies are satisfied. And so this is whole going into dependency injection and I recommend reading Pascal's blog post on that.
[00:11:46] And notice that we're not having to define our widget service like this from an Angular standpoint. So that it can handle dependency injection.
>> Lukas Ruebbelke: Because Angular knows how to supply that dependency to inject it in. But from an ES6 module standpoint we have to have it at the constructor to satisfy essentially the type script dependency.
[00:12:22] So that it knows, this is being injected in here so this module has to be made available. So ng module think of it as really for the dependency injection at kind of the framework level. But you still need to do modules at the language level and that's why that's happening.
[00:12:44] So that is admittedly confusing cuz you kinda have two things happening at the same time. You have your ES6 modules then you have your NG module which is defined for mainly dependency injection purposes.