Angular Fundamentals

View non-AMP version at androidpolice.com

Course Overview

Course Overview

Hey there. This is Jim Cooper. ‑And this is Joe Eames. ‑Welcome to our Pluralsight course, Angular 2 Fundamentals. Joe and I have been developers for a long time, and we've been building large‑scale Angular applications ever since Angular 1's official release. And we're excited to share with you what we've learned about Angular 2. This course will give you all the fundamental knowledge you need in order to start building your own Angular applications, whether for small, fun personal projects or for large enterprise applications. In this course, you'll gain a high‑level understanding of the architecture of Angular applications in addition to a detailed understanding of building applications with Angular. Once we introduce you to the high‑level concepts, we'll spend most of this course actually writing code for a demo application that models real‑world applications. This intermediate‑level course has been designed to help you learn Angular from the ground up. If you feel like things are moving a little too quickly, you can check out one of the beginner‑level courses, but we've tried to make this a course that will teach you the fundamentals, even if you've had no prior experience with Angular. In this course, you'll learn about the following: the architecture of an Angular application and how to bootstrap a new application, Angular components and template syntax, including pipes and directives, creating reusable services and how dependency injection works in Angular, working with forms and validation, making API calls with HTTP and observables, and how to unit test and end‑to‑end test your application, and finally, how to package it all together for production. When you have finished this course, you will know enough about Angular to start building real‑world applications using Angular best practices. The only real prerequisite for this course is that you have some knowledge of JavaScript and HTML, but you certainly don't need to be an expert. So join us as we explore the exciting world of Angular.

Getting Started with Angular


Hi. This is Jim Cooper, and welcome to this Angular Fundamentals module on getting started with Angular. In this module, you'll develop a high‑level conceptual understanding of Angular applications, and you'll create your first Angular Hello World app. We'll also cover some of the prerequisites for this course and give a brief introduction to some of the technologies that it will be helpful to know a little bit about for this course. We'll make this as quick and instructive as possible so that we can dive right into coding. Before we get started, let's talk a little bit about some prerequisites. First of all, you'll definitely need some fundamental JavaScript knowledge. We won't be doing anything too complex, so if you feel like you have a decent grasp of basic JavaScript fundamentals, you'll be just fine. If you want to brush up on your JavaScript, choose a course or two from the Beginner JavaScript Learning Path. You'll also want to have a basic understanding of HTML. As long as you can build a simple web page, that's really all you'll need to know. If you're fairly new to HTML, you may miss some concepts, but it shouldn't distract too much from learning how to create Angular applications. There's also an HTML Learning Path if you want to learn a little bit more. Now let's take a look at a few things that will be helpful to know, but not necessarily required. Don't let this list worry you, you'll be just fine without knowing them. This is just a heads up on some of the technologies that we'll be using. First up is Node and npm. We'll be using Node and npm to get up and running, and you'll need to get Node installed and functional if you're going to follow along. We'll show you how to do that, but having a little bit of background will make things easier. Joe Eames has a great Npm Playbook course to help you along there. We'll also be using some ES2015, or ES6, syntax in this course. We won't be using a lot of this, but we will be using some. And Joe Eames and Scott Allen have a great JavaScript Fundamentals with ECMAScript 6 course that you can watch if you want to dig deeper into that. And then we'll also be using TypeScript in this course. You aren't required to use TypeScript to write Angular 2 apps, but it is by far the most mainstream approach, so it's what we'll be using in this course. Dan Wahlin and John Papa have a great course to help you learn TypeScript. Again, if you don't know TypeScript, don't worry, most of the code we'll be using is just plain JavaScript and the TypeScript pieces shouldn't throw you off too much. None of the items listed here are required before you watch this course. If you're not familiar with them, you could certainly wait to brush up on these things until after this course and be just fine. We'll guide you through the Node and npm pieces in the course and we'll actually introduce you to the key concepts of TypeScript in just a moment. But first, we'd like to introduce you to the practice exercises that we've provided for this course.

Practice Exercises

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.

Introduction to TypeScript

