To help facilitate your learning, Joe and I have created practice exercises for a lot of the concepts taught in this course. When we learn a new technology, it's always helpful to be able to practice what we're learning. While it's certainly helpful to your learning to follow along and create the demo application that's demonstrated in this course, there is a lot of valuable learning that can come from trying to do something without having all of the answers provided beforehand. We seem to really cement our learning when we have to figure out why something we've done isn't working like we'd expect. It helps to break down misconceptions in our learning. So, for many of the clips in this course, we've created related practice exercises on Plunker. The's practice exercises are all available on my website at this URL, and we'll let you know at the end of each clip if that clip has a corresponding practice exercise. You can then find the practice exercise on this page, which is organized by course module and then by clip. For each exercise, you'll find a link to the clip in the course, a link to the Plunker exercise, and a link to the finished example for you to compare against when you're done or for you to use to get clues from. So if I click on one of these practice exercises, notice that it takes me to Plunker, and the instructions for this exercise can be found here. Read these carefully, and you should be able to finish the exercise with what you just learned in the course. And you can get back to these instructions at any time by clicking this button over here. If you're not familiar with Plunker, here's how it works. Here are all the files for this Plunk. You can just click on these files to edit them or add new files in order to complete the exercise. Notice that to put a file into a subfolder, you just name that file with the folder name followed by a slash. Then to try out your project, you just click Run. Notice when I run this that Plunker just displays my running site here, starting with the index.html like a normal web server would. And depending on the exercise, you'll see something different here, and the app may be broken and you'll have to fix it. Or it may be working, and you'll just need to change something about it to finish the exercise. And if you get stuck or just want to compare your solution to our solution, you can come back to the list of exercises and click on this finished link to see our finished version of this exercise. We hope you'll enjoy these fun little exercises, and hopefully they'll help you cement what you're learning in this course.
When the Angular team released Angular 2, it was a dramatic shift from Angular 1, and now they have different product names. All Angular 1.x versions are now referred to as AngularJS, and all versions starting at Angular 2 and above are referred to as Angular. Let's take a quick look at a couple of high‑level differences between AngularJS and Angular. Angular 1 was pretty much an MVC, or model‑view‑controller, framework. Angular 2 and above kind of departs a little bit from that, although it's not difficult to relate the concepts together. In AngularJS, you had a view or a template, and the view would refer to a controller, and your controller would expose models or objects that represented your data. In Angular, you have a component, and that component has an associated template. And, as with Angular 1, you have models that represent your data. So at a glance, you can kind of relate these together. However, in Angular 1, the template was kind of in control. Your template would identify one or more controllers that controlled sections of your page, whereas in Angular, components and templates really are one to one. In fact, you can kind of consider the template to be a part of the component, and you can actually write your code like this and have your HTML right inside your component if you choose. In this way, a component in Angular is actually more comparable to a directive in Angular 1. In Angular 1, you could define a directive that allowed you to basically create custom HTML elements, which encapsulated both display and functionality in a more cohesive unit. If you wanted a sortable list component that let you display an array in a stylized table with sortable columns, you could just create a directive that gave you a sortable list element. And the directive contained all the logic and HTML to make it all come together. Something about the directive bringing it all together made it feel very cohesive. That's basically what components are, except it feels a lot smoother. As awesome as directives were, they often felt clunky, and you'd run into weird edge cases that were quite difficult to solve. Components feel much more smooth.
Okay, we're going to dive into code real quick here. But first, let's take a high‑level look at Angular. Once we understand the conceptual model of how Angular works, it will be easier to understand each of the pieces as we start coding them. So let's take a graphical look at an Angular application. When you navigate to the URL of an Angular application, there is always a root application component that is loaded first. And then the Angular router takes a look at the URL and says oh, I have a component that matches that route, and it loads that component. The component's template is then displayed in the browser, and the component may then load some data from the server and give it to the template to be displayed. Of course, if this page is very complex, it's likely to be composed of lots of smaller components. And those components may be composed of other components. And so this kind of ends up creating a tree‑like structure. It's helpful sometimes to think about your Angular app in this way. So here's the tree view of our imaginary application. Now imagine what happens if a user navigates to another URL. Well, then basically, you start a new tree, except that your app component remains. The router sees the new route and loads the corresponding component and all of its subcomponents. And this repeats for all of your routes. As your application gets bigger and bigger, this can become a lot of stuff to load into memory. This is where Angular modules come in. Don't confuse Angular modules or NgModule with ES2015 modules that we've been talking about before. Angular modules are meant to be containers that group all of these routes or component trees and their corresponding bits of code into modules that can be loaded independently of each other. That way, if a user only ends up visiting this section of the site, only these files will get loaded, and the browser will only load these other files if the user navigates over into this section of the site. This is one of the main purposes behind Angular modules. You don't have to use multiple modules in your app, but as your app gets larger, you may consider it. One more high‑level concept regarding modules that is important to mention is how modules are used to make components, services, and directives available to the rest of your application. When you create a component, service, directive, or pipe, you register it within a module. That makes that object available for use by everything else in that module. And with all of these, except for services, they are now only available in that module. If you want to use them in another module, you must register them with that module also. That's true for all of these, except for services. Services or providers get registered in the root injector, so they're available across Angular modules. So that's kind of our high‑level view of Angular applications. Let's take a look at what we'll actually be building in this course.
Okay, let's take a quick look at the demo app we'll be building in this course. We'll build an application that displays and allows users to create technology events or conferences. The starting page is this page that lists all of the upcoming events. From here, we'll add the ability for users to create new events using this Create Event form, complete with validation. And then we'll wire things up so that users can click on one of these events to see more detailed information about that event. This page displays sessions for the event, and users can vote on the sessions that they like. You can even create a new session for the event. And we'll even add the ability to sort and filter the sessions to find what you're looking for. We'll also add in some basic authentication and edit profile features. If this app looks familiar to you, you may have watched the Angular 1 Fundamentals course. This is the same application that we built in that course, which gives you the ability to compare how things used to be done with Angular JS and how they're now done with Angular. So without further ado, let's start writing some code.
We're going to need a few tools installed to get going. First, we'll need Git installed. I'm on Windows, so I'm going to use Git for Windows, which can be downloaded from here. If you're on a Mac, you can install SCM Git from here. And if you're on Linux, you can just run a command like this one from the terminal. I'll go ahead and download and install Git for Windows. And then I'll run that, and I'll just use the defaults throughout the install. And now that that's installed, I have this new Git Bash console that I can run. So we'll use that in a minute. And actually, while I prefer to use this Bash console, sometimes Windows users have issues with it. So if you're getting weird errors, try using the Windows console window instead. The next thing I need is Node. I prefer to install Node using Node Version Manager just because it makes it easier to switch between versions of Node as I develop different applications. On Windows, I can download that from here. For Linux and Mac, you can just run this command from the terminal. Of course, these each have their own README with instructions about installing them, so you may want to read through those for your environment first, but I'm going to go ahead and install this on my system. So I'm going to go ahead and install NVM for Windows, and I'll just use all the default options here too. Okay, now that that's installed, I'm going to open my Git Bash console. On Windows, be sure to open it as administrator. Okay, now that I have NVM installed, I can just run nvm install and then the version of Node that you want to install. It's recommended that you use this version for this course if you're following along to avoid any compatibility issues. And now I can just tell NVM to use this version of Node. Okay, We're good to go with Git and Node now. If you have problems using NVM to install Node, you can try installing it directly from here. Just choose the correct installer for your system. Okay, let's get coding.
Okay, so here's the Git Bash console that we just installed. The best way to get started with a new Angular project is to use the Angular CLI. The Angular CLI is a command line interface that we can use to create a new project, complete with Webpack config and tools for packaging up your app for production plus a host of other features. It's highly recommended that you always start your projects with the CLI. So to get started, let's install the Angular CLI. We can do that with npm like this. This will install the Angular CLI globally so that we can use it to create new projects. And in order to avoid any issues for those who are following along, we're going to install a specific version of the CLI like this. We recommend that you use this version of the CLI if you're following along just to avoid any surprises with new versions. Okay, now that that's installed, we can create our new project like this. So this will create a new folder named ng‑fundamentals, and it will generate a new Angular project with Webpack and everything we need to build for production. So let's go ahead and do that. Now depending on your environment and due to an apparent bug in the CLI, you may or may not be presented with a couple of questions like these here. If you are, just say no to adding Angular routing and choose CSS for the style sheet format. We'll add those things later. As you can see though, in my environment, I didn't even get prompted, which is fine. Okay, now that that's complete, let's go take a look at what it generated. So I've opened up that new folder in Visual Studio Code here. And here's the project the CLI created for us. So notice that it created a number of things, including a package.json file and this angular.json file. This file is used for configuring a number of settings for our project that the CLI will use for various things, including its Webpack build. And it created this end‑to‑end testing folder and installed some npm packages for us. And then, if we look at this src folder that it also created, you can see that it created this app folder. This is where you'll do most of your coding in an Angular project. And it also created this assets folder. This is where you put static assets like images and sitewide CSS files, etc. We'll take a look at this in a minute. For now, let's go make some small changes to this package.json file. You can see we're installing approximate versions of our dependencies. For the purposes of this course only, I want to pin these exact dependency versions so that anyone following along won't get surprised by any dependency version changes. So I've already created a package.json file with the exact pin versions that were installed by npm at the time this course was written. In order to make this easy, we've created a little GitHub repo for this course where we can grab a few files like this throughout the course. It's available at this URL here. So you can see down here that we have this package.json file. So I'll click on that and then look at the raw version here and then copy everything out of here. And then I'm just going to paste that in here. Okay, so you can see that the versions here are now specific versions, and we're not using the carets and tildes anymore so that we'll always install these specific versions. Now we just want to do one more thing to ensure that you're definitely working with the same package versions that we are in this course. Over here, you can see that we also have a package‑lock.json file. Let's grab that too. So let's look at the raw version and then copy that. And then we'll come over here, and we'll open up our package‑lock.json file here and select everything and then paste over the top of it. Now there's just one last thing that we need to do in order to make sure that you're using the same package versions. If we come back over to our terminal window where we created our project with the CLI, let's go ahead and move into the folder that it created. And now we're going to delete the npm packages from our node_modules folder, and then we'll reinstall them. Again, all of this that we're doing with the package.json files and reinstalling the npm packages isn't necessary for normal development. This is just to make sure that those that are following along with this course don't get hung up if some dependency makes a breaking change. Okay, so now that we've deleted those packages, let's go ahead and reinstall them. Okay, excellent. So now we're back at the point where we've generated a project with the CLI and our package versions are locked in. So now all we need to do is run it. We can do that like this. Okay, so you can see that this is now running at port 4200. So let's go check that out. So over here in my browser, I'm just going to navigate to localhost 4200. And here you can see that we have a fully functioning app, and it just generated this default boilerplate HTML. Now let's go take a deeper look at what the CLI did to get our new Angular app bootstrapped.
As we saw in our last clip, the Angular CLI created a fully‑functioning Angular app, including everything needed to Bootstrap this app. But it's really helpful to understand how an Angular app is Bootstrapped, so let's dig into that a little bit. We talked earlier about the hierarchical component tree, and at the top of that component tree is the app.component. And as you can see, the CLI created our app.component for us here. Notice that the component is composed of three files, the component, its template, and its styles. We'll talk in depth about components in the next model. Just be aware that the template from this app.component is what's being displayed when we load our site. So let's look at how that's wired up. The Bootstrapping of our app begins with this main.ts file. And if we look over here in our angular.json file, you can see that this main property is pointing to our main.ts file. This is used by the webpack.config for our site, and it causes this main.ts file to be loaded when our app first loads. And you can see right here that we are Bootstrapping our app with our AppModule. if you remember from earlier, Angular applications are grouped into models, and every Angular application has an AppModule. That module is defined here, and you can see that the AppModule is Bootstrapped with the AppComponent. So that's how Angular knows about our AppComponent. But there's one more piece. This makes Angular aware of our component, but we haven't seen yet where we tell Angular to actually display this component. If we look at our AppComponent, you can see that it has this app‑root selector. This selector defines the HTML tag to use in order to display this component. And if we look over here in this index.html file, you can see that we're using that app‑root selector right here. This index.html file is what is first displayed when our app loads, and it is loading our AppComponent. So that's how this all comes together. Now to show that there's nothing magical about the naming of this AppComponent, let's just rename this to eventsapp.component. Remember our app that we're building is a website that will allow users to find technology events. So we'll call this the eventsapp.component. And instead of renaming its template and CSS files, we can just inline them. We'll talk more about this later, but let's just delete this template file and this CSS file. There wasn't anything in here anyhow. And then here in the component, let's just change this selector to events‑app, and then we'll change templateUrl to just template, and hard code some basic HTML here. And then since we're not applying any styles to this component, we'll just delete the styles. The CLI also created this specs file, but Joe will talk about testing later in the course. And so for now, we'll just delete that. And finally, let's just rename the Component class to events EventsAppComponent. Okay, now that that's done, we just need to go update a few places that reference this component. So first in the app.module,, we need to fix this import, so this will be EventsAppComponent, and we'll import that from events‑app.component, and then we need to declare that and Bootstrap our app with it. So notice there's nothing convention based about the name of the AppComponent. It's really here that we tell Angular which component is our main top‑level AppComponent. And then one last place we need to update is over here in our index.html because we changed the selector. So this is going to be events‑app. Okay, cool. So now if we go check out our site, you can see that it's still working, and now it's using our new template. So to recap the whole bootstrap process, the main.ts file is loaded by webpack via the angular.json file. Then the main.ts file loads our app.module, and that makes Angular aware of our AppComponent. Then our index.html file is loaded in our browser, and it loads our app.component,, which uses this template here, and that's it. So that's the basics of how to Bootstrap an Angular app. Next, we'll take a look at how to pull in some static resources into our site.
You'll get some more experience with modules as we add different components, services, directives, and pipes to our app throughout this course. But since the CLI created an AppModule for us, let's take a brief look at it. We talked in an earlier clip about the purpose of modules. This is our first chance to see what one actually looks like. Specifically, I just want to mention these three sections, declarations, imports, and providers. When you want to add a component pipe or directive, you must declare them here like we're doing with the EventsAppComponent. Services, however, are added as providers here, and this imports array is used for importing other modules. Importing a module makes all of its exported declarations and providers available to this module. So you can see we're importing Angular's BrowserModule here. This makes a number of core Angular services and directives available to us that are commonly used throughout the Angular app. Pretty much every Angular app will import this in the AppModule. If you create a service component pipe or directive, you need to be sure to add it to a module before you try to use it. You'll get some experience with this and with creating other modules like feature models as you explore this course. I also explore, in depth, the different types of modules you can create in my Angular Best Practices course. So feel free to check that out if you find yourself wanting to learn more about modules after this course. For now, let's delete this providers array since we don't currently have any services. We'll add this back later. And I kind of like to have imports at the top here since declarations and other things depend on those imports. There's no real technical reason for doing this. This is just a personal preference. Okay, cool, so that's our AppModule. Now let's go take a look at how to use static assets in our site.
In this module, we explored some of the prerequisites for this course, and then we took a look at a conceptual overview of how Angular apps are architected. We then looked at the Angular CLI and how to use it to create new Angular apps. We also explored the app component created by the CLI and how the CLI Bootstrapped our Angular app. And finally, we learned how to pull static assets into our app. All of this sets us up really well to get started building our demo app and exploring Angular. In the next module, we'll learn the fundamentals of Angular components as we start creating our own components, and explore a host of concepts related to creating, styling, and communicating between components.
In this module, we're really going to get into the meat of components. This is where working with Angular really starts to get interesting. We'll start by creating a component with an inline template and data binding, and then we'll take a look at how to optionally move that template into an external HTML file. Next, we'll explore the various ways to communicate between components, and then we'll see how easy it is to apply CSS styling to our components. And finally, we'll explore how Angular provides built‑in encapsulation of CSS styles to prevent them from bleeding out to other components. So let's jump right in.
Okay, now let's see how we can move our template HTML out into its own file. For very simple components, it's really nice to have the HTML right in the component, but often there's enough HTML that it's easier to have it in its own file. So let's create an events‑list.component.html file right here next to the component. Then, we'll copy this HTML out of here and into our HTML file. And since this is no longer in a string literal, we don't need to escape our dollar sign anymore. Now in our component, instead of using template, we just need to do use templateUrl, and then we just provide the URL here to our template. And notice, this URL is relative to our component. And now if we go take a look, our app should look the same. There we go. It looks exactly the same, except now we're loading our HTML from a separate template file.
Okay, so we've covered how to communicate in and out of components using input and output properties, but there's one more way that we can use to access public properties and methods of a child component, and that can be quite useful for different use cases. This approach can be used to call methods on a child component or to bind to data in a child component. And we can accomplish this using template reference variables. Template reference variables allow you to specify a variable name that points to a component, and then you can access any public properties or methods on that component using that variable. So let's check this out. Let's add a variable name to our event thumbnail component, and we'll just call it a thumbnail, like this. Now this variable is available for us to use anywhere else in our template. So let's go create a public method on our child component that we can call. So over here in our thumbnail component, we'll just create a method called logFoo. And, of course, that will just log foo. Alright, now back in our parent component, let's just add a button that when we click on, it can call this new method on our child component. We'll just add that right here. And then we're going to wire up our click event to our thumbnail local variable, which is a pointer to a component, and so we can call the logFoo method on that component. Okay, let's save everything. And then let's go check that out. I'll refresh and there's my button, and this is on my parent component. If I open up the console and then click this button, you can see that it logged the word foo. And so we were able to call thumbnail.logFoo and thumbnail is pointing to our event thumbnail component, and over in our EventThumbnailComponent, this is where we actually logged foo. So you can see, this is actually a public method on our EventThumbnailComponent, and you can see how we're able to access that using a reference variable. I really like how straightforward that is. In some ways, this is more simple than input and output parameters, and there's another use case where we can use this template variable, and that is if we want the parent to bind to a public property on our child component. So let's add a property on the thumbnail component. We'll just add that right here and we'll just call it someProperty. And let's just set that to a string. And now we can access that someProperty property over in our parent component using our template variable. So let's add an h3 here, and then we'll just bind directly to this with interpolation. So again, here we're using our thumbnail local variable, and we're going to access some property. Okay, let's go check this out. Alright, you can see that some value is being written out here to our parent component, even though that value is in our child component, and we can access that using our thumbnail template variable. Okay, so those are the three different ways that you can handle inter‑component communication; input properties, output properties, and template variables. And we're not going to need this template variable stuff. So let's just go ahead and clean that up and we'll clean it up over here in our child component, too. Okay, that's all there is to local variables. And there's a practice exercise for this clip so go check that out.
Let's take a look at how we can apply CSS styles to a component. Typically, when you want to apply styles to a web app, you'll create CSS files that contain your styles, and there are lots of different approaches to doing this in a maintainable way. With Angular, you can still handle CSS as you would with any other app, but Angular components have some built‑in functionality for applying styles to your component that can be very useful. First, let's look at applying some simple styling to our event‑thumbnail component. If we take a look at our template, you can see here that we're using a non‑breaking space to add some blank space between the address and the city. Let's use a class to style that instead. So let's delete that non‑breaking space and add a pad‑left class to the city span. Now in our component, we'll add a styles array to the component config. The styles array takes an array of strings, but typically you'll just provide a single string with all the styles for your component. So let's add our pad‑left class here. Cool! Let's go take a look at that. Okay, here's the current padding with the non‑breaking space. If we refresh, there, you can see we're getting a little bit more padding, but we no longer have that non‑breaking space in there, so the padding is coming from our class. All right. Now let's add some styling to our text. We'll slightly change the color of the event details, but we'll leave the event name alone. So we want to style all these divs inside this well, so we'll just add this class, and let's see what that does. Okay, now the text is a little darker. So it's kind of cool that you can put your styles and your HTML and your component all together like this in one cohesive piece. It's really that easy to just add styles to your component. It's worth noting here that just like we can put our HTML template in a separate file, we can also put our CSS in separate files and refer to them here. We just use style URLs instead of styles and provide an array of URL strings for our style sheets. There's a little bit more that we're getting for free with our styles here, and we'll talk about that in our next clip. And there's a practice exercise for this clip, so go check that out.
Now if you've done much work with CSS, you may be thinking we're headed for big trouble because we just added a fairly broad CSS selector. Typically, if you add broad CSS selectors like this, you run the risk of changing the style of every div within a well across your entire site. In order to avoid this, it's becoming common to use some sort of namespacing type standard such as BEM or SMACSS, where your class names have the names of components or pages appended to them, or there is some higher level class that contains all of your code. Then when you apply styles to your elements, you style them using very specific class names. This can become cumbersome, and can really interfere with the semantics of your code. Fortunately, this is all taken care of with Angular. Let's take a look at how this works. Just to make it a little more obvious, let's change the color of this class to red. Now let's go over to our events‑list component, which contains our thumbnail component, and add some content to demonstrate this. Before we show our event‑thumbnail, just above our event‑thumbnail let's add a div within a well like this. So this matches this CSS selector here. In a traditional HTML app, a style like this would get applied to the whole site once the style is loaded. But if we go look at our site now, I'll just refresh this, you can see the style only got applied to our child component where we added the style. It did not affect elements in the parent that matched that same CSS selector, so Angular is taking care of encapsulating our CSS styles and causing them to affect only the component where they're added. You might think that this is working this way simply because we've added it to a child component. What if we add this style to a parent component instead? Will it affect the child components? Let's take a look. So let's move this style over to the parent component, so we'll need a style attribute. Okay, let's go take a look at this. Okay, notice here that it is only now affecting the parent and it is not affecting the child. So Angular really is just scoping this to the component where we've added it. So what exactly is going on here? This is Angular's built‑in view encapsulation. If we take a look at this element in the HTML, you can see that Angular is applying attributes to all of these elements. Notice that our parent component has this attribute applied to it ending in ety‑2, but the child component, its elements have an attribute that ends in ety‑3. And then if you look at the styling or the classes that are being applied, here is our selector we created, .well space div. But angular has added this attribute ngcontent‑ety‑2. This is a randomly generated string, so Angular has modified the CSS selector to say only apply it to wells that have an attribute of this ngcontent ety‑2 and to divs that have that same attribute, and this is how Angular targets only the elements from that component. So this CSS was made very specific, without us even having to think about it. This is great. We get safe namespace to CSS without any thought on our own part. Now, one thing to note is that we are getting global styles applied across our site, or in other words, styles from our styles.css and our Bootstrap styles. To demonstrate this, let's go over to our styles.css and add a style that targets h2 elements. Okay, so now all h2's across our site should be green. Let's go take a look. Okay, sure enough, you can see that this h2 element turned green, and so you can use global styles that apply across your site, and you could even use BEM or SMACSS or something else in order to organize your global CSS, but when you want your CSS to be very specific and tied only to your component, which is actually quite often, Angular just takes care of it for you, and you can mix global styles with component‑specific styles, which we will be doing throughout this course. So that's a good demonstration of how CSS encapsulation works with Angular. Let's go clean up some of this stuff that we don't need anymore. So we'll get rid of this h2 styling, and we'll move our style back over to our thumbnail component and change it back to its normal color. And then we can get rid of this Hello world div over here. And then one last thing that I wanted to mention that we're not really going to cover in this course is that there is a way to get around this CSS encapsulation if you want to apply styles to a child component. All you have to do is apply the deep selector. That's fairly well documented, so if you find you have a need for it, go check that out.
Okay, just to demonstrate that the app component is no different from other components and to get a little more practice creating components, let's add a site header with some navigation elements to our app component. So right now, in our app component, our template is just displaying this events‑list component. Eventually, when we add routing to our application, this component will be replaced with a router‑outlet component, and as we navigate around the site, each top‑level page component will be displayed here. So we want to add our navigation component above this. The nice thing about this is that this navigation element will be displayed on every page, since it's in our top‑level component. This will make more sense later when we had routing. For now, let's just get the navigation element showing up. Okay, so first, let's create our component. This component will be mostly used for navigation, so let's create a new folder for it called nav. All right, now let's create the component. All right, and then let's create our basic shell for our component. Okay, there's our basic component. Now the HTML for this component will be a little lengthy, so let's use a separate template file. Okay, now, let's go create that file. All right, since the HTML is a little long for this component, and typing it in isn't too helpful to learning Angular, we've added a GitHub repo over here. And this is where we'll share a few helper files for this course. So let's just grab that HTML from here. So it's in src/app/nav, and it's this navbar.component.html. So let's just go to raw view, and we'll copy that out of here, and then we'll just go paste that into our template file. All right, cool. Now I'm not going to spend any time explaining this HTML. It's all just simple HTML, and there's no Angular code in here. And all of the CSS classes currently used here come from Bootstrap. So this component is basically ready to go. So let's just go add it to our main app component, and again, we'll add this above the events‑list component. So let's change this to a string literal and then we'll add it here. Remember, nav‑bar is the selector that we gave to our new component. Okay, cool, now we have this nav bar that will show up at the top of our application, and then the page components will show up underneath that. Okay, let's not forget to add our new component to our module, so we'll just import it here and then add it to our declarations. Okay, that's all there is to adding this component, so let's save everything, and then let's go make sure our web server's running. You might have it running already. If not, go ahead and start it up. All right, let's go refresh our app. So if I refresh here, cool, now we have this nice nav bar up here. But we have some strange font issues going on here, and we'd like a little bit more spacing over here to the right of our search component. So let's go add some styles to our component. So I'll add styles right here. So first, let's address the font size for everything in the nav bar, and then let's add some margin to the right of our search form. Okay, and then we need to hide our search form that's in our nav bar if the browser window gets too small, so let's make that happen. Okay, let's check that out. All right, that looks a lot better. Okay, so now we have this new component, and hopefully that helped you see what the flow is like to add a new component to an app. Okay, that's it for components. In our next module we'll take a look at some more Angular syntax.
In this module, we created our first date‑bound component, and we saw how to use an external template for our components. We also learned about a few ways to communicate between components and how to style our components. And finally, we learned how Angular keeps our styles encapsulated to just the component where they're defined.
In this module, we're going to explore all the fundamentals of template syntax in Angular. We'll start off by looking at interpolation and expressions, which allow us to bind to and display data in our templates. We'll explore what is and what is not allowed in expressions and the types of behaviors that are discouraged in expressions. We'll then take a look at the syntax for binding to DOM events and the statements that accompany them. Then we'll look at how we display repeating data with ngFor. To do this, we'll display a list of events on the Events List page instead of just a single event. In this module, we'll also take a look at how to optionally remove elements with ngIf and how to do that in more complex cases with ngSwitch. We'll also look at how to hide DOM elements by binding to their hidden property and when you might want to do this versus removing them with ngIf. And finally, we're going to take a look at various ways to programmatically add and remove CSS classes and styles to and from DOM elements. So let's go take a look.
Okay, so we've looked at interpolation, property bindings, and expressions. Now let's take a look at event bindings and statements. This event binding is binding the button's click event to the doSomething function on our profile component, so that will be called when this button is clicked. Notice that event bindings use parentheses around the element event to bind to, versus property bindings that use square brackets. And notice that statements follow an event binding and are put in quotes. Let's take a look at the guidelines for template statements. Template statements have similar restrictions to template expressions, with a couple of exceptions. Statements actually do allow you to make assignments using equals, but assignment operators other than equals are still prohibited. And then you actually are allowed to chain expression statements. But these other restrictions still remain for statements. And as far as recommendations for statements, they actually can have side effects. In fact, they often do. It's pretty much the norm for statements to make changes to the state of the application, so therefore, they are also not required to be idempotent. And while you never want any part of your application to actually be slow, statements typically will end up calling a function or something that makes an AJAX call or something that's slower, so there isn't quite the same requirement for them to be fast. So the only real recommendation for statements is that they should still be simple. Again, you shouldn't be doing a lot of business logic in your templates. They can, however, call a function on the component that is more complex. So really, this is the only recommendation that remains for statements.
Before we jump in, I just wanted to remind you that we've made changes to this course to keep it up to date. This course was originally created without the CLI since it was still in beta. Because of these updates, you may notice some inconsistencies in the File Explorer over here. Mainly, this app folder is now nested inside a src folder, and these files at the root of the project have changed. However, almost everything we'll be working on will be inside of this app folder, and everything inside of that folder will be consistent other than that this assets folder has been moved out. So don't worry about the inconsistencies you may see outside of this folder. Okay, the events application that we've been writing has been desperately waiting for us to demonstrate ngFor. So far, this Events List page has been listing only a single event. Let's update our application so that it can display multiple events. NgFor is going to make this very easy for us, and the fact that we've encapsulated all of the display logic for an event into this event thumbnail component is going to help. So first, let's update our data to have more events. Currently, we just have this one event object here. Eventually, we'll have this data come from an API call, but for now, we'll just leave it right here. This is going to be a lot of data, so we're not going to want to type all of this in. So this is another file that we've provided in our helper repo and GitHub. So in this repo under the misc directory, there's this event‑data.js file. So let's look at the raw view for that. And we'll copy all of this, and then we're just going to paste it all in right here in place of this event object. Okay, so you can see, this is now an array called events. And that array now contains multiple event objects. And the event objects are the same shape as they were except that they have a little bit more data. You can see that we've added sessions to the events. Don't worry about that right now. We'll use that data later. All of this data is really obnoxious in our controller. We'll move that out of here when we talk about services in the services module, and eventually it'll come from an API. But for now, it'll just stay here. So our page will be broken right now because we were binding to an event object that was singular. And now we have an events plural array. And so up here, we just need to use ngFor to bind to our new events array. So we just want to put the ngFor directive on the element that we want to repeat for each item in the array, so that's our event‑thumbnail element, so we'll add it here. Okay, and then we'll leave this binding here, except that it's going to bind to event instead of event1. And that is the same event as this one right here. So we'll come back and dissect this statement in a minute. But for now, let's go over and take a look at our web page. So if I refresh this page here, you can see that I'm now displaying multiple events. That was really easy. Okay, so let's take a closer look at this ngFor statement. The first thing that stands out is this asterisk. That indicates that this ngFor directive is a structural directive. Structural directives are different from other directives because structural directives actually change the shape of the DOM. They actually add or remove HTML elements from the HTML document. They don't just hide them. They actually remove them or add them. NgFor is a structural directive because it will add an HTML element for each item in the array. And so it is prefaced with an asterisk like this. Okay next, let's take a look at the expression that's being passed in to the ngFor directive. Looking at the first part of this expression, it does just what you think. It is declaring a variable. So we're defining a variable called event, and then you can see we're accessing that variable in our template binding here. So this is creating a local variable, just like we did with the hashtag syntax when we were talking about component communication using local variables. And the rest of this syntax is something specific to ngFor. This just tells Angular that events is the array to loop over, and for each item in the array, ngFor is going to duplicate this event‑thumbnail element and assign the value of each array element to this local variable. We can then use that local variable anywhere inside the element that's being repeated. To demonstrate this a little bit further, let's move this ngFor statement up to a higher element. So we'll put it on this div here. So now this entire div is going to be repeated, and you'll see that event is still accessible down here. But now we're going to get a lot of extra stuff repeated too. So let's go see what this does. Okay, you can see that this heading is now being repeated also. So ngFor will repeat the element that it's put on plus all of the elements inside of it. Let's go ahead and move this back down. Okay, now let's just style this a little bit. We're going to use bootstrap to add a row class on a containing div around this event‑thumbnail, and then we're going to create a column class div element, and that will also contain our thumbnail‑element. And then let's move our ngFor up to this div element. Okay, so this is just going to take advantage of bootstrap's grid classes in order to build a grid of these elements. And so this div with a class of column 5 is going to be repeated for each event. Let's go take a look at that. Alright, cool. So now we have each event showing as a little thumbnail on our page, and all we needed was that simple ngFor statement. Let's just go fix the styling on this so that these are all the same height. So we'll come over to our event‑thumbnail, and we'll just add a style right here. Okay, let's see how that looks now. Alright, cool. So now they're all nice and uniform. It's really nice to be able to think about styling a component and to know we'll just go to that component to add the styles instead of trying to think about a separate hierarchy of CSS files and thinking about where to go find those files. Okay, cool. So that's all there is to using ngFor. And there's a practice exercise for this clip, so go check that out.
All right, let's take a look at how we'd hide these fields when they're empty on these events. ngIf is a built‑in structural directive that allows us to show content only when an expression evaluates to true, so hiding these fields is easy. Let's start by showing the location section only if the location is not null or undefined. We can do that using ngIf like this. Okay, so this is just checking to see if location is truthy. So if the location is set, then the ngIf directive will do nothing. But if the location is not set, then this expression will evaluate to false, and the ngIf directive will remove this element completely from the DOM. So let's take a look at how this is working. I'm going to refresh my page. Great, now you can see that Location is hidden on our ng‑nl event, but it is visible on the others. Now let's hide all these empty online URL lines in all these other events. We'll just do the same sort of thing down here. Okay, let's check that out. All right, this is looking a lot better now. And if we take a look at the HTML, you can see that Angular didn't just hide them with CSS. They're actually commented out here, which means they're not even being rendered in the DOM. This can be a great performance saver if you know that you're not going to need this element again for a while, especially if this element is something that's costly to render or to generate. Our case is really simple, but what if this was an actual component that we were hiding, and that component would actually go and fetch data from the server? In that case, it's nice to not even render the component in the DOM so that it doesn't have to go do all that work. On the other hand, what if we were going to show and hide this section frequently, say, based on a button click or a mouse hover that toggles its visibility? If we completely removed this and added it back each time, Angular would have to do all that work to render it every time we show it. In that case, completely removing it from the DOM can be expensive. It would be better if we can just hide those elements. Let's take a look at that next. And there's a practice exercise for this clip, so go check that out.
We just demonstrated how to remove these Location and Online URL elements from the DOM completely using ngIf, and we talked about how that's great if you know you're not going to need them, but if you're going to show and hide them frequently, simply hiding them is better from a performance standpoint. So how do you hide an element in Angular? Well, the same way you would do it with HTML. You just add the hidden attribute to the element. That's not an Angular thing, that's just HTML. But Angular's ability to bind to DOM properties makes it easy for us. Remember, we talked earlier about how you can bind to any DOM property on any element. Well, hidden is a DOM property, so we can just bind to that, like this. Instead of using ngIf here, we could bind to the hidden property, and then we're just going to set that to a Boolean value so that hidden will show up if this expression returns true and it will not show up if it returns faults. So we want something like this, but that will hide it if the location exists. We want to hide them if they don't exist, so let's not that. Okay, cool. And let's do the same thing down here for Online URL. Okay, let's go take a look at that. I'll refresh. Okay, now it's still hiding Location and Online URL when they're not present, but now it's actually hiding them. If we take a look at the HTML, you can see that the location object here is still in our DOM, but it's hidden. So you can see that Angular applied the hidden attribute to this element. And the same is true for the Online URL elements in the other events. So you can see these approaches are different from the standpoint of what gets rendered in the browser. Even though from the user standpoint it looks the same, it's good to keep these two options in mind when you're deciding to hide things in your DOM and to consider the performance benefits of each approach. In our case, these are going to stay hidden, and so we want to put this back to just ngIf. Okay, that'll do. And there's a practice exercise for this clip, so go check that out.
Okay, so we've shown how to change the visibility of elements using ngIf and by binding to the hidden property of a DOM element. But what if there is a part of our document that we want to change based on multiple possible values of an expression? That's where ngSwitch comes in. So let's add something to our event that will tell us whether the conference starts earlier or later based on the event time. So we're going to add a div right here, and inside that div we'll have three spans, one that says Early Start, one that says Late Start, and then another one that says Normal Start. Okay, and then we want to show and hide these based upon the event time. So I'm going to add an ngSwitch up here, and that will just get bound to the event?.time. And notice for ngIf and ngSwitch and other things that we also have to use the safe navigation operator to guard against nulls. Okay, so now I have an ngSwitch that is bound to my event?.time. Now on my spans, I just need to add ngSwitchCase statements, and then I set this to the value that should allow Early Start to be displayed. So in this case, I'm going to bind this to the value of 8:00 am. Okay, so this span has an ngSwitchCase directive that is bound to the string value 8:00 am. Let's do the same thing for these others. So for Late Start, we will bind it to the value 10:00 am. And then for Normal Start, this will be our default case. So if 8:00 am doesn't match and 10:00 am doesn't match, then this will be displayed. And we do that with ngSwitchDefault. Okay, so now we have this div that's bound to our event?.time using ngSwitch, and the cases are Early Start, Late Start, and Normal Start with Normal Start being the default. Okay, so let's go take a look at this. So I'm going to refresh my page here. Okay, cool. So you can see this one that starts at 10:00 am says Late Start, this one that starts at 9:00 am says Normal Start, and this one that starts at 8:00 am says Early Start. Okay, cool. That was easy. Now we would like these values to show up right after the time, so let's go over and take a look at our HTML here. So they're showing on a new line because this is a div, not a span. Really, we want this to just show up right after the time up here on the same line. So just to demonstrate that there's nothing special about this ngSwitch, it doesn't have to be on its own div. We could take this and move that up here, like this, and then we can move these spans up here and delete this div. And since this will be displaying right after the time, let's add some parentheses around it. Okay, let's go take a look at that. All right, cool. So now that's showing up on the same line. Now, our ngSwitch example here is using event?.time, which is a string, and so the ngSwitchCase values are also strings. Notice that they are wrapped in apostrophes. But ngSwitch doesn't have to work with strings. It can be any data type, and then the ngSwitchCase statement expressions should also return the same data type. And that's all there is to using ngSwitch. And there's a practice exercise for this clip, so go check that out.
There are a couple of ways to conditionally add CSS classes to elements with Angular, and they're both pretty easy. Class bindings are good if you're wanting to toggle a single class, and the ngClass directive is better if you're wanting to toggle multiple classes. So let's take a look at class bindings first. Let's make it so that the start time of an event turns green if it is an early start event, meaning it starts at 8 a.m. So on this div that surrounds the event time, we're going to add a binding that looks like this. So this looks a lot like a property binding, but there is no property class.green on a div. So what is this? This is a special type of binding called a class binding, and it is parsed by Angular. And it's basically saying that if this expression, event.time, equals 8 a.m. returns true, then add the green class to this div. So let's add that class to our styles and then take a look at it. I'm using !important here because, otherwise, this style will get overridden by another one. This has nothing to do with the fact that we're using a class binding. It's just the nature of the CSS that exists in our app. And I could make this CSS binding a little more specific and not use !important. But we'll just do it this way for now. So let's go take a look at this over in our app. Okay, Cool! You can see that time is green only for the 8 a.m. event and not for the others. So this is working great. But what if we also wanted to add a second class, say, a bold class, to this element? That's where ngClass comes in. So let's create a bold class, and then we'll use ngClass to add both the green class and the bold class. We can do that with an ngClass expression like this. So instead of a class binding, we'll use ngClass, and then here we'll return an object, and that object will have two properties on it, one for each class we want to apply. So the first one will be green, and then it will have an expression that looks like this. So this ngClass expression would apply the green class if the event time equals 8 a.m. And then let's just apply a second class, and we'll use the same expression here, but we could use a different one. So the ngClass binding is going to expect an object where the object keys are the names of the classes you want to add. And the values are a Boolean expression that determines whether or not that class should be shown. So this will add the green class and the bold class if the event time is 8 a.m. So this should be working. Let's take a look. Okay, Cool! So now both the green and the bold classes are being applied to this element. If we come back over to our code, and we look at this expression that we've applied for ngClass, it's starting to be a lot of logic to exist in our template. So instead of this, let's actually call a function on our component. Now let's add that class to our component or that function. And then rather than running the calculation twice, let's run it once and assign it to a constant. Now we can just return our object. Okay, Cool! This should be working the same. And it is. And then I had said earlier that ngClass expects an object to be returned. That isn't exactly the whole truth. You can actually return an object like this, or you can return a string, which is a space‑separated list of the classes you want applied. Or you can return on array of strings which represent the classes you want to apply. So let's see how this would look if we were going to return a string. So, basically, we would replace this with an if statement, and then inside here, we will return a string with the classes that we want applied if this is true. And, otherwise, we'll return an empty string. All right, cool! So this should be working too. Great! And then the last thing that we could do is instead of returning a string, we could return an array or an empty array. And that should work just fine too. Cool! So you have various different approaches that you can use here depending on your needs of your application and your particular style. And then one last thing that I want to mention here. What if on the element that you're adding ngClass to or doing a class binding on, what if this already had a class applied to it? Something like this? Well, that's okay, actually. So what would happen here is the well class would always be applied to this div. And then any classes that are applied conditionally with ngClass will be added in addition to this class. And that's true for both class bindings and ngClass. And so that's the two different ways that you can use to apply classes to elements. And there's a practice exercise for this clip. So go check that out.
And just like you can apply a single class to an element with a class binding, you can also apply a single style to an element using a style binding. To demonstrate, let's replace this ngClass with a style binding. We'll just make the font green again If it's an early start event like this. Okay, so this is going to set the color based on this ternary statement. If the event time is 8:00 am, then the color will be green; otherwise, it will be this gray color. So this should behave the same as the previous ngClass binding, except that we're not applying the bold font weight, so let's take a look. If I refresh, there, you can see it's green but is not bold. Okay, So if we want to apply that bold class, we'll need to use ngStyle. And to do that inline, it'll look like this. Okay, so this is a lot like ngClass where we're returning an object, only in this case, the keys of the object, or the property names of the object, are styles like color and font‑weight, and the values are a ternary statement that will set those values based on whether the ternary is true or false, And this will work like this, but this is a really convoluted statement to have in a template. So let's go ahead and break this out into a function like we did with ngClass. So we'll replace this with getStartTimeStyle, and that will actually help us make our logic a little more simple. So let's come over here and we're going to replace this with getStartTimeStyle. And our if statement's going to be the same, but what we return is an object like this. Okay, so this is just returning an object with the styles we want, and font‑weight had to be put in quotes because it has a dash in its name. And then down here, we'll just return an empty object if the start time is not 8:00 am. Okay, and because these two objects that we're returning are different shapes, we have to set the return type of our function to any like this, just to satisfy TypeScript. Okay, let's go take a look at this. Okay, there we go, so we're now getting both of our styles applied through that function. And just like with ngClass, if we were to add a style directly to this element like this, then the styles applied with ngStyle are additive, so this style would always be applied and ngStyle would optionally apply any styles from that function. So let's delete this, and since we're using ngStyle now, we don't need these classes. And of course, we could have left ngClass in and used that instead of ngStyle, but either one works fine. And there's a practice exercise for this clip, so go check that out.
In this module, we learned about interpolation, property bindings, and expressions, and we learned about event bindings and statements, and what is legal and recommended for each of these. We also learned how to repeat data using ngFor, how to remove elements with ngIf and ngSwitch, and how to hide elements using the hidden property binding. And finally, we learned how to add classes and styles using class bindings, or ngClass, and style bindings, or ngStyle. In the next model, we'll take a look at creating our own reusable services.
In this module, we'll take a look at how to create reusable services and how that helps us keep our components and our app clean. First, we'll explore why services are necessary in the first place, and then we'll talk briefly about what dependency injection is and what it means in an Angular app, and then we'll dive into creating our first service with Angular, which will finally get all that ugly JSON out of our events list component. And then, finally, we'll talk about how to wrap third party libraries in Angular services so that they can be injected and used in your Angular apps just like any other service. Cool. Let's go take a look.
Okay, let's talk for a minute about why services are necessary. Imagine an old‑fashioned record player. The record player had an arm with a needle at the end that would move across the album as the album spun around on the turntable. It was a brilliant device for its time that allowed an unlimited number of artists to produce albums, which we would then buy and play on our oh‑so‑cool turntable. But the record player had one responsibility, to run the needle over the album and translate that into sound. What if the record player had attempted to also be responsible for the music? What if the albums were embedded into the player itself? Whenever a new album came out, you'd have to sell your old player and buy a new one. Not very practical. It was good that the record player was only responsible for playing the music, not for producing or storing the music itself. We want the pieces of our application to be like our record player, and we've made a good start. Our events‑list.component is responsible for listing events, but not responsible for what each event looks like. That's the responsibility of our event‑thumbnail.component. But our events‑list.component is currently doing more than it should. It's not only responsible for listing the events, it's also currently responsible for defining and supplying the event data. That really should be the responsibility of some other part of our application, especially once we start adding in logic to make a request to an HTTP endpoint. This is where services come in. Services allow you to define business logic in a separate file and then inject whatever service we need whenever we need it, kind of like choosing which record to put on our turntable. And this is where dependency injection comes in. Our record player doesn't get to determine which album is placed on to, or injected, if you will, on to its turntable. The same should be true of our events‑list.component. So we could do something like this in our EventsListComponent. Here we've created a new EventsService, and we're using it to get our events. So this is one step better. At least now our EventsListComponent doesn't have to worry about how to get the event data, but there is a problem here. The EventsListComponent is mandating that events come from an EventsService. In fact, it's this very specific new EventsService. What if elsewhere in our application we decided in some cases we should get the data from an AJAX call and in other cases we should get them from the local browser storage? We'd have no way to use a different type of event service. It's like a record player is saying, sure, I'll let you give me the albums to play, but they all have to be Elvis Presley albums. So we'd like to be able to pass in the instance of the event service to use. That way the EventsListComponent isn't mandating where they come from. This is dependency injection, and it looks more like this. Notice here that we're injecting the EventService as a parameter into the EventsListComponent's constructor. We're then calling getEvents on the service that is passed in. This code is a little oversimplified. We really shouldn't be doing a potentially long‑running call like getEvents from a component constructor, but this gives you the general idea. The point is that someone else is deciding what instance of the EventService we're using, So let's go write some code to make this a reality.
Before we jump in. I just wanted to remind you that we've made changes to this course to keep it up to date. This course was originally created without the CLI since it was still in beta. Because of these updates, you may notice some inconsistencies in the File Explorer over here. Those inconsistencies have been explained previously. Okay, so as we've seen, our events‑list component has all of our data hard‑coded right here. Eventually, we'll be getting this data from an API, and we could just add that API call right here in our component, but then our component starts to take on too many responsibilities. We'd really like to just let another service take care of the details of making that HTTP call. It would be nice if we could just call a function here and not worry about the implementation here in our component. So let's create a service that will take care of that for us. Alright, so inside our events folder, we'll create a new folder called shared where we can put some shared elements, and then in that folder we'll create a new TypeScript file for our service. Okay, so in here we're going to create and export an EventService class, and it will have a method on it to retrieve the events. Alright, so eventually this getEvents method will be the thing that will make the Ajax call to fetch the events from a server, but we'll get into that later. For now, let's just hard‑code the events and return them directly. So let's grab them out of our events‑list.component. So we'll just copy this array out here, and delete this, and then over here in our service, we'll just add it as a constant down here, Okay, and then we'll just go ahead and collapse that so it's not distracting. And then we'll just have our getEvents method returning those events. Okay, so here we have our service; it's just a class, and technically, this is all we really need. We could now inject this service into our component or other services, but it's always a good practice to mark services as injectable like this. Adding this Injectable decorator is important for any service that you're going to inject into your components or another service, and it's important that you don't forget to put parentheses on the end of here like this. That's an easy thing to forget. This Injectable decorator isn't really required for this service, because this decorator is only required when you inject a service which also injects other services as dependencies of its own. Just to clarify what I mean by injecting a service, I don't mean imports. I mean, if you have a constructor that injects services like this. So now that this EventService injects the HTTP service, this Injectable decorator is required, and since you never really know if a service is going to take a dependency later, it's just a best practice to always add it. We don't need this HTTP dependency yet, so let's undo that, but we'll leave the Injectable decorator even though it's not technically required yet. So now we just need to let our app know that this service exists. We do that by registering it in our app.module. First, let's fix this spelling error. Then we'll come over to our app.module and we'll import it, and then we'll add it as a provider down here. Okay, now that it's registered as a provider, Angular's injector is aware of this, and so whenever we request it in another component or service, Angular will know where to go to get this service. Alright, so now Angular knows how to inject this, let's go ahead and inject it into our events list component. So we just do that in our constructor like this. Okay, cool. So we'll just have to go ahead and import the event service. Okay, and that's all there is to injecting a service once it's registered. Remember this private syntax right here is shorthand for saying essentially that we have a property on our class like this, and like we're saying this.eventService = eventService. This is shorthand for that syntax essentially. So Angular will look at the constructor for this component and see that we want an event service and it will go out and construct that or grab it from the injector and inject it in right here. So now all we have to do is use it, and we'll just do it in our constructor for now, which is a bad idea, but we'll come back to that and fix it later. For now, let's just add it right here. Okay, and we need to declare this events variable, and we'll just declare it as an array of any data type. Okay, cool. So let's go take a look at this. First, let's make sure our server's running. Okay, now, let's come over to our app and refresh, and this should still work just fine. So this is working great. Now back in our component, remember, I said it's not a good idea to put this in our constructor. It's really not a good idea to put things in your constructor that are potentially long running, and eventually this will be an Ajax call, and so this will take a little while to fetch those events. So we really shouldn't do it in our constructor, and yet we need to have this happen when our component first loads. So where can we do this if not in the constructor? Well, components have lifecycle hooks that you can hook into, and one of those is the ngOnInit method. So that lifecycle event is called when the component is being loaded. So let's create an ngOnInit method, and then let's move this code into there. Okay, and we still need our constructor, even though it's not doing anything in the body, because that's where our service gets injected. But then we can access the service elsewhere in our class, like we are here in ngOnInit, and this will work just fine. If we go over and take a look and refresh here. This is still working great, only it actually fetched that data in the ngOnInit event. And then just a side note, we can also take advantage of some Angular TypeScript declarations and let TypeScript know that this component implements ngOnInit like this, and then we just need to import OnInit. Okay, cool. Now, if we were to remove our ngOnInit here, we would get a warning indicating that it should be implemented, because we're implementing it here on our class. So we can just add that implementation, and then we're getting a little bit of TypeScript compilation safety. Okay, cool. Now we have a functioning events service, and there's a practice exercise for this clip. So go check that out.
In this module, we learned why services are necessary and what dependency injection is and why it's important. We then saw how to create our own reusable services and even how to wrap third‑party libraries in reusable Angular services. There's one more use for services that we haven't shown here, and that is to use services to hold state that is accessible throughout your application. We'll do this in the Forms module when we create our authentication service, which will hold information about the currently logged‑in user. In the next module, we'll explore routing and navigation.
Before we can demonstrate routing, we need to have multiple pages in our app to route to. Currently, we're displaying a thumbnail for each of our events here, but we'd like to have a page where we can show more details about each individual event. So let's create an event details page, and then we'll see how to navigate to that page when we click on one of these events. Before we jump in, I just wanted to remind you that we've made changes to this course to keep it up to date. This course was originally created without the CLI since it was still in beta. Because of these updates, you may notice some inconsistencies in the File Explorer over here. Those inconsistencies have been explained previously. Okay, so there's going to be a number of things in this event details section of our site, so let's create a folder for this component. And then in here, we'll create our component. Okay, and let's create the basic shell for our component. Okay, now let's add the properties for our component here. And typically, we've added a selector here so that our component can be used from within an HTML page, but this component isn't going to be used as a child component from another page. It's going to be routed to directly, so we don't need a selector. But we're going to put our HTML in a separate file, so we're going to want a template URL, and that I'll go here. Okay, let's go ahead and create that template file. Okay, and then we're just going to want some HTML here to show some basic information about this component. We don't want to have to type this all in, so this is also available over in our GitHub repo. So let's jump over there, and it's inside this app folder in this events/event‑details folder, and it's this HTML right here. So I'm going to click on Raw here. Okay, and here's our HTML. Let's just go ahead and copy of that, and we'll paste it in right here. Okay, so this is just some basic HTML with some bindings to an event property on our component. Alright, and we're going to want a little bit of styling here, so let's at a class on this outer div here, and then we'll add that style to our component. This will just add some padding around the whole thing. Okay, and one more style to add. We're going to want to limit the size of this image here. Okay, so let's add that style over here. Okay, so as we saw in our HTML, we're binding to an event object here, but our component doesn't have that property. So where's that going to come from? Well, this page is going to be navigated to directly, and the ID of the event that we want to view will be in the URL. So when we navigate to this page, it'll be a URL like this, so that 1 will represent the event ID for this page. Okay, so when this page is loaded, we're going to want to make a call to the event service to fetch the event for this page. And remember, we don't want to do that in the constructor because that's going to be a longer‑running AJAX call. So let's create an ngOnInit method here, and we'll do it in here. Okay, and we'll pull this from our event service. If we go over and look at our event service, it only has a method right now for retrieving all of the events. We just want to retrieve a single event. So let's add a new method here called getEvent, and that will take in an ID. That will be a number. And then we'll just pull that out of the events array. And again, we'll have this make an AJAX call later. But for now, we'll just pull it off of the array like this. Okay, so now let's go call that from our new EventDetailsComponent. So first, we're going to have to import that service. Okay, now we just need to inject it. Okay, now we can just make that call from ngOnInit. Okay, and remember, we're going to be passing the ID of the event in on the URL. And we're going to want to pass that ID in here. But for now, let's just hardcode this to event 1. Okay, and we have to declare that as a property. Alright, now this component is ready for use, but we need to register it in our app module. Okay, and then we'll just register it down here. Okay, so now we have another page to route to. But the question is, how do we get to it? Let's add our first route.
Alright, so now we have this event‑details component, but how do we get to it? First, let's remind ourselves how we're currently displaying our events‑list component. Over here in our index.html file, you can see that we're loading our events‑app component. And if we go look at that component, you can see that in its HTML, it has two child components, a nav‑bar component and an events‑list component. So this events‑app component is the top‑level app component for our entire app, and it gets loaded during our app's bootstrap process. And so it loads and is displayed when we first navigate to our app, and then it loads these nav‑bar and events‑list components. And so that's how our events‑list component is currently being displayed, and right now there's really no way to change that. What we really want to do is to always show the nav‑bar component, but instead of this events‑list component always being shown, we want to show whatever route‑level component matches our URL. This is where routing comes in. So instead of putting this events‑list component here, we'll replace it with Angular's router‑outlet component. And then somehow we need to tell Angular when a user requests a particular URL, display its corresponding component here. We do that by defining routes. So let's go create a routes file at the root of our app where we can define those. Okay, so the routes that we define for an application are going to basically be an array of route objects. It will look something like this. And right now, we need two routes. First, we need one for our Events List page. Okay, so this basically says if the URL matches /events, then show this EventsListComponent wherever our router‑outlet component is. And remember, we just added that router‑outlet component right here in our AppComponent. And now we need another route for our Event Details page. Okay, this route looks a little different because it has this :id on the end of it. That's basically a parameter placeholder where we expect a value to be passed in on the route. We'll talk more about this in the next clip, but this route will match things like /events/1 or /events/foo. And when it sees a route like that, we will display the event‑details component. And then we want a default route so that if the user navigates to the root of our site, it will take them also to the Events List page. So that will look like this. Okay, so this path is a little bit different. It's saying when the path is empty or when we're at the root of our site, then redirect to the route/events. And redirect routes need this pathMatch property, and there are two options for that, either prefix or full. Prefix means redirect if the URL starts with the specified path string, and full means redirect if it fully matches the specified path string. In our case, we just want to use full. Okay, now we just need to import our components. Okay, there's one more thing that we can do here. This actually would work as is, but Angular provides a TypeScript definition for this router config that will give us some extra IntelliSense and compile‑time safety if we add it. So let's import that, and then we'll just add that type definition to our array like this. Okay, cool. Now you can see as I add a new path, if I hit Ctrl+space in VS Code, you can see it gives me some extra information about properties that I can add to this route. And we'll talk more about a lot of these properties in a little bit, but it's nice that we get this IntelliSense here so that as we add a path, we know we're doing the right thing. And if we were to misspell something, we would get some compile‑time safety and warnings in our editor. Okay, so now we've defined our routes. We just need to tell Angular to load this config over in our app.module. So first, let's import our routes, and then we just need to add it as an import using Angular's RouterModule like this. Okay, and we need to import RouterModule. Okay, so down here, we just use RouterModule forRoot to import our route into our app. Alright, one more thing that we need to do when we add routing to our app is we need to tell Angular where on our web server our app is hosted. For example, our app is actually hosted right at the root of our web server. But what if our app was hosted here? Angular needs to know this so that it knows what it's routes are relative to so that it can parse the URL. So we do that by providing a base tag in our index.html. And you can see right here in the head, the Angular CLI has already created a base tag for us. And since our app is just hosted at the root of our website, the href is just a slash. If it was hosted somewhere other than the root, we would just indicate that here. Okay, so we now have three routes defined, and our old Events List page is now being routed to directly instead of hardcoded into the HTMl of our app component. So that means over in our events‑list component, we really don't need this selector anymore since we'll be routing directly to it. Okay, cool. We've been jumping around a little bit, so let's just recap what we actually did here related to routing. First, we added a router‑outlet component to our EventsAppComponent here. And then we defined our routes for each of our pages, including a default route. And then we loaded our routes into our event module using the RouterModule. And finally, we added our base tag to our index.html page. Okay, cool. That's pretty simple really. Let's go check this out. So you can see, our Events page is loading here. And the interesting thing is notice that our URL is now /events. If I delete this and navigate directly to the root of the site, notice that it's redirecting me to /events. That's because of that redirect route that we added. And if I add a /1 on the end of this, then I get my Event Details page. Awesome, this is working great. There's just one exception here. If I navigate to event number 2, I still get event number 1 regardless of what I put in here. That's because when we created our event‑details component, we just hardcoded the event ID 1. We really want to get that event ID off of the URL here. So let's take a look in the next clip at how we do that. And there's a practice exercise for this clip, so go check that out
Okay, so when we navigate to our event details page, this event ID is always being ignored. So no matter what event ID we put in here, it always loads Angular Connect, which is the event with ID 1. And that's because in our event‑details.component, when we call the getEvent here, we're always passing in event ID 1. So let's see how we can pull that event ID off of the URL and use it in our component. Remember that over here in our routes, we added this id parameter. That colon in front of the id is a cue to Angular that this is a parameter in the URL. Angular will take whatever value is passed into that location in the URL and will create a parameter named id for that route, and that parameter will be set to the value that's passed in at that point in the URL. And then we can access that in our component. So if we navigate to events/4, then the id parameter for this route will be set to 4. So if we come over to our component, we can import ActivatedRoute from Angular. And then let's just inject that into our constructor, and we'll just call it route. And then down here, we can just use that to get the event id like this. Okay, so on this ActivatedRoute service, we're calling snapshot.params.id. That will give us the parameters off of the current route that was used to access this component. And then this is wrapping a little bit funny, but we're passing this in as a parameter to getEvent, and getEvent takes a number. So let's just cast this to a number. Okay, so now we are passing in the event id as a number into getEvent. And notice that this id here matches this id over here in the route. Okay, let's check that out. So let's refresh our page here. Notice that we went to events/4, and it loaded a different event. And if we go to events/3, we get NG CONF. And that NG CONF image is a little crazy. Looks like we might have a typo in our styles. Let's go take a look at that. Okay, yeah. Here, we have a colon here that shouldn't be here. Let's refresh that. Okay, that looks better. So now as we navigate around, that image is going to be a little better. And you can see that we're loading a different event that matches the event id that we're passing in. So that's how you pull parameters off of the URL using the ActivatedRoute service. And there's a practice exercise for this clip, so go check that out.
All right, so now we have our two pages working with routing, but we have no way to navigate between them other than just changing the URL. We'd like to make it so that when you click on each of these event thumbnails that it takes you to the event details page for that event. So let's go over to our event‑thumbnail.component. Up here In the HTML, we're going to add a routerLink to the main container div like this. So that's going to turn this div into a link, and when you click on it, it's going to navigate to /events and add the event.id to the route. And that's all we need to do to add a link to the new route, so let's go check that out. If we refresh over here, now if I click on Angular Connect, notice that it loaded the Angular Connect event so it navigated to events/1. And if we go back and click on ng‑nl, then it loads that event, so that's working great. So that's really easy to add router links. But now how do we get back to the events list page? We'd like to make it so this All Events link takes us back there. So let's go over to our nav component, which is in here. Okay, so here's the HTML, and here's our All Events link. You can see it's already got an anchor tag around it. And we can add the routerLink to an anchor tag, just like we did with the div in our thumbnail component, so it'll look like this. Okay, and notice that the expression for our routerLink takes in an array. That array is basically a list of path segments followed by the parameters. And there's no parameters for this route, so it's just /events. The link for the event thumbnail that linked to the event details was slash‑‑‑we passed in /events and we passed in the event.id. Okay, so this should be working. Let's go take a look. If I refresh over here, I can now click on All Events, and I can go back and forth between the events list and the event details. Cool. And there's a practice exercise for this clip, so go check that out.
Okay, we've just seen how to link to our routes from our HTML. Now let's take a look at how we would navigate to a page from within our code. For that, let's create a real simple component. This will become the page that we use to create new events, but for now we'll just make it a real simple page. So we'll add that in our Events folder, and it'll be a real simple component for now. And for now, we'll just use an inline template. Okay, so this page isn't going to do much right now, but we'll expand this page out in the module on forms, but we'll use it right now to demonstrate how to navigate back to the All Events page from code when the user clicks this Cancel button. So first, let's get this page wired up so that we can see it. We need to add our new component to our module, so we'll import it here, and then we'll just add it to our declarations down here. And then let's just add a route for this page. Okay, and import that component. Okay, and the placement of this route is kind of important, and actually, we have it in the wrong place right here. Problem is that this path actually matches the path above it. So Angular doesn't have a way to differentiate between whether we're trying to pass in the id new to the events id path or whether we're trying to hit the events/new path. And so, actually, let's move this up here. That way it will get processed first. So, if Angular sees events/new in the URL, it will hit that first and will send us to this route. Otherwise, it will keep looking for a matching path. Okay, so this is all wired up. So if we come over here, we can go to /new, and that will take us to this page. So let's just add a link to this Create Event element in our nav. So back over in our nav component, right here where this Create Event is let's add a routerLink. All right, now I should be able to click on this. Okay. There we go. All right, now, this Cancel button doesn't do anything right now. What we want to do is when we click Cancel, we want it to just take us back to the events list page. So let's go wire that up. So over here in our Create Event component, let's just add a click handler on our Cancel button. Okay, and that's wrapping kind of funny, but you can see when we call click here, we're going to call cancel on our component, so let's go add that method. Okay, now to navigate from code, all we have to do is inject Angular's router service. So let's import it and inject it. Okay, now all we need to do is call navigate on the router and pass in the route that we want to navigate to. And that should do it. Let's take a look. I refresh here. Now if a hit Cancel, there, it takes us back to our All Events page. That was easy. All we needed to do was inject the router and call navigate. And there's a practice exercise for this clip, so go check that out.
Sometimes we want to prevent a user from going to a particular page or discourage them from leaving a page. That's what route guards are designed to do. If we take a look at the IntelliSense for one of these route objects, I can do that in VS Code by hitting Ctrl+space, then you can see all the different properties available on our route thanks to TypeScript. Two of these properties are canActivate and canDeactivate. CanActivate allows us to determine whether or not a user can navigate to a route. Let's take a look at how canActivate works. And there are a couple different ways that we could do this. We can either use a function or we can define and use a service. We're going to use a service here because it gives us flexibility and the ability to inject other services, and we're going to need that. So right now, if we go take a look at the site, I can navigate to an event details page with a URL like this, and that works fine. But if I navigate to the event details page using an invalid event ID like this, the page actually loads, but it sure doesn't look very good because there's no data here. We'd like to put a route guard in here to redirect them to a 404 page if the event ID is not valid. So let's create that 404 page first. This will be quick. First, let's add an errors folder, and then we'll add a 404.component. Okay, and let's grab that component out of our GitHub helper repo. So over here in the app folder, there's an errors folder, and it's this 404.component. So let's grab the component out of there, and we will paste it into here. Okay, now we just need to add that to our module and add it as a declaration, and then we just need to add a route for it. Okay, let's just import that. Okay, now should be able to hit that page. Come over here and navigate to 404. Okay, good. So now we have a 404 page that we can redirect to. Okay, so we're going to add a route guard that sends us to that 404 page. So let's go create a service called event‑route‑activator. We'll add that in the event‑details folder. Okay, and the shell of our route guard service will look like this. Okay, so we just have our basic Injectable service here, and then we're going to make this implement this CanActivate TypeScript interface. Okay, so that requires us to implement the canActivate method. All right, so we want to just check to see if the ID passed in is a valid event. So we need to inject our EventService, and we'll inject that here. And then in our canActivate method, we'll look up the event, so we'll need to grab the event ID off of the route. This will be easy since the current route is passed in to the canActivate method as the first parameter, so we can grab it like this. Okay, lets import that. Okay, now we can get our event off of the EventService using the ID from the route like this. Okay, now if this doesn't return a valid event, we want to redirect to our new 404 page. So let's just set a Boolean variable based on whether this call returns a valid event, and then we'll just cast the result of this call to a Boolean. Okay, and then we can just right here check to see if the event exists. And if it does not, then we will navigate to our 404 page. Okay, and we'll need to inject that router. Okay, so here we're loading our event. If it does not return a valid event, then we redirect to our 404 page, and then our canActivate method needs to return a Boolean. So we'll return here whether the eventExists. Okay, so it will return true, meaning the route can be activated if the event exists; otherwise it'll return false. Okay, that's all there is to creating a route guard. Now, we just need to go add this as a provider to our module. So we'll import it up here, and then we'll just add it as a provider. Okay, so now we have this route guard. We just need to go attach it to the route that we want to add a guard to. So over in our routes we have our event details route right here. And then we're just going to add CanActivate and pass in our EventRouteActivator. Okay, cool. So that's all wired up. Let's go check it out. So now if I go to events/1, that's not working, actually. I think there must be something wrong with our call to getEvent. Oh, yes, we need to cast the event ID to a number here. I think that should fix it. So let's try this again. Okay, cool, that works. But if we go to event 42, then it does not work. It sends us to the 404 page. So that's exactly what we're wanting. Okay, so that was pretty easy. Now you know how to prevent routes using a route guard. And there's a practice exercise for this clip, so go check that out.
Just like we used canActivate to prevent the user from navigating to a page, we can use canDeactivate to prevent a user from leaving a page. This is often helpful if, for example, you want to warn a user if they try to navigate away from a page before saving their data. So let's add a route guard to the Create Event page that warns the user if they try to cancel before saving their event. So we'll start by adding a canDeactivate property to our create event route. And remember, we said that there are two ways to add route guards. You can either use a function or a service. In our canActivate example, we used a service, but we don't need something that involved for our canDeactivate, so let's just use a function. So to use a function, you just add the function name here, so we'll create a new function called canDeactivateCreateEvent. So the question is, where do you define this function? Well, we just need to register this as a provider in our module. Let's go over to our module, and then down here in our providers, we've been defining providers using this shorthand approach. If we take a look at this EventService provider, another way we could provide this is using the longhand approach, like this. So this is the longhand form that says when this is requested, used this to fulfill it, and it just makes a lot more sense to use the shorthand form in the cases where we're using services. But in this case, we're going to be requesting a string, canDeactivateCreateEvent, and for that, we want to provide a function. So we'll put that here. And then for useValue, we'll create a function called checkDirtyState. Okay, let's just put these on their own line. Okay, so now we need to define that function. We could define that over in another file. For ease of use, let's just define it right here. All right, just to demonstrate this, let's just have this return false right now. Okay, let's go check this out. If I refresh our Create Event page here and try to hit Cancel, you can see it no longer works. The Cancel button, remember, is wired up to send us back to the All Events page, and it's being prevented by our route guard. And not only is it being prevented here, but also if I click on anything that would take me away from this page, it prevents me from doing that. So that's pretty awesome how easy that is to just disable all navigation in your application using a route guard. Okay, so let's make this a little more interesting. What we really want to do is prevent them from leaving this page only if they haven't saved their event. So the question is, how will this checkDirtyState function know the state of that component? We have to have a way to know if they've saved the event or not. Well, that's actually really easy. The very first parameter that is passed in to your canDeactivate function is the component itself. So let's go take a look at our CreateEventComponent. If we were to define a property on this component that represented the component state, we could access that property in our canDeactivate function. For now, let's just add an isDirty property on the component like this. Okay, so we've created this isDirty property and it's defaulted to true, and this is essentially a public property. So over in our checkDirtyState function, if we grab that component that's being passed in, then we can check that isDirty property like this. All right, and if the component is dirty, let's call the HTML confirm dialog and return the result like this. And then if the component is not dirty we can just return true. Okay, cool, let's go check that out. So let's refresh this page. Now if I hit Cancel, okay, cool, now I'm getting this confirmation dialog that says, You have not saved this event, do you really want to cancel? And if I say Cancel, it will not. And if I say OK, it will. And then just to show that this is really based on the state of that component, let's go make that component return true, or return false. So now it's not considered dirty. So now if I hit Cancel, it will just work. Of course, we'll want this to do something more than just return true or false, and we'll come back to this when we wire up our create event form and make this return something reasonable. All right, cool, that's all there is to adding a canDeactivate route guard. And there's a practice exercise for this clip, so go check that out.
Typically, when you have a navigation header in your site like this one, you want to highlight the currently active link so that users can see from the nav bar which section of the site they're on. So let's go make it so these All Events and Create Event links are highlighted when we're on those pages. All we have to do is add a routerLinkActive directive to each of these links like this. So this is basically saying when this link is active, apply this active CSS class, and we'll add that class here in just a second. Let's go ahead and add this routerLinkActive directive to this link also. Okay, cool. Now let's come over to our component and add that CSS class. Okay, cool. So we're just going to add this orange color whenever the active class is applied. And we had to add the extra li prefix to our styling here so that is specific enough that our styles don't get overwritten by Bootstrap. Okay, so let's go check this out. If I refresh the site now, cool, you can see that All Events turned orange because I'm on the events list page. And if I click on Create Event, you can see it gets turned orange also, but the All Events link should not be orange here. This is happening because the routerLinkActive binding will do a starts with match. So if we take a look at our routerLinks over here in our HTML, you can see the events route will get the active link whenever the route starts with /events. So that is also matching when the route is /events/new. But we can change this to be less greedy by setting the routerLink options to require an exact match like this. Okay, so this will make it so that the active class only gets applied if the route exactly matches /events. So let's go take a look at that. Let's refresh here. Okay, cool. Now you can see we're on the Create Event page and only it is highlighted. If I cancel and go back to All Events, you can see it turns orange and only it is orange, so this is working better now. Cool, that was super easy, and it's cool to see something like this work with so little effort.
So far, our application has only one Angular module. It's our main AppModule. Let's take a look at adding multiple modules and some of the performance benefits that we get from that. Typically, larger sites can be broken down into smaller sections. Imagine we had a section of our site for creating and managing user profiles. Let's go ahead and create the shell of an edit profile page that will be part of a new module. So we'll create a new user folder, and inside that folder we'll create a profile component. Okay, let's just grab the basic starting point for this component from our GitHub helper repo. So over here, we have an app folder, and in our app folder, we have a user folder, and then we have this profile.component. So let's just grab the raw contents of that, and copy it, and paste it into here. Okay, so now we have this user ProfileComponent that we'll update later for adding a profile. Right now it just has two buttons and an empty spot where we'll put a form later. So the pattern that we've seen so far is that, at this point, we would go and add this to the module and to the routes. And we still want to do that, but the user portion of our site is very different from the rest of our site. So we'd like to make this a totally separate module and feature section of our site. So let's go create a new user module. In the user folder, we'll create a module. Alright, and a basic, lazy, loadable module will look like this. Okay, so we'll declare our module like we normally do. Okay, and it will have imports, declarations, and providers. Alright, this looks similar to our AppModule, except for our imports are going to be a little bit different. Here, we're going to use CommonModule, and in our app component, we actually import BrowserModule here. So that's one key difference between the AppModule and a feature module or a lazy loadable module. And then the other difference is for our RouterModule, we'll call forChild. In our AppModule, we used forRoot here, and then we'll just pass in the routes for this module. Okay, we haven't created those. Let's go ahead and create the import, and then we'll go create them. Okay, so we've already created a ProfileComponent that we want to import into our new user module. Okay, so let's declare that down here. Alright, now let's go ahead and go create our routes. So we'll create a new routes file, and it will look like this. Okay, so there's nothing different with this route; however, I do want to make note of one thing. It looks from this like the route for this would be /profile. But when we're done with everything, the route is actually going to be /user/profile, and you'll see why in a second here, but just keep that in mind. Okay, so this new feature module is ready to go. Now we need to go tell our main AppModule when this module should be lazily loaded. We actually define that in the main module's routing config, so let's open that up. And then right here, we're going to create a new route, and its path is going to be user. So this is where that prefix to our user feature routes is going to come from. So anything inside the user feature module is going to have a route that's prefixed with user. And then to load that module and its routes, we use loadChildren, and then you supply a string here that's parsed by Angular that has two parts. The first part is the path to the file where your new module is. So that's here, and then the second part follows a hash sign. And the second part here is the name of the module. So if we go over to our userModule, you can see what's being exported here is the class userModule, and actually that should be in uppercase. And then that's what we'll put as the second part of this stream. Okay, so this is basically saying when a route starts with /user, load the userModule from this path. Alright, now let's go add a link to our new profile page. So over in our navbar HTML, right here, we're displaying Welcome John up in the upper right‑hand corner. And let's add a router link to this anchor tag, and that will link to our new user profile page. Okay, so this is all wired up. Let's go take a look. So I'll refresh here. Okay, so now notice if I click on Welcome John here, that it loads our new user profile. And notice the URL up here is /user/profile. And one thing that's really cool here. Let's open up our debug tools to the Network tab, and I'm going to refresh my app here. But first, let's put a filter in here, /user. So let's see what requests are made for /user when I first load this app. Alright, notice nothing is loaded here. But when I click on the user profile and go to the user profile page, notice that only then did it load the user module, and the routes, and the component. In a bigger application, this could be really helpful if a module is composed of a lot of files. It would avoid loading those until the user actually goes to that section of the site. Okay, cool. So that's how you add new feature modules to your application and lazily load them.
We just demonstrated how to organize our code into modules. Let's take a look at another way to clean up our code a bit. If we take a look at our app.module, it has quite a long list of imports, and most of them are coming from the events folder. We can simplify this a little bit by exposing all of the imports inside the events directory from a single index file that we can then just import with a single import line. This is referred to as creating barrels. So let's start by creating a barrel in our events directory. So we'll create an index file right here, and then we'll simply import each of the components in this directory and re‑export them like this. Now we can do this for all of our subdirectories, and we'll even do it for our shared folder for consistency, even though it only has a single file inside it. So let's go ahead and create that now, and it'll just export the event.service. Now we can actually add this barrel to our outer barrel like this. Now we'll do the same thing for the event‑details folder, and we'll export the two things that are in this folder. And we need to add that to our outer barrel too. Now that we have these barrels created, and they're all rolled up into this one barrel, we can now go simplify our imports in our app.module file by creating a single import. So we do that like this. So there's our one barrel that has everything exported from it. Now we can move up everything from the events directory like this. Now we can delete all these extra import lines. That looks much better. Now we can go simplify our routes file too because it has a lot of imports in here from the events folder. So we'll make a single import for those and move each of these up. And then let's clean this up. That feels a lot better too. And so this will make things a lot more simple each time we need to add something to these imports. So let's just go take a look at our site and make sure that everything is still working. So we'll refresh. There we go. Everything's still loading just fine.
In this module, we learned why routing is necessary, how to define routes for pages, and how to link to those routes from HTML and navigate to those routes from code. We also learned how to create route guards to prevent routes from being activated and deactivated, and how to preload data for a component using resolve. We also learned how to style our links based on whether the routes for those links are currently active. And lastly, we learned how to create feature modules and lazily load them. In the next module, we'll take a look at how to collect data using forms and validation.