Component-Based Architecture in AngularJS 1.x and ES6 Components of a Component
This course has been updated! We now recommend you take the Angular 9 Fundamentals course.
Transcript from the "Components of a Component" Lesson
>> Scott Moss: Components. This is where the fun happens. This is where you start to see how this stuff comes together, because it's kind of crazy at first, but it's fun. So again, a component is a widely used term, but we'll be using it as a reference to a composition of functionality, UI, state, and also tests.
[00:00:23] I know everybody writes tests all the time, right?
>> Scott Moss: Yeah nobody writes tests man, I swear it. Unless you work at like Pivotal Labs or something. And then nobody else writes it. So components of a component, so here's a directory structure of what a component will look like.
[00:00:40] So let's say our component's name is profile. So we have our profile folder and inside of it we have a profile.js, a profile.directive.js, profile.controller.js, profile.whatever flavor of CSS you want to use, and a template for it and also the tests for it. So these are just the naming conventions that I came up, that work for me.
[00:01:03] You can call them whatever you want. This is just works for me. So this is not in John Popa style guide somewhere or some like that, this is just what works for me so I started using it. So this is how I organize stuff. So a little more deeply about what's happening in these files.
[00:01:19] So component.js or in this case profile.js. This is our entry file for the component. So this is like what home.js is kind of doing. Home.js is just a little more, but this is like the entry file for the component. So this is where we would start when we go to import our component, the name.js of that component.
[00:01:39] So in this case, profile.js. It creates the angular module and registers the directive to it, right? So, it's not going to define the directive, but it's going to register the directive. You'll see that means in a big difference, it's a big difference. Also, if you need it routing, this is where you would do it.
[00:01:57] So anything dealing with like angular stuff. It would go in this file. Everything else is nothing to do with angular. It's like completely outside of angular, so it's regular ES 2015, and then we're going to bring into this file and tell angular about it. And you'll see why that works in a minute, especially in testing, because you just test things without angular even caring, which is great.
[00:02:16] Any questions about that component.js? So component.controller.js, again just my naming convention, you can call whatever you want, this is the controller file where we create the controller for component's directive. That's why it's called controller.js. But the key right here is the controller for our component's directive. It's not a controller for a template, just willy nilly somewhere else we'd have to reroute.
[00:02:43] Its not that. It's an actual controller for a directive. That means all our directives will have controllers now. We won't be using- you know like when you make a directive, you'll never put a controller on a directive unless it's like a container directive and has like mini directives inside it.
[00:02:58] Like if you were building a tab system, they have like a tab container directive, and it has a controller. That's the only time you'd ever use a controller, other than that you'd just use link, right? Not the case anymore. You can use a controller like every single time now for your directives.
[00:03:10] Then, of course you will use links when you have multiple instances of the same directive, but if they all use the same controller, then you might have some problems. So you might need links then, but at very minimal they all will probably have controllers. Unless they're like attributes and not components themselves.
[00:03:25] So yeah, this is where we're gonna find our controller, inside this file, and it's gonna belong to the component.
>> Scott Moss: So component.directive.js, this is where we create the directive that will be the meat and potatoes of our component. So it also has a responsibility of importing the styles and the template.
[00:03:44] So we know that, from this directory structure here, we know that each component has a template, and it has some styles associated with it. So inside of the directive file, its job is to import the styles and the template. Yes?
>> Speaker 2: This is sort of inverting my sense of the stuff I'm working on.
[00:04:05] Is that the controller has like everything, you know, it's really like huge, and the directive is about this big.
>> Scott Moss: Yes, so the whole point is you want skinny controllers.
>> Speaker 2: Okay.
>> Scott Moss: You don't want big controllers. The smaller your controllers can be, the better they're going to be.
[00:04:21] And I'm going to show you how to do that. And that's, mainly, pretty much putting everything in a factory or service. Pretty much.
>> Speaker 2: Okay.
>> Scott Moss: Because what happens is, the reason you're controllers are big is because you're making maintaining state.
>> Speaker 2: Yeah.
>> Scott Moss: If you don't need to maintain state, then your controls go from this to this, right?
[00:04:35] I'll show you put about that when we get to the common components section. The directive is where it imports the styles and the HTML, and it creates the function that's gonna be called by angular to return the DDO, or the directive definition object. So the other files are self-explanatory, when I say other files, I'm talking about the spec, the CSS, the HTML, they are exactly what they say they are.
[00:05:02] So, this set up allows for easy testing and flexibility, reusability is on the maximum for sure, because we're creating a new module each time. So again, I can take that module and put it in, anybody's repo who has the same dependencies and build system as me, and it should work exactly the same.
[00:05:20] Unless they're messing around with, we have like CSS name clashes or whatever, but it should work exactly the same.
>> Scott Moss: But one more thing you also need to do is that- so we create these components, but they're still not gonna work. And you probably found out before, you have to register the components with some type of parent, right?
[00:05:41] So like in our example, we have home. If we didn't export this home and imported somewhere else, we would never know about it. It would just be here, it'd just be a file. It's just like downloading something from bower, and like never adding a script tag. That's exactly what would happen.
[00:05:59] That's all you did. So you need to export it, and then import it somewhere else. And because your using angular, not only do you need to import it, you also need to register it with the angular module too. So you gotta do two things. Import it to ES 2015, register it with angular.
[00:06:12] So remember that, that's all you gotta do. So that's why app.js, we imported it, and then we registered it. So remember you have to do that. If you don't, it'll just be sitting there and nothing will happen. Any questions on that? Remember that. People always forget that. Totally remember that one.
[00:06:33] I forget that one all the time. I got stuck for three hours one time. Because I couldn't figure out why this thing wasn't working. But I was like 30 components deep, and I couldn't figure it out. There were no errors because the thing never got loaded up. So because webpack allows us to treat anything as a module and has an extensive plugin community, we can import more than just javascipt files.
[00:06:54] So we talked about this, right? So like css/stylus/less/sass, anything. PNG's, JPEG's, again, anything we want to import, we can import it. You just have to find an appropriate loader. And in fact, if you try to import something with webpack and it can't, it will tell you like, "Yo, I don't have the loader for this".
[00:07:12] It'll just tell you like "I don't know how to handle this, you never told me how to handle this". "I can do it, you've just got to tell me how". It'll tell you in the terminal, I don't know, I don't know what you want me to do, just figure it out.
[00:07:23] So it can handle anything. This setup is exactly like web components. It's very similar, at least, except for one thing, and that's the CSS closure. Does anyone know what I mean when I say CSS closure?
>> Speaker 3: But good morning. CSS closure?
>> Scott Moss: CSS closure, yeah. It's a real thing.
>> Speaker 3: Like CSS that only knows about- it's encapsulated.
>> Scott Moss: Yeah the CSS is encapsulated. Like with a directive, we make an isolate scope, our job description is encapsulated, and that's great. But there's nothing protecting our CSS. So, if I were to bring my component in your angular file inside of my home.style.
[00:08:03] I had this stuff, right, and mine got a loaded up before yours did, and then you had another file that also has some stuff like this. Yours would overwrite mine, I don't have any closure, I need protection. At web components you do. You have to like specifically go into the web component, like I really want to change this, right?
>> Speaker 4: You kind of like, if you go back to that kind stylus file.
[00:08:38] And you kind of like name space those, like if this is like less for you that you have invested? And the title and items, and then they're kind of, they have to be within .home.
>> Scott Moss: Yes they have to be. Yes, I mean there's ways you can make a really really hard, almost impossible.
[00:08:54] Even webpack will allow you to, I don't know the exact syntax, but it will allow you to use something like hash, or something like that. So you can like get the hash of this file. And you can use that inside of- like, it's crazy. So you can make it as unique as possible but like-
>> Speaker 4: You are still affected by real general.
>> Scott Moss: Exactly. So there's still a possibility. And then, it's like now you can't even read it [LAUGH]. So it's like what's the point. So there are some edge cases there. So yeah, no more link tags, no more script tags. There are some cases where you still will need to add link tags and script tags.
[00:09:34] Everything is not on MPM, right? How do you handle stuff that's not on MPM? Everything is not on there.
>> Speaker 4: Put it on MPM.
>> Scott Moss: You could put it on MPM. There you go. That's a solution. Get you some green dots on your GitHub, you can put it all on MPM.
[00:09:46] Or, let's say you wanted to use bower, you want to download some stuff about from bower, webpack will allow you to actually import bower components. By default it doesn't, but you can use- webpack actually has an extensive plugin system that you can teach it new tricks. Hey webpack, not only do I want you to look in the known modules for it, I also want you to look in, you know, wherever your bower stuff is, whether it's components.
[00:10:13] Wherever you put your bower stuff, bower components or lip. You tell it to look in there and look in the bower.JSON. And it will load those things up too. Now, how it handles those things, that's up to webpack. If it detects that it's AMD or common JS, it'll take care of it.
[00:10:28] Hopefully the the person who made it is responsible and decided to build it with UMD in mind, which is universal module definition, which means it'll work in common JS, the browser, AMD. Hopefully they decided to do that, but if not, they'll just load it up on the global windows space.
[00:10:43] So that's probably what will happen. Yes.
>> Speaker 5: Scott, I got a got two questions here, one from Danielle M asking, is there a way to do these CSS and ES 6 to JS transformations as a build step for like a distribution. So like right now we're- our bundled up JS is loading those dynamically, right?
[00:11:04] We don't have on our distribution index.html some style tags.
>> Scott Moss: Right, right right.
>> Speaker 5: Import, or script tags, or anything like that. Is that something you would do differently in production?
>> Scott Moss: Yeah, so in production, I might just keep it all bundled, but if I was making a library.
[00:11:44] So start all those entries files and make bundles of all those files and their modules, and then split those out at whatever destination you tell them to. But that's a more advanced configuration, but yes, you can slowly do that, and in fact I think that's the best way to build lives from here on now.
[00:11:58] It's just using something like that because it super easy. Yes other question.
>> Speaker 5: The other question I think is actually answered. It was a question from Heratio H.about, what about using iffys, but our bundle.jss is wrapped in an iffy, so we're not flirting with global namespace in any sense here.
>> Scott Moss: No we don't need any iffys, unless you want an iffy in your iffy. You don't need any iffys. So yeah we're good. That's the whole point. So if I were to come in here and- pretty much there's no iffy, so we're fine. But what happens is, because all this stuff is bundled up.
[00:12:35] Let's say I import angular in app.js. I import angular. I have this thing at the top. And all this is going to be bundled, so that means angular is at the top of the file. And then, this imports home.js, so home.js goes and gets bundled at the bottom of app.js.
[00:12:51] So technically, home.js should have access to the angular in that same file, right? And if it ran in a browser, it would. But Babel wanted to compile if you don't import angular in the other files. So even though, honestly speaking, if this home.js, was, if I didn't have this in here, and this is an app.js too, if I have that in here and this ran in a browser and bundle.js, it will work, but Babel won't even compile.
[00:13:17] Because Babel doesn't know about app.js when it's looking at this file. All it does is it sees angular here, and it's like where's that coming from? Right, it won't even compile. But it will run in a browser, so remember that.