We'll be doing very little TypeScript in this course, but we will be using some, and it will be helpful for you to understand a few TypeScript concepts. Let's take a look at a high‑level overview of what TypeScript is. First of all, TypeScript is a superset of JavaScript. That means anything that you can do in JavaScript, you can also do in TypeScript using the exact same syntax. But it also means that there are additional features that are available for use. So how is this accomplished? It is accomplished using transpilation. So when you write your TypeScript code, you're using a mixture of plain JavaScript plus TypeScript features. Then your build process runs the TypeScript compiler and transpiles all the TypeScript code into plain JavaScript code. That's an important part about TypeScript. Your TypeScript code is only a development environment construct. TypeScript doesn't give you anything in production that you couldn't have accomplished with plain old JavaScript. It simply gives you more options for how you want to code and think about your code. It is basically syntactic sugar that is enforced via a transpilation process. So there is a TypeScript compiler that you run that handles this transpilation, and if you write any code that violates the rules of TypeScript, the compiler will emit an error and fail to do the transpilation. So it gives you some development time or build time checking that helps to prevent some runtime errors. One nice thing about TypeScript is you can use as little or as much TypeScript as you want. Really, you could write all JavaScript and pass it through a TypeScript compiler, and it would work just fine, but of course there's no point in using the TypeScript compiler at that point. Again, we won't be using a lot of TypeScript in this course, so let's just take a quick look at the few TypeScript features that we'll be using. This includes static typing, interfaces, class properties, and accessibility levels such as public and private. So let's look first at static typing. Static typing allows us to specify data types for variables, properties, and parameters, etc. In plain JavaScript, we declare variables like this. Adding typing with TypeScript is as simple as adding data types to the variable declarations like this. With this in place, if you were to try to set any of these to an invalid value, for example, setting age to a string value, your TypeScript compiler would throw on error and fail to transpile, catching potential bugs earlier in the process. And that's all there is to typing in TypeScript, and you can use as much or as little as you'd like. Taking typing a little bit further, you can actually define interfaces for entire objects, and that will enforce the shape of objects. So if we wanted to ensure that all cats had a string name property and a numeric age property, we could create an interface like this. And then you could declare variables of this type like this. Given this declaration, we will get compile time safety if we try to assign an object to fluffy that does not include these fields with these types. So let's take a look at some examples that would fail to compile. First there's this example. This one would fail because age is set to a string value instead of to a number. Let's take a look at another example. This example would fail to compile because we have not provided an age property. If we want the age property to be optional, we could add a question mark to the interface declaration for the age property like this, and now this example would work just fine. And, again, you can choose whether to use interfaces or not when doing Angular development, but we will be using a few of them in our course. Now let's take a look at TypeScript class properties. Given a simple ES2015 class like this, we can initialize the name of a cat in the constructor like this. This is just plain ES2015, not TypeScript, but we can make it more explicit that we have a name property by declaring it here. Adding this didn't really change any functionality, but it's more explicit. We can more easily see that our cat has a name property. We could also define properties that are not initialized in the constructor like this, and actually the types are not required. I could just declare these properties like this, and that works just fine. We just don't get any compile time type safety on those properties. Now that we have these properties, you may wonder where these properties are accessible from. For that, let's take a look at our final TypeScript topic, public and private accessibility. Take a look at this class. We basically have three members on this class, the name property, the color property, and the speak function. Of course, we can access all of these internally in the class, so I could access the name property in the speak function like this. I could also access the speak function from other functions in this class. However, as defined here, these three members are also accessible outside of the Cat class. That's because class members are public by default in both ES2015 and TypeScript. I'm going to simplify this class a little bit just to give us a little more room to type. So let's say I create a new Cat here, I can now access the class members outside of the class like this. So what if I wanted any of these members to be private, meaning I want to be able to access them from within the class, but not externally? Well, I can just preface them with the private keyword like this. Now I'll get compile time errors if I try to access them here. And that's all there is to making things private. Remember, class members are public by default, and you have to explicitly mark them as private if you want them to be accessible only within the class. Now let's take a look at one last use case for private members that's pretty common. Consider this class, it's pretty common to receive values as parameters in the constructor like this, and then set corresponding private member properties to the values passed in like this. Since this is so common, TypeScript has created a shortcut for all of this that looks like this. Notice how much this simplifies this common practice. There's not even any assignment code in the constructor. The TypeScript transpilation is going to just generate code for us based on the fact that we marked these parameters is private. We'd call this constructor the same way like this. So it's not that these constructor parameters are actually private, obviously we can still access them externally to pass values in, it's just a shorthand for creating private properties that are initialized via the constructor. We'll use this a number of places in the course. And that covers pretty much everything that we'll be doing with TypeScript in this course.

Comparing Angular to AngularJS

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.

A Conceptual Overview of Angular

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.

Here's What We'll Be Building

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.

Installing Git and Node

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.

Getting Started with the Angular CLI

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.

Bootstrapping an Angular App

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.

A Brief Look at the App Module

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.

Accessing Static Files

Now that we have a basic site set up and running, let's take a look at how to access some static files like images and site‑wide CSS files. Then we'll be ready to really jump into building our Angular app. Let's start by looking at how we'd access an image file. The Angular CLI has created this assets folder, and this is where we put our static files. So let's create an images folder. Okay, now we need some images. For those who are following along with building this project, we've created a GitHub repo where we'll grab some files from throughout this course. It's available here at this URL. So inside this source folder, you can see that we have this assets/images folder. We just need to click on each one of these, and then click Download, and then Save image as. And then we'll just save that in this assets/images folder. And then I'll go ahead and download the rest of these files off camera. If you're following along, go ahead and download each one of these. Okay, so now I have all of these images downloaded here and put in this assets/images folder. So let's go ahead and add one of those to our app component. So over here in app in our events‑app.component, and let's change this to a template string so we can add a new line, and we'll just add an image tag. And we'll go ahead and set the source to the assets folder, /images/basic‑shield.png. And if we go look at our site, there we go, we can see that that image is showing there. Now, it's important to understand what exactly happened here. First of all, if we take a look at our image source, what is this path relative to? Well, it's relative to the index.html file, but you can't statically access any file that is relative to the index.html file. Webpack needs to know which files to bundle up when it builds the app. So the only reason why this is working is because if you look in our angular.json file, by default, the assets folder is included in our assets array. This array is an array of paths that we'd like webpack to include in our app bundle, and these paths are relative to our angular.json file, or the root of our site, and that's how you make files statically available to your app. This makes sense for static files like images, but for static, CSS, and JavaScript files, there's a different convention. Notice down here that we have styles and scripts arrays. This is a place to reference styles and scripts that you'd like loaded with your app. Notice that by default it is loading this styles.css file. If we go take a look at that file, you can see it's empty, but we do have some site‑wide styles we want. To avoid typing those in, let's go grab them from our helper repo. So in this src folder, we have this styles.css file. If we click on that and then click on Raw, we can copy all of that out, and we'll just paste that in here. So these are some styles that we'll be using throughout the course. Okay, cool. So since this styles.css file is referenced from our styles array in our Angular CLI JSON file, these styles will now be loaded globally. So notice if I change the background color to black for the body and then go over and refresh my app, there we go, we can see that the background color is now black. All right, cool. Let's go and remove that. And now let's take a look at how to load some third party vendor styles and scripts. We've actually created an npm package for use with this course that will give us some Twitter Bootstrap CSS styling. Twitter Bootstrap is a CSS library, and we've created an npm module that has some specific styles that we want for this course. So if we go over to our terminal and stop our server here, we can install that like this. So this is an npm package that we created. Okay, cool. Now, if we go look in our node_modules folder, in addition to that ngf‑bootstrap folder, we also have a bootstrap folder. So that was a dependency of ngf‑bootstrap. And we have a jQuery folder. So, jQuery is also a dependency of that. I want to be clear here that jQuery is not required for Angular development. This is just part of that ngf‑bootstrap package that we pulled in. So there are a few files from here that we want to use, so go ahead and start up our server and come back over to Visual Studio Code. We want to load some things from those directories that we just installed. So if we go back over to our Angular CLI JSON file, then let's add above our styles.css, let's add node_modules ngf‑bootstrap. Then in the dist folder, there is a bootstrap.min.css. Okay, so this will load that CSS file. And then we want a script file from Bootstrap, and that's also in the dist folder, and in the js folder, there's a bootstrap.js file. And then Bootstrap uses jQuery for some of its menus, so let's grab that also. Okay, and since this is a change to our webpack config, which is a server‑side thing, we need to stop and restart our server. And then if we go look at our app, cool, you can see that the background color of our site has changed. This is because we're now getting our Bootstrap styling. And let's add a little bit of padding to our site. We can do that by adding a Bootstrap container. So, over here in our index.html, we can just on the body add a class container. So that's a Bootstrap class. Okay, now if we go look at our site, there we go, now our site has some nice padding. So now you know how to load static files in your Angular apps. Now, let's get to the real fun. Let's go create our first component.

Creating and Communicating Between Angular Components

Creating Your First Data-bound Component

Okay, so we've created our first Hello World component, but that isn't a terribly interesting component. In this module, we'll really start having some fun as we get into the meat of using components. In just a few minutes, we will have created a component that starts to demonstrate the power of Angular. To demonstrate this, we're going to create a page in our app that displays all of the upcoming events. So let's get started. Okay, so I'm going to create an events folder in my app folder. And this will hold everything used to display and work with events in our app. And then let's create our events‑list.component. Eventually, this will display all of our events, but to get started, let's just get it displaying a single event. This will be a great canvas to demonstrate some really cool, basic, Angular functionality. So just like we did with our last component, we will need a class that will eventually contain all of the business logic for this component. We'll call this our EventLstComponent. And of course, we're going to need to import our Component decorator and decorator class with it, okay, and this will just have a selector of events‑list. Now we just need to define the HTML content for this component. To get started, let's just display a title, we could do that like this. But that HTML is really hard to read, so to make our HTML easier to read, we're going to change this into a JavaScript string literal like this. We'll change these apostrophes to back ticks, and now we can have multi‑line HTML. If you're not familiar with string literals, they were added to JavaScript in the ES6 specification, and in addition to some other functionality, they allow you to define multi‑line strings like we have here. This allows us to create a much more legible HTML in our components. Okay, so now we have this basic component that we can start adding some interesting functionality to. Let's just wire this up so that we can see it working. To do that, let's open up our events‑app.component, and instead of displaying Hello World, let's pull in our component. So we've created our component, and we're pulling it into this page, or this other component, and it feels like that would be enough, but really we're missing one step. Let's go take a look at our page real quick. First, we'll make sure that our server is running, and that will compile our TypeScript for us. And now let's go take a look at our site. So if I refresh, notice that Hello World is gone, but our new component isn't showing up. This can be a kind of frustrating state. It seems like we've done everything right, but if we look at our console, you can see that there is an error here saying that events‑list is not a known element. Remember, we have to register all of our components with our module, and we haven't done that yet, so let's go do that. So over here in our module, we need to add our new component to our list of declarations, and of course we'll have to import that. Okay, let's save everything here and take a look at that. So if I refresh here, there we go, now are EventsAppComponent is referencing our EventsListComponent, and that EventsListComponent is being displayed here. Cool. Now let's go make it do something more interesting. First, let's create some sample data that will represent the data that we'll eventually get from an API. For now, we'll just add that data as a field to our class like this. Okay, so now we have an events object that has fields like name, date, price, etc. Now we just need to update our HTML to access that data, and we'll do that right here in our inline template. Let's start by displaying the name of the event. First, I'll add a little divider after our heading, and then we'll display the event name like this. Those of you who have done development in Angular 1 will immediately recognize this double braces notation, this is interpolation, and it represents a one‑way binding. When you put something inside these double braces, Angular will look for that object on the component. So in this case, Angular is going to look for the EventsListComponent class and expect to find an object named event. And it will find one because we've created it here. And then it's going to expect to find a property called name on that object, and it should find that here. So let's take a look at that. Awesome, you can see here that we're now binding to our event and displaying the event name. Now let's display the rest of the properties like this. So we're just going to use some Bootstrap classes here to give our event a little bit of styling, and then we're just going to start displaying each of the properties on the event. So let's move this down here, and actually we don't need two of these, and then we'll just display the rest of this data. And then we need to escape this dollar sign because we're using a string literal, and dollar sign curly brace is a syntax that's specific to string literals, and so we have to escape that dollar sign. Okay, now, if we go refresh our page, you can see that we're displaying all of our event data. That was easy. Hopefully you're already beginning to see how quickly you can build applications with Angular. There's a lot more to learn, but Angular really does make building applications easy. So we're starting to get a fair amount of HTML in our template here, and we had to do something weird here where we had to escape the dollar sign. In a later part of the course, Joe will talk about Angular pipes, and that will take care of our currency formatting, and we won't need this dollar sign here. But still, this template's starting to feel like it's getting a little bit bigger, and you may want to move this HTML out of your component. In the next clip, we'll take a look at how we can have our template files separate from our component files. And there's a practice exercise for this clip, so go check that out.

Using External Templates

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.

Communicating with Child Components Using @Input

Okay, so you can see how creating little components like this is pretty easy. Breaking our app up into lots of little components will make our application well organized and easy to maintain, but it won't be very useful unless we know how to communicate between them by passing data and events back and forth. In this clip, we'll learn how to pass data from one component into a child component. Before we jump into this, I want to call out a small inconsistency you might be noticing starting with this clip. If you take a look at the File Explorer over here, you may notice that the files here look a little different from the last clip and they don't match what was generated from the CLI. For example, this app directory is not nested inside a source directory. This is because when this course was first created, the Angular CLI was still in its infancy and we've since updated the course. Since all of our development for the rest of this course will pretty much all happen inside this app folder, there is no real need for us to update this file tree for the rest of the clips. Don't worry much about that inconsistency. If you're following along, stick with the file structure you've already built up from the CLI. Okay, so let's take a look at component communication. Right now, our events‑list.component is only displaying a single event, but we'll eventually change this to display multiple events. So to make things a little more organized, let's create a new event thumbnail component that will encapsulate all the display logic for a single event like this. And then our events‑list.component can just worry about showing multiple of these event thumbnail components. Okay, so let's create that event‑thumbnail.component. And now let's add the basic component code. Okay, so there is our basic component, and since this HTML is pretty straightforward, let's just put it inline in the component, and then we'll have to escape this dollar sign again. Okay, so now we have this component, and it's all built to bind to an event object, but the question is, where is this event object going to come from? Our events‑list.component is going to eventually contain a list of events, and it will want to create one of these components for every event. That means that the event data is going to come from the events‑list.component. So how do we pass that data in? Well, first of all, we need an event object in our class that our template can bind to. With TypeScript, we can declare that as a public property of our component like this. This is just creating a property called event and telling TypeScript that it is of type any, which is really just saying we don't care what data type it is. Later in the course, we'll start giving our variables data types so that we can take advantage of TypeScript's type safety and IntelliSense, but for now, any will suffice. So now we have this variable here, but there is nothing here that tells Angular to expect a value to be passed into our component. That's where the input decorator comes in. So let's import that and that comes from Angular Core 2. And now we can just add that decorator to our Event property like this. So this input decorator tells Angular that this event will be passed in from another component, and don't confuse the word event with JavaScript events. Again, this is just an event like a technology event or a conference. So let's go see how we pass in this event to our component. So we'll go back over to our event‑list.component and let's just take this HTML out of here and put it back in line in our component because it's very basic. Okay, so we don't need this empty HTML file anymore so let's delete that. And now our event‑list.component needs to display an event‑thumbnail component and we can just do that like this. So that matches the selector that we added to our thumbnail component. And again right now, this is still just displaying a single event, but we'll update this later to show multiple events. But we still aren't passing the event data into this component. Well, that's super easy. All we have to do is add an attribute like this. Okay, so we have too many things called event here and it's going to be hard to talk about, so let's rename one of our events to event1, so I'll rename this here to event1, which means we have to rename this 1 to event1. So these two values correspond to each other, and this event corresponds to our Input property over here. So when we add brackets around an HTML element like this, what we're saying is that this event thumbnail has an input parameter named event and we want to pass the value of event1 from this component into that component. So it's important that this matches the name of an input parameter and that this matches the name of a member in our component. You may think it's odd to have an HTML attribute that has brackets in it, but this is actually valid HTML. The HTML spec does allow for special characters like brackets in attribute names. We'll talk more about these brackets and lots of others syntax items in the next module on template syntax. But for now, that pretty much covers wiring up these two components with each other, except that we've forgotten to declare our new subcomponent as a component in our module declarations, so let's go do that now. So we need to import it, okay, and then we just need to add that to our list of declarations down here. Okay, so we're all wired up. Let's go take a look. First, let's go take a look at our batch console where we're running our server. So notice that our server is running in watch mode, so it is constantly watching for any changes and recompiling our TypeScript for us. If I scroll up, you can see it has recompiled multiple times as I've been saving changes. So let's go take a look at our app now. If I refresh this, there we go. So it looks exactly how it did before, but now this event thumbnail is coming from a different component, and it's getting its data passed into it from its parent's component through an input parameter. So it's pretty easy to pass data from one component to another. You simply create an input parameter or property on a component, and then in your HTML, you pass that in using the square bracket binding. Alright, in the next clip, we'll see how to pass data out of our child component back to the parent. And there is a practice exercise for this clip, so go check that out.

Communicating with Parent Components Using @Output

Okay, so you've seen how to pass data into a child component, but what if you want to pass data back out to the parent? We'll demonstrate how to do that here, and then you'll get some good opportunities to use component input and output throughout the course. When you think about component input and output, it's pretty common that input parameters are used when constructing a child component in order to give that child component its data. Output, on the other hand, is quite often used in response to some event within a child component so that the parent can receive some information when some event, like a click, occurs within the child component. At this point in our application, there's not much for our child component to do, but we'll demonstrate here the basics of how to use output parameters, and then you'll get more practice with some examples later in the course. Okay, to demonstrate this, we'll just add a button on the thumbnail component, and we'll add a click handler to this. Okay, we haven't talked about this type of binding, and we'll talk about it more in a later clip, but basically, this is just wiring up the click on a button to a function called handleClickMe on our component that we haven't created yet. Okay, so let's just go add that function to our component. And for now, let's just console.log something. All right, let's just go take a look at this so you can see that that click handler works. If I open my console and click on my button, there, it says clicked! Okay, that's working. But we're still not doing anything to tell our parent component that anything happened. In order to do that, we're going to have to add an Output property to our child component, like this. Okay, so we've decorated this eventClick property with the Output decorator, and we're setting it to a new EventEmitter. This is a very common pattern you'll see with Output parameters since typically Output parameters are used to convey some event that has occurred. Don't confuse the word Event here with our events application. The word Event here is about JavaScript events, and this EventEmitter is an Angular thing. So let's import the Output decorator and the EventEmitter, and now let's emit an event with this EventEmitter each time the button is clicked. And then we can pass a bit of data along with this event too. For now, let's just emit the string foo. All right, so this component is now outputting this data when the button is clicked. Let's go make our parent listen to that. We just do that by adding another event handler to the child component's element in our parent component, like this. So this eventClick binding has to match the eventClick Output property that we created on our child component here. Basically, we're saying that when the eventClick event is fired on our event‑thumbnail component, call this handleEventClicked method on my component. This $event refers to the data emitted with our event. And remember, in this case, it is the string foo. You can only pass along a single value with an event emitter, so if you need to send multiple values, you can just wrap them in an object first. So let's go ahead and add this handleEventClicked method, and we'll just console.log the data that we received. Okay, let's go save our files here, and then let's go take a look at it. So if I refresh and open the console, now if I click my button, there we go. Notice it says received: foo. So that value foo is what we emitted from our child component, and then we console.log that out in our parent component by binding to the eventClick Output property. We can make this a little bit more interesting by emitting some actual data from our child component, such as the name of the technology event that's being displayed in the event‑thumbnail. So let's come over here, and here we're receiving in our conference event, and that has a name property on it. So let's just love that out. All right, let's take a look at that. So if I refresh this now, now if I click on this, notice it says received: Angular Connect, which is the name of our event that we're displaying in our event‑thumbnail component. Okay, so that's all there is to passing data back to the parent component from a child component, and you'll get some great opportunities to practice using this later in the course with some real data that makes more sense. For now, we're not going to need this demo code, so let's get rid of this handleClickMe event handler and the Output parameter. And we'll get rid of the button. And then over in our parent component, we'll stop handling the event and get rid of the event handler down here. Okay, so that's all cleaned up. And again, you'll get a chance to practice this a little bit more later in the course. And there's a practice exercise for this clip, so go check that out.

Using Template Variables to Interact with Child Components

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.

Styling Components

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.

Exploring Angular's CSS Encapsulation

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.

Adding a Site Header

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.

Exploring the Angular Template Syntax


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.

Interpolation, Property Bindings, and Expressions

Okay, consider this block of code. We have a component here with an inline template, and our component has a user property and I doSomething function. Let's take a closer look at our template. This is interpolation, and this is a property binding. Both of these are used to bind data from the component to the template. Interpolation is used when you just need to display that data, such as when displaying the username in an h2 like we are here; whereas, a property binding is used when you want to bind the data to the property of a DOM element. In this case, we're binding the user's image URL to the src property of this image tag. Interpolation and property bindings both use expressions to specify the data from the component to bind to. As you can see, to use interpolation, you enclose an expression in double braces. But to bind to a property, you put the property in square brackets and the expression in quotes. Expressions are interpreted by Angular and typically reference a property on the component. In both of these cases, we are referring to the user property on the profile component. However, expressions aren't restricted to just component property bindings. You can actually use a JavaScript‑like expression. For example, instead of using user.name here, we could use an expression like 2 + 2, and Angular would evaluate this expression and display the value 4. I could even call a function on my component like this, but you can't use any expression here, and there are some recommendations on the types of expressions you should use, so let's take a look at those. First, let's look at the expression restrictions. Expressions cannot use assignment operators, such as equals, plus equals, plus plus, etc. They also cannot use the new keyword to create new objects. You are also restricted from chaining multiple expressions together in a single expression using semicolons. And finally, you can't access anything on the global namespace, such as console, window, etc. These are the most notable restrictions. Now let's take a look at some recommendations for expressions. Perhaps most importantly, expressions should have no side effects. This means that calling an expression should not change any data or the state of the application in any way. Angular applications should have a unit directional data flow, and changing the state of the application, while evaluating expressions, can have some nasty consequences. Next, expressions should be fast. Expressions can get called more frequently than we realize, and so it's important that they be fast. Expressions also should be simple. You don't want a lot of business logic in your templates. That really belongs in your components. And finally, expressions should be idempotent. Or in other words, each time you call an expression, it should return the same result. This is largely maintained by making your functions have no side effects.

Event Bindings and Statements

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.

Repeating Data with ngFor

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.

Handling Null Values with the Safe-Navigation Operator

So far, we haven't had any problems with null or undefined values in our data, but we need to be aware of issues that missing data can cause us when we're binding to objects with interpolation like we are here in the event‑thumbnail. What if this event object we're binding to is undefined? If you've done development with Angular 1, you may expect this to work just fine, but in order to avoid hidden runtime bugs, Angular isn't quite as forgiving as it used to be. Let's just see what happens if this event is undefined. That's easy enough to do. Over here where we're calling our event‑thumbnail component, we just won't pass in this event, so that will cause the event to be undefined in the event‑thumbnail component. So if we go look at our site, okay, looking at this, at first glance you might think that it's working without errors and just not displaying the data. But if we look at our console, you can see that our app is broken and displaying errors here. And if we scroll up to the top, you can see this error, Cannot read property 'name' of undefined. And up here, you can see that the error occurred in our inline template on line 2. So if we go take a look at that template, you can see on line 2 we tried to bind to the name property of this event object that was undefined. Just like you would expect in any JavaScript code, this throws an error. So what do you do if the event might be null? That's where the safe navigation operator comes in. We can just put a question mark after the event, like this, and we'll have to add that everywhere where we use the event in this template. Okay, let's go take a look at that. First we'll clear our console, and then refresh. Okay, you can see that we're not getting errors anymore because it's safely handling that undefined object. One thing that's interesting to take note of here is that we handled the case where event is null, but notice down here where we have event?.location.address that we didn't blow up even though location is essentially undefined because event was undefined. That's because the safe navigation operator short circuits the evaluation of the expression so that you don't have to put question marks throughout your entire expressions if you know that, for example, location won't ever be undefined if the event is defined. So that's working, but what if our location object can be undefined, even for a valid event? Let's change our data a little bit so that we have another use case for this. So down here in our data on our second event, we'll collapse these sessions here, so in our second event here that is for ng‑netherlands, what if this event had no physical address, but was online only? So we'll change this like this. Okay, so now this doesn't have a location and does have an online URL. So let's put this binding back that we removed earlier. And now if we go back over to our app and refresh, you can see it's broken again because we now need a safe navigator on the location object. So event was defined, but location was undefined. So let's add a safe navigation operator here. And while we're here, let's go ahead and add support for Online URL. Okay, let's have a look. So we'll clear our console again and refresh, okay, we're no longer getting errors, and you can see that this is working, so we're not getting a location here and we are getting an Online URL. But this is kind of ugly how the location is showing up empty here, and then we have these empty Online URL fields on all the other events. It would be nice if we could just hide that data when it's blank. In the next clip, we'll see how to do that using the ngIf directive. And there's a practice exercise for this clip, so go check that out.

Hiding and Showing Content with ngIf

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.

Hiding Content with the [Hidden] Binding

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.

Hiding and Showing Content with ngSwitch

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.

Styling Components with ngClass

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.

Styling Components with ngStyle

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.

Creating Reusable Angular Services

Why We Need Services and Dependency Injection

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.

Creating Your First Service

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.

Wrapping Third Party Services

It's pretty common in web applications that we'll want to use third‑party libraries or components. Let's take a look at how we might take something like that and turn it into an injectable service in Angular. To demonstrate that, we'll use toastr. Toastr is a JavaScript library that allows you to create pop‑up notification messages like this. Notice this message here. So let's see how we would use this in our application. First, we'll need to npm install toastr, so we'll come over to our bash console, and stop our server, and then we'll just run this npm install command. Okay, so that npm module that we just installed gives us a style sheet and a JavaScript file that we need to import. So let's go import that. So over here in our angular.json file, right here at the top of the styles, we'll import the toastr styles. And then down here in the scripts, we'll import the toastr JavaScript file. Okay, so now toastr will be loaded with our app, but the question is, how do we make this consumable as an Angular service and use it in our components? So let's make it so that when you click on this event thumbnail, we display a toast message that shows the name of the event that was clicked. So first, let's wire up the click event. Okay, so we have this event available to us here because we're looping over all the events in this ngFor. So this will appropriately wire up this click event for each event thumbnail and pass in the appropriate event.name when you click on the thumbnail. Now let's add this method to our component. Okay, so that click handler is now wired up to this handleThumbnailClick method. So now we just need to display the toast message inside this method. So when we load a toastr in the Angular CLI config, that made it globally available. So we could just call it right here like this. Now you can see here that our IDE is complaining because it knows that TypeScript is not going to compile this. That's because even though toastr is available globally, TypeScript doesn't know about it, and so it thinks that this is an undeclared variable. So we just need to declare that up here like this. This just lets TypeScript know that this variable is in scope already declared somewhere else. So we come over here and refresh this. When I click on one of these, you can see I get a toast with the name of that event. So that's working, but there are a couple of problems here. First of all, we're using a global reference for this toastr object, and using global objects is never a good idea. And then finally, another problem is that this is not testable. Since we're not injecting toastr into our component, we can't mock it, and so that makes it difficult to test this component. So let's take a look at how we would create an Angular service around this that we can inject. Alright, so we'll create a ToastrService, and it really doesn't belong in this events folder. So let's create a common folder for items that will be shared commonly throughout the app, and then we'll create our service here. Alright, so in here, let's create a Toastr class, and let's make that injectable so that Angular knows about it. And, as always, don't forget these parentheses here. Okay, now we basically want to wrap each of toastrs methods. It has four methods that we're interested in. The first method is called success, and you call that like this. So you pass in a message and the title. Let's create a method on our service to wrap that like this. Okay, so now we have a success method on our new ToastrService. We didn't have to name this success, of course. We could call it anything. The important part is that we're calling success on the toastr object. But we still have a problem here. Our compiler still doesn't know what this toastr object is. We're just going to tell TypeScript not to worry about that, and you can do that by declaring a variable like this. So this will tell our TypeScript compiler that toastr is an object that we know about. And in this case, it's something on the global scope. But now at least accessing our global scope is limited to this class and we won't be using it all over our application. Okay, now let's go ahead and wrap the other toastr methods. Okay, cool, so now we have an injectable ToastrService. Alright, so this service is ready to use. Let's go back over to our events‑list.component. We're going to have to import it, and now we can just simply inject it down here. And then down here, we'll use our injected ToastrService. And now the step that's easy to forget. We need to add our ToastrService to our AppModule. So we'll declare it as a provider here, and then we'll have to import it. Okay, that should do it. Let's see if that's working. Let's refresh, and click on our events, and there we go. We're getting our toast messages. That's working great. So now we aren't using a global variable in our code anymore. TypeScript is happy, and our code is much more testable than it was.

Routing and Navigating Pages


In this module on routing and navigation, we'll explore how to define URLs for pages and navigate between them in our app. We'll talk briefly in this introduction about why routing is necessary, and then in this module we'll see how to define routes for various pages in our site. And then we'll see how to add links that activate those routes and how to navigate to those pages from code. We'll also learn how to prevent routes from being activated or deactivated using route guards, basically preventing users from navigating to or away from pages. And we'll look at how to preload the data for a page using the resolve route handler. We'll also demonstrate how to style links based on whether their corresponding route is currently active. And finally, we'll see how to lazily load different sections of our site so they're not loaded into memory until we need them. So let's just talk quickly about why routing is necessary. In a traditional website before the advent of single page apps, each page was completely separate and distinct from others, and every page was served independently from the server. When you went to index.html, the browser would ask the server for the index.html file, which the server would then return to the browser and then display. And if you went to foo.html, it would ask the server for that file, and the file would be returned and then displayed. And the entire page would be replaced, even if 60% of the page was the same as the prior page. Modern web applications,, however, load an app into memory by loading just a single page, typically index.html, and then all other pages are actually loaded via JavaScript. But they're not really full pages. Your initial index.html is the only full page load. And then only portions of that page are replaced as you navigate from page to page around the site. To the user, it seems like new pages are being loaded. They even see the URL changing in their browser, and the back and forward buttons even work despite the fact that only one index.html page has ever actually been loaded from the server. There's a lot that goes into making this work, but frameworks like Angular have abstracted a lot of that away and made it very simple. So let's take a look at how we can make this happen in our app.

Adding Multiple Pages to Your App

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.

Adding Your 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

Accessing Route Parameters

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.

Linking to Routes

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.

Navigating from Code

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.

Guarding Against Route Activation

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.

Guarding Against Route De-activation

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.

Pre-loading Data for Components

So we've taken a look at the canActivate and canDeactivate route handlers. But we haven't looked yet at the resolve route handler. Resolve allows you to prefetch the necessary data for a component or to do other checks prior to loading a component. We haven't really felt the need for this in our app yet because the data is all being provided synchronously from local variables. But this isn't very representative of the real world. Let's change our event service so that getEvents acts a synchronously like it would if we're making an AJAX call. In order to make this asynchronous, we're going to use an RxJs observable. Don't worry too much about the syntax we're going to use here. Joe will talk a lot more about observables in his module on HTTP and observables. But for now, we're just going to go ahead and import Subject from rxjs. And then inside our getEvents method, we'll just create a new Rx observable Subject like this. And then in order to make our getEvents method act like it's asynchronous, we're going to use JavaScript's setTimeout method like this, and then we'll just return our observable. Okay, just to explain this a little bit. Observables are like streams of data. They are kind of like arrays where the data arrives over time. Angular is designed to work very well with both observables and promises, so we're going to take advantage of that. So basically, Subject is a type of observable. And right here, we're adding data to this observable stream, and we're doing it inside of setTimeout to simulate asynchrony. So after 100 milliseconds, we'll add data to the stream. And then you can see right here that we're returning the observable. We were previously returning the data directly. So we're going to have to go adjust the consumer of this data. That's over here in this events‑list component. So right here, getEvents is going to return on observable, and you get the data out of an observable by subscribing to it like this. And that's going to eventually return instead of immediately. So instead of setting this.events to the return value of getEvents, we're going to set it only when data is received, which happens inside our subscription, so we can set that like this. And to get TypeScript to stop complaining, let's just change this to any for now. Now let's go refresh our page. Okay, you can see that's still working. But now we're getting our data somewhat a synchronously, and it's happening through an observable. Again, we'll touch on observables more later. Okay, so let's go add in a little bit more of a delay in our asynchronous method. So let's make this wait for 2 full seconds. Now if we refresh, you can see the page partially loads, waits for 2 seconds, and then finishes loading. This doesn't look so bad on this page, but on some pages, this looks really bad if the page partially loads and then the data pops in afterwards. So let's add a resolve route handler to this route so that we can wait for the data to load before displaying the component at all. To do that, let's go add a events‑list‑resolver service, and let's add our basic shell. Okay, so this is an injectable service that implements resolve. In the resolve method, we will typically make an asynchronous method call like an AJAX call. And then when it returns, we'll return that data. So we're going to do that like this. Alright, and we'll have to inject our event service. Alright, and let's fix our typo over here. So this is a very basic implementation. We're calling getEvents, which returns an observable. And then we're calling map on that observable, which gives us access to the events that are passed in on that stream. And then we just return those events. So we're receiving events in to this function, and then we're just returning them right back out. Okay, and we need to import this map function. Okay, and one more thing to clarify about what we've done here. Typically, when you listen to an observable, you would call subscribe here. But because this is in a resolver, we need to actually return the observable to Angular so that Angular can watch the observable and see when it finishes. If we were to call subscribe here, the value that would be returned would not be the observable. Subscribe returns a subscription, not an observable. And so we use map, which kind of does the same thing as subscription in this case, and it returns the observable. So then, because we're returning the events inside our map expression, these events will then get passed along to the component defined in our route. Okay, so this resolver is finished now. So let's go consume this resolver, and hopefully it will all start to come together and make sense. So let's add this as a provider in our module so we don't forget. Alright, and we'll add it down here as a provider. Okay, and then we need to add this as a resolver to the route on the events‑list route. So let's come over here. Okay, so here is our events‑list route, and this is where we want to add a resolver so it will look like this. Alright, let's import that, and then we'll talk about this. Okay, so if we take a look at what we're doing down here where we're adding this resolve handler, notice that we're passing in an object, and that object has a property, events, and that property value is set to the EventListResolver. Okay, so basically what this is saying is before resolving this route, call this EventListResolver. And when that resolver finishes and returns us some data, add this data to the route as a property named events. So it's going to take the events that are returned from the resolver and put them in a property named events on the route. Okay, so now let's go over to our component and consume that. Okay, so in our ngOnInit, we were calling getEvents and subscribing to that. We don't need to do that anymore because we're doing that in our resolver. Instead, that data is now put on the route for us, and we can just get that data right off the route. So let's go inject the route. Inject that here. Okay, now our onInit is just going to look like this. Okay, so just to tie this all together, notice that this events right here matches this events over here on the route. So that's how that's all wired up. The resolver gets the events from the event service, the route takes that and puts it on the route, and then we can access it in our component. Cool, let's check that out. So now I'm going to refresh this, Okay, notice it's still taking 2 seconds, but this Upcoming Angular Events that is part of the Events List page does not show up until all the data's been loaded. Okay, that's pretty cool. And the great thing is, we only have to load our data once. Notice that our resolver loaded our data for us and put it on the route. So we didn't have to wait for the data to be loaded in the resolver and then load it again in that component. Okay, and just to clean up here, let's go over to our events service and change this timeout back to just 100 milliseconds. And there's a practice exercise for this clip, so go check that out.

Styling Active Links

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.

Lazily Loading Feature Modules

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.

Organizing Your Exports with Barrels

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.