What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
Angular: First Look
by John Papa
This course is a gentle introduction to the changes that Angular 2 brings, how they compare to Angular 1, and provides an understanding of the architecture and how the core concepts work together to build applications.
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Learning Check
Recommended
Course Overview
Course Overview
Hi everyone, my name is John Papa. Welcome to my course, Angular 2: First Look. I'm a web architect, Angular developer expert, and the author of the official Angular style guide. I'm very excited to share this course with you. This course is a gentle introduction to the evolution of Angular 2. It provides an over-arching view of Angular 2 and how the core concepts fit together to help us build applications. We'll learn how our Angular 1 skills translate and have prepared us to build Angular 2 apps. I've updated and extended this course, including its code samples, to reflect the final release of Angular 2. You'll find over an hour of new material, including two entirely new chapters on routing and Angular modules. The major topics that we'll cover are components and their templates, template syntax including data binding, services including dependency injection, routing, HTTP and data, observability with RxJS and how Angular modules help us organize our code and set us up for optimizations like lazy loading in our applications. By the end of this course we'll have learned these concepts and more and we'll be well on our way to building Angular 2 apps. Before beginning this course, you should be familiar with JavaScript, but you don't have to be an expert by any means. Please join me on this journey to learn Angular 2 with the Angular 2: First Look course on Pluralsight. We hope you enjoy it.
Angular 2 in Action
Angular
Angular 1 applications have spread like wild fire on the web, establishing Angular as a core framework in many company's toolbox. As the web evolved, so did Angular - into Angular 2. It's a full and modern web framework that enables us to create powerful applications. This course provides a developer's first look at Angular 2. We'll learn its benefits, understand the role of its features, and how to build Angular 2 apps. Hi, I'm John Papa, and I'm excited to welcome you to Pluralsight's Angular 2: First Look course. This course is a first look, which makes it an ideal starting place for us to see the over arching view of the core concepts in Angular 2 and how to write apps with it. We'll learn how our Angular 1 skills translate and prepare us to build Angular 2 apps. The smoothest way to see the value in Angular 2 is to jump right in. To that end, we'll be coding in the Plunker online editor, this will streamline our learning experience by enabling us to run all samples live on the web where we can see and edit them with a click of a button, no setup required. ES5, ES2015, TypeScript, we have plenty of options. While we can write Angular 2 in a variety languages we had to choose one, so we'll use TypeScript. If you want to learn more about TypeScript, check out the TypeScript Fundamentals course that Dan Wahlin and I co-authored here on Pluralsight. Before beginning this course you should be comfortable with the basics of JavaScript, while familiarity with Angular 1 and TypeScript will be helpful, they're certainly not required. But let's start by asking, why Angular 2? I mean, who will I be if I learn and use Angular 2? The answer to that question lies in understanding Angular 2's value to companies and developers. Well, it's fast, much faster than Angular 1 as it relies on modern web standards and practices. It's powerful, Angular 2 is a full framework that covers the common use cases we all encounter. And we write clean code with Angular 2. There are less Angular constructs, for one example, Angular 2's templating syntax alone removes the need for dozens of features from Angular 1. Instead, you write HTML and pure JavaScript or TypeScript. And my favorite is writing Angular 2 is easy. The concept count is way less in Angular 2 than it was in Angular 1 and the code you write is far more intuitive. We often don't have the luxury of picking which browser our customers will use, that'd be great, some of us have to support a variety of browsers and versions. We're happy to know that Angular 2 supports all of these browsers, even IE back to version 9. Angular 2 is already being used internally by Google for a massively large app that makes a lot of money for them, you may have heard of it, AdWords. So what can we build with Angular 2? This course covers the core concepts of Angular 2, including components, shared services, navigation between views, dependency injection, data management, and user and system events. But now let's take a look at the app that we're going to use to learn Angular 2.
What Can We Build?
We all love a good story, but it can be difficult to keep track of characters and their experiences. The demonstration vehicle for this course will be a storyline tracker, which is a simple application to manage fictional characters and their vehicles. This course will be presented in chapters where each will shine a light on the core concepts in Angular 2, for example, routing between different pages so we can navigate, drilling into detail pages so we can edit, the new template syntax and data binding, how to modularize your application by using components, how to share different functionality by using services, and we'll be demonstrating how features have either changed from Angular 1 or they're entirely new. There are over 2 dozen samples in this course, all showing how they contribute to building the storyline tracker application.
Running the Samples
An important part of the learning experience is working with the sample code, all the samples will be able to run live on the web, so you can code along and run all the samples with me. There's zero setup required, you just need a browser and internet access. You can even download the samples right from Plunker, just go to this URL here and you'll be presented with this screen. Here you can see all the samples that we'll be running for Angular 2. There's even a couple in here for Angular 1 to show us the comparison between how a controller looked in Angular 1 and how it looks as a component in Angular 2. Just find the sample you want, they're numbered and they're titled with descriptions, and click on the sample. For example, an Angular 2 component, we can click on the sample over here and it opens it up in a Plunker window. Then we can navigate to the files on the left, change the code right here and see it run on the right, and because all the samples run online, as Angular 2 evolves, we'll be updating all these examples so you get the latest code. The same samples are also included for download in this course for Pluralsight Plus subscribers. Okay, but what do we do beyond our first look? This course is indeed a first look. I recommend that you follow the QuickStart and the tutorial on the angular.io doc site. The QuickStart will always be up-to-date with the latest things that you need to get started with Angular 2. And after you take this First Look course, keep your eye out for the Getting Started with Angular 2 and the Angular 2 Fundamentals courses on Pluralsight.
Angular 2 Architecture, What's New and What's Different
Angular 2: What's New and What's Different
Let's get started with some Angular 2 Architecture. We'll cover what's new and what's different. This module we're going to show you how the concepts we know from Angular 1 are still fundamental in Angular 2, and more importantly how our Angular 1 skills can translate to Angular 2. We'll discuss the different language options we have and then we'll take a brief look at the impact of Angular 1 on the modern JavaScript landscape. This is going to help us understand why a good migration of Angular 1 skills to Angular 2 skills is really important. Of course we're going to highlight some of the most compelling features and walk through some examples step by step of Angular 1 side by side with Angular 2. And then finally we're going to cover some resources that may be worth exploring afterwards. Let's get started.
Language Choices
When we start to dive into Angular 2, we have many choices of languages that we can use. This isn't unique to Angular, it's part of the evolution of JavaScript and the web. There's four main choices, let's explore each of these. We'll start with ES5. It's been around for years and all modern browsers support it out of the box, it's just JavaScript. It doesn't require any compilation, it just works. ES5 is also the most common language that people use to write Angular 1. Next, ES6 is another option we have. It offers modern language features, such as classes, import and export of modules, ES6 destructuring, and the simple but effective let statement. It's a much cleaner way to develop, but we need some help getting all browsers to process it. But this is easy when we use compiler like Babel. ES5 and ES6 both don't support types, but TypeScript does. TypeScript is an evolution of JavaScript, always adopting the standards and adding a few extra features. Their mantra is JavaScript is a valid TypeScript. And did you know that the Angular team is actually writing Angular 2 in TypeScript? Most notably it adds interfaces and types, so TypeScript's big advantage is that it helps detect errors while we type. The modern editors use the TypeScript compiler to check the code and alert us when we make a mistake. They can also help give us hints on parameter signatures and available members of a class. Like Babel, with TypeScript we also use a compiler to use ES5 so browsers can use it. The good news is ES6 is a super set of ES5. And the better news is TypeScript is a super set of ES6, and TypeScript adopts emerging standards such as decorators. We're going to see these in just a bit. The fourth option, Dart, is another way we can go. But adoption for it is the lowest among these. Now I appreciate getting hints when I type something wrong and I love having IntelliSense and autocomplete when I type, so in this course we're going to be using TypeScript, but in your everyday programming you can pick which one you want.
Angular 1's Impact
Let's take a look at the impact that Angular 1 has had on the modern development landscape. Angular 1 is really widely used and it's got a massive ecosystem, so what does that mean? Well there's a lot of community efforts behind Angular and there's some great products like Firebase and internationalization for Angular material, and those are just to name a few. So why such a huge ecosystem? Well maybe it's because there's 1.1 million developers that have used Angular, according to Brad Green the director of the Angular team. So let's take a look at how we can lean on our Angular 1 skills to kind of get us to Angular 2. Our Angular 1 skills matter, and you know what, there's less to learn in Angular 2. So let's go over seven things that we'll all be familiar with in our transition from Angular 1 to Angular 2.
Angular Modules
Let's start by taking a look at Angular Modules. First in Angular 1 we used to have this IIFE, where we had a function and then inside of it we used the angular.module function to define a module called app in this case, and it had no dependencies. And then we would refer to that module name inside of our HTML, and our dependencies if we had any would go in here and that became our root module. Now in Angular 2 the module concept is a little different, in fact we're going to call them Angular modules. So these Angular modules, or NgModules, are a little different because you import them from Angular and then you use them as a decorator on a class, we define a class called AppModule and then we use the decorator to tell this module where is it going to get its imports from. Effectively we're going to run this in the browser so we're going to import the browser module, which Angular provides to us. We'll learn a lot more about modules, because they're an integral part to Angular 2, throughout this entire course. So here we're defining our too module, which every application has.
First Look at NgModules
We're going to flip over to a browser and we're going to type in the address of where we're going to find all the samples. That's at angular2-first-look.azurewebsites.net. And on the site you're going to see a list of all the samples and then over on the right hand side you can click on the button to view the sample. We'll do that in just a sec. You can also get to the source code for all these at GitHub link up here in the right hand corner or go to the Angular 2 docs or my blog for more information. Let's start by clicking on the example for Angular 2 Component, which is right here. Now it's going to open up two tabs, the second tab is actually going to be a Plunker, a Plunker is an online editor we can run our code, and you can see over here in the tree view, we've got a module and a component. Let's take a look at a module, since that's what we were just talking about. Let's take a step back since it's the first time we're in Plunker here, to understand what we're looking at. On the right we've got a preview, in the middle we've got our editor, and on the left we've got our tree view for our files. Let's say you wanted to make some more space, we could actually click on the file right there and there's going to toggle that. Or we could use Alt+F. You can also check out the settings in here and change your theme, increase your font size, or the refresh interval because every time we type into the editor it's automatically going to rerun the code. For example, if I come over here and I just put a couple of enter keys here, it's going to reload on the right hand side. Great. And if you want to download the files, you can just click on the cloud in the upper right hand corner. Feel free to explore in Plunker, it's a pretty cool tool. Now let's take a look at the modules here, on line 6 you can see we've got an @NgModule decorator. That decorator is decorating what's on line 11, the class. So our AppModule, which is something we're going to have in every single Angular 2 project, it's the root module, is what defines what our application is going to use. We'll telling it, okay this guy is going to import the browser module. We always tell Angular what our platform is. In this case our platform is the browser. And then we have to declare any components we're going to use, in this case we're declaring a story component and we'll learn more about those in just a moment. And then we have to tell Angular in our root module, our application module here, what we're going to bootstrap the application with, and what does that mean? Bootstrapping is the process of telling Angular - where do I start. We're telling it start with this story component because after all we could have like hundreds of components if we wanted to. So we want to tell it which one is the starting place. And then up top you might see these import statements, those are TypeScript imports. We can also do these kinds of things in ES6 as well. You might have also seen in older versions of Node, we can use require statements, or if you're familiar with .NET maybe in C# use using statements. These are ways of referring to other modules. So in this case, we're referring to other ES6 modules like a story component, that's our code. Or referring to the NgModule or browser module that Angular provides to us. So we reference those, pull them in and use them to define this module. So we've effectively created a simple application module that's going to run on the browser and it's going to start at StoryComponent. And how do we kick this off? For that we start over in main.ts. Main.ts effectively is our kick off point for our application. It says, what am I running? In this case I'm running the platform browser. And then I want to bootstrap my root module called AppModule. So the application starts here, kicks off the AppModule, which is over there, and then it reads this AppModule to figure out what does this application need. Awesome. Now that we know about modules, we'll take a look at the next step.
Controllers to Components
In Angular 1 we had a controller, we define that in our template with like ng-controller, or we could do it in a route, and then we refer to the name of the controller, such as here it's StoryController, and that would refer back to some code where we defined that controller. So we had a template and we had some code. In Angular 2, what goes in the template is just a reference to what is my component name? Well in this case we call it my-story. And the code that it's referring to is the selector in the component down below. In our code, TypeScript in this case, we import the component decorator and then inside of there we define that this class, this story component, is going to be known as my-story in the HTML templates. And our template is going to be an h3 that just puts the story name there. Let's go take a look at an example.
First Look at Components
We'll flip back to our demo application and we'll go down to number 2, Angular 2 Component, and we'll open the same example, and here, remember we had this app.module and it was declaring on line 8 that we're going to have a StoryComponent and that was also where we're bootstrapping? Well let's go look at that StoryComponent in this file. How do I know it's that file? Well obviously it's the only other file in this project, but also on line 4 of the app.module, notice it's referring to story.component, we leave off the .ts. That's how we import that ES6 module. So let's click on the story.component and we can see the same things we saw in the slides, here we're importing the component and then we're using that decorator to say okay this class here on line 12, StoryComponent, is going to be something that's got a story property and a color property, and then we can use those inside of our template. Now notice the template is being defined in line, inside the decorator, and we're also using this back tick, that is not a quote. I quote you, that is not a quote. That's a back tick. Now you might have never seen it on the keyboard before, it's up in the upper left hand corner, basically if I don't use that and I put in a single quote, watch what happens here. Things just don't go so well for the application and it doesn't load on the right hand side, because you can't have a multiline string. So we need the back tick, and this is something that was introduced in TypeScript, that we can use. So now we have a multiline template string. And here we've got an h3 and a div and some other things, and we'll explore that these things do, but you can see on the right hand side we're just putting the name of the movies on the right. So our component is made up of a class that might have properties and functions, and then it also has a selector to define it inside the HTML. As you might guess there's going to be a my-story selector tag inside of our index.html. And then we define what that template is going to be. So back in the index.html, we can see here on line 11 we have a my-story and then what's in between those is going to disappear once it loads, and then it shows all the content that was in the template we defined.
Structural Directives
In Angular 1 we had different directives that we could use for things like looping through a list or maybe optionally showing different content, ng-repeat and ng-if in this case. Well we have something very similar in Angular 2, and get ready for it, they are ngFor and ngIf. Now the syntax is a little bit different. Here you can we've got to precede it with a star and then we say ng and then we use the camel case to do For. Same thing with the ngIf. And the syntax inside them is slightly different too. So we can look at the ng-repeat and the ngFor first. In the ngFor we're saying let the vehicle of vehicles. Now vehicles in the far right is the list we're going to go through, maybe an array of vehicles, and then we're going to say let vehicle, it's basically defining a variable, to loop through those. So for every iteration of this li tag, we're going to have a different vehicle. And then we can use vehicle.name to display it. Let's take a look at the if. The if just evaluates an expression and if it's truthy or falsey, it's going to display or not display the content. Now you might be wondering about those stars, let's talk about them for a minute. In Angular 2 these things are called structural direction. Whenever we see that star, yeah it's a structural directive because it's changing the structure of our DOM. So that star is important. It's a shorthand syntax where instead of having to list out the template tag, which is part of HTML5, it's telling us, okay I'm going to take care of that for you, just precede this with a star and I'm going to replace this with a template, so I can basically just rubber stamp all these different li's into your application for all the vehicles. There aren't too many structural directives in Angular, but these are two of the most popular that we're going to use, and that let vehicle, that's going to be a local variable that we can reference inside of the li. Let's go take a look at an example.
First Look at Structural Directives
Back in our sample we can scroll down a little bit and we can see sample 4 is going to show us an Angular 2 Structural Directive. Sample 3 right above it, is an Angular 1 if you want to get a refresher. We're going to click on sample 4, open it up in Plunker, and then it's going to run our demo. We're just showing three different vehicles. Let's go click on the vehicles.component.html. Here we can see we've got a components HTML for the template, which is showing us our li's that we're looping through and then an ngIf. And how's that getting loaded? If we go over to the vehicles.component.ts or TypeScript file, notice now the template on line 6 is referring to a template URL property. So it's not embedding the template inside of the component, instead it's pointing to a URL right here, vehicles.component.html, and it's going to find it right there, side by side. So back over here, if we change this ngFor up a little bit, we could say let vehicle of vehicles and then we can change it to like v, notice it's not going to render over here now, we just see three dots because it's listing three things, but it doesn't know what a vehicle is. Once I change that to a v to match it, it should load and launch it there. Now we can also change things down here, like the vehicle's length. Once we make that a falsey value, it's not going to show anything. So it says we have three vehicles, well what if we didn't have three? What if we say if it equals 5 or 55? Now it's going to load on the right hand side and we don't see that message down at the bottom. Once we make that a value that it equals, like 3, it's going to show it. So we can show that we can put any kind of expression here that shows truthy or falsey. Some people like to say things like length is greater than 0, and that works too and there's nothing wrong with that. I happen to like to write the shorter hand of just length because length is going to evaluate to 0 or 3 and if 0 is a falsey number, so it wouldn't show it, and 3 is truthy so it does. So here we can see different ways to use ngFor and ngIf.
Data Binding
One of my favorite topics about Angular is the way it does data binding. Let's explore what data binding is and how it works with Angular. First we're got a DOM, that's our browser, and then we've got a component, our code. And we need to get the data to pass from the component to the DOM and sometimes back. So we have different ways to do this. We've got Interpolation, which sends the data one way up to the DOM, we also have One Way Binding, which again sends it one way up, we have Event Binding so we can talk from the DOM with user actions back to the component, maybe like a click event, and then we have Two Way Binding. Let's look at each one of these. In Angular 1 we had interpolation as well, we used the double mustaches or handle bars or curly braces as you call it, and we put in there the expression we want to evaluate and it would show that value. In Angular 2 we've got pretty much the same thing, we've got those handle bars again, but this time we don't actually need the context of vm, we recommended that with Angular 1 in the style guide because it gave it a context. Well our context is the component now in Angular 2, so we don't need that. Okay so what about one way binding? In Angular 1 we could also do ng-bind, a built in directive. Well that would display the value, sure. In Angular 2 we don't actually need ng-bind, we can now just say take a property in HTML, innerText in this case, and let's bind it to a component's property, the story.name. So as you might imagine, there's a story object that has a name property in my component, and its value would then display inside the innerText. Now those square brackets are the way that we do the one way binding in Angular 2. So we put the square brackets around any valid property in HTML. That's really important. So you can do things really cool like this. Now we can say there's a div, I want to set the style's color, style is a property on the div and it's got a color property, so we can say okay bind that up, put those square brackets around it, to a color property in my component, red, blue, green, whatever, and then it'll set the style's color. We can bind to any HTML element property. This is super important and super powerful and it gets rid of a ton of directives that we used to have to have in Angular 1. Okay that's one way binding and interpolation, now let's take a look at event binding. Sometimes we need to be able to take user actions and send them from the DOM back down to the component. In Angular 1 we used ng-click, ng-blur, ng-focus, all that kind of fun stuff, a bunch of built in directives. In Angular 2 we just use the parenthesis to wrap around existing events on HTML elements. So we might have an event like click or blur that are already in HTML, so let's just take advantage of them and wrap them with parenthesis and say when you see this, when you see click, go ahead and call this function called log in my component. Easy huh? Alright two way data binding. In Angular 1 we use a thing called ng-model to do this. We have to go up from the component to the DOM and then from the DOM back to the component when something changes. Most commonly you'll see this with input elements. We load the story, somebody wants to change the story's name, and it goes back into the component. In Angular 2 we have a helper directive here, a built in directive called ngModel, same name, slightly different spelling, instead of a dash we're using camel case. And now we're wrapping it with parenthesis and square brackets. Now at first you might do what I did and go whoa what's that thing? But it actually makes sense. You see, what we really want to do is we want to take the story name and load it from the component to the DOM. Well that would imply we need the square brackets. Cool, we go those. And we also want to take the input from the user when they're typing it in and send it back to the component. Well that would imply the parenthesis. So we use both of these. And if you took out the model ngModel in there, what you really have is a football in a box. So that's how you remember that the parenthesis go inside of the square brackets. Now let's go take a look at how we do data binding and some code examples.
First Look at Data Binding
Back in our demo let's slide on down to the data binding examples, number 6 is Angular 2 Two Way Data Binding, we'll click on that. And inside of here, we've got an application which has got a couple different inputs. Well let's take a look at our component TypeScript first. Notice line 6 we point to a templateUrl of app.component.html. And then we've got two properties, title and story. So we're going to take a look at the story name, The Empire Strikes Back, because that's we're binding to over here, and we can go look at the app.component.html to see how that works. We can see in line 5 we've got an ngModel and that does the two way data binding. Line 7 we've got interpolation, that's going to go from the component up to our presentation and our view, and the same thing with line 10, we've got an input but we're only binding to the value property with the story name, so we're not accepting any input back. So let's prove this out. Let's go over to the two way data binding and let's remove that, notice it wiped out everything else, and we'll put in something like Jedi. Now notice when I did that it reflected in the other two boxes. Well I can't change this here because that's just a P tag, but I can change Jedi to something like Clone. And when I do that it's not reflecting up top, that's because we're not accepting the input in line 10. We don't have those parentheses. Let's go ahead and add a button to our application so we can do a click event. And in that button we'll put OK. Now when we click that button, we have to use the click event here, and we can tell it to go run some code. Well what do you want to tell it to do? We can tell it to change the story name if we really wanted to. So let's say we'll call a function called changeName. Now back into our component, we can go write a little function inside of here, and we called it changeName and we tell it to change the story's name. And for now we'll just type something in here like Jeki Rules. Now over here in the application, when I click on this button, notice it changed all the places to Jedi Rules. So we're just showing ways that we can change the events, we used all four types of binding here. We used a two way binding up top here on line 5, interpolation line 7, one way binding on line 10, and then we used an event binding on line 12.
Less Built-in Directives
The fifth concept we'll cover is now Angular 2 removes the need for many of the directives we used to know in Angular 1. For example, we had an ng-style, an ng-source, an ng-href in Angular 1. So we could set the style based upon some condition or we could set the source or href to a line or an image path. In Angular 2 we don't need any of those directives. We can simply just bind to style.visibility or to src in image or to the href inside of an anchor. So that's bye-bye to three more of those directives. In fact, there's over 40 Angular 1 built in directives that go away in Angular 2. Angular 1 we also had ng-click, ng-focus, ng-blur, ng-keyup, all the mouse ones, all those, we don't need them in Angular 2. Now we can just bind to the events on that particular element, like click, focus, blur or keyup. If you think about it, that's pretty powerful. That means that you no longer have to worry about is there a directive in Angular that supports some property or an event on the DOM. Now any event or property of the DOM, you can just bind to it.
First Look at HTML Element Property and Event Binding
Let's go back to our demo and we'll slide on down to element 7 and 8 down here for property binding, Angular 1, we'll take a quick look at that and just see an example of how we did it. So if you go look over in the index.html, we can see the way we did things with ng-model and we also see ng-style, ng-src, ng-href, over here to get the links and then also the image source. Well we don't necessarily need those. I'm going to close those out and then let's go into Angular 2 Property Binding. So when we look at this example, notice inside the app.component.html, it looks the same on the right, but now we don't need the ng-src or the ng-href or the ng-style. Instead we can just take the HTML property for style visibility, the one for src, and the one for href and bind right to them. So that's three different directives we don't need any more in Angular 2. We'll let's take a look at how events work. If we slide on down to number 9, there's Angular 1 Event Binding. We'll look at that first to remember how it used to work. So inside of the index.html, look at all those ng's we have, mouseover, mousedown, mouseleave, mouseup, oh my gosh, there's so many mouses, or is it mice? And then you've got ng dashes in here. So let's click out of there and now let's go look here for the big reveal in Angular 2 event binding. And in this one we've got an app component. Now we've got mouseover, mousedown, mouseleave, we have all the same events, but instead of the ng dashes, we just take the built in events that are in the DOM and then we wrap them with the parenthesis. So we can just mouse over the A, we see that there, I can click on it, and you can see the different events being trapped. I can also see the focus and leave and the key presses. And as you can imagine, this is pretty powerful because we now can remove all that code from Angular 1 that we didn't need any more in Angular 2 because we just bind to HTML properties and HTML events.
Services
Number 6 of our features is services. Now in Angular 1 we had factories and you might have said, well maybe instead of a factory I want to create a service or did I want a provider? But did you know there's also constants and values? There's actually five kinds of services in Angular 1. And one of the most popular Stack Overflow posts that I've read is one that says which one do I use? Well guess what? In Angular 2, do you know how many of these still exist? None. We just have a class. When we want to create a service in Angular 2 we just define a class and it can represent any of those things that we want. Let's take a look at how we do that here. In Angular 1 we would define a module that had a service or a factory or one of those other things, and then define that service. In Angular 2 it's very similar, we just write some code and instead of telling it it's a service, we just export a class and we give it a name, and by convention we give it a suffix of service. You don't have to do that, but it's a nice convention so you can recognize it in other code. But notice here it's just a class, that's it. You don't have to pick what kind of thing you want. So I can give that class state if I want to or functions like get my vehicles.
Dependency Injection
Number 7, now to go along with services, when you've got a service sometimes you want to be able to inject it into something else. For example, I have a service, I want to use it from a component. Well the term we use for that is dependency injection. So let's say we've got a component, maybe our story component, and then we want to inject something into it so we use the constructor and we tell it go get this service, my vehicle service, my story service, whatever it happens to be. And then Angular will go find that service and inject it into our component. Pretty cool. So the way this works, in Angular 1 we had something similar. We would define our service like this, there's our VehicleService, and what we're really doing is up top we're registering with Angular this dictionary, this registration of this VehicleService, there's a string name, and then it's associated with this function called VehicleService. Well in Angular 2 we still have to register with Angular. But now we do it in a different way. Notice here we've got this class, an AppModule. Now this AppModule class, remember we might have one of these in every one of our apps, is going to have a providers list and the providers are things we're providing to Angular, we're saying hey this module has a thing called VehicleService, go ahead and register it. Notice there's no magical string here on the right hand side either. So in Angular 2 we're going to register the service via the providers. And we're most commonly going to do this in the root module or the AppModule just one time. And then when somebody goes and asks for it, it'll be available. And speaking of, in Angular 1, the way we'd ask for it is maybe a VehiclesController wants it, so we tell it to inject the VehicleService, that code look familiar? We used to have to do this $inject, so we go get the strings or minification, it makes our code safe. And then in the function we refer to the VehicleService. In Angular 2, inside the constructor of the VehiclesComponent, we just say go get me the variable called VehicleService, and the important part is the type, VehicleService. So now it'll go look up with the Angular injector and say do I have something called VehicleService? Uh yes, you provided that to me earlier in that AppModule that we just looked at, so yeah you can have that. One of the cool side effects of this is there's no more magical strings so there's no more worrying about minification safe code and there's no more worrying about mistyping it.
First Look at Services and Dependency Injection
Let's take a look at our demo and slide on down to our Services and DI example. One here on number 12 is one for Angular 2 and we'll click on that. And first let's run it and make sure it works. We've got a service that's going to give us three different vehicles, let's take a look at the vehicle.service, and here it is. It's got a getVehicles method, which is going to return those three different objects. If I change the second one from Tie Fighter to something like Jedi Fighter, it should reflect in the right hand side, and there we go. Now how did this get there? Our component, here our vehicles.component, is injecting that service. So let's make some room. Here we can see that on line 13 we're injecting in this VehicleService type, right here in the right hand side. That VehicleService is going to be looked up inside the Angular injector to say hey do you have something called that? Well where's that coming from? Well just because we created this file doesn't mean it's going to exist and it's going to be able to go get it. We have to tell Angular, we have to provide it to Angular. So our AppModule, this is the root of our application, we tell it on line 11, we have a provider for VehicleService, we import it on line 6 from that ES6 module and then we provide it on line 11. Well what happens if we don't provide it? Over on the right, you notice we're not getting anything. Well let's open up the developer tools and over here let's clear that out for a moment just to look at it. We'll make a little bit of room by clicking on the File Explorer and let's put a space in the provider just to let it rerun, when it reruns we'll get the error message. Now there's a lot there. Let's scroll to the top. And you might be thinking, uh-oh error messages, I'll never be able to figure this out. Well the cool thing in Angular 2 is the error messages actually are pretty darn good. So right here the first one says the class VehiclesComponent Host, well we can figure out what that is, the VehiclesComponent, has an inline template and it says no provider for VehicleService because we don't have a provider. So that's a good hint that the component that's using it is called VehiclesComponent and somebody has to provide it, but it couldn't figure out who was going to do that. So when we go back over here and we put this back in place, it should rerun and we should see our code on the right hand side. So we declare our components in the module on line 10 and then we provide our services on line 11. Now when you get a much larger application, we can change the structure of how we provide and declare different things, and we'll talk about that later on in the course. But for now just know that declarations are for things like directives or components, and providers are for services that we're providing or registering with the application.
Your Skills Translate
We just took a look at Angular 1 compared to Angular 2 and the new things that we can do, but there's seven comparisons we did that shows us there's a lot of familiarity between Angular 1 and Angular 2. For example, we still have some concept of a module, which gives us a context of our application. And we also have components instead of controllers. We also looked at data binding and the four ways we can do it. Do you remember them? Okay, there's interpolation, which goes from the component to the DOM; there's also one way binding, we can do that with property binding with the square brackets, and that also goes from the component to the DOM; and then if we want to go within the DOM back to the component we use an event binding with the parenthesis; and then the fourth one, yeah that's the ngModule, that's our two way data binding, and we use that term that we called the football in a box, the square brackets and then inside of it the parenthesis. And who doesn't like to get rid of code? So we talked about how we removed a bunch of concepts in Angular 2 that used to exist in Angular 1, those things like ng-whatever. We had 40 of them we got rid of. We also looked at structural directives, the *ngIf and the *ngFor, and then we talked about services and how they got much simpler in Angular 2, and of course, how dependency injection evolved, and we'll talk more about these concepts again later on in the course. But that's not all that Angular 2 has. There's other things you might have heard about. We talked about services and we're going to talk more about those later, but what about filters that we had in Angular 1? Well we've got pipes in Angular 2, very similar concept. And we still use that pipe character. There's also a router in Angular 2 so we can do routing and navigation with pages, there's even eager and lazy loading, and there's some pretty cool other features there too. Of course we can get data using HTTP. We can also raise events and we can use promises if we want to or we can use things like RxJS, right with Angular. So a lot of things that you may have used in the past are also going to translate to things that you're doing in Angular 2.
Putting It all Together in Context of an App
Now that we've take a whirlwind ride through different features of Angular 2 that you're probably familiar with if you came from Angular 1, let's take a look at a larger demo that we're going to refer to at the end of each module for this course. So I'll flip back over to our demo and the very first demo at the top is 0, Angular 2 Storyline Tracker. We click on this one, it's a much larger example. It shows a lot of different things. So we'll let it load, but on the left you can already see there's a lot more folders and files than we were looking at earlier. Here we can see we've got an API folder. We have a fake API basically in memory. We're going to get a list of characters or vehicles. That's so we don't have to have a database. And then we've got admin, characters, core, dashboard, lots of different things going on in here. Now notice on the right hand side we're loading up a dashboard, so let's close the code and we can look at the application. We'll explore what we're actually going to be using. So here we've got our top characters, we've got Chewy, and Rey and Luke, all sorts of great people. We can also look at the characters list over here. And now we can look at those people and if we want we can filter them down, like type in c for C-3PO. If we want to edit somebody we click on them and then we can look in here and we can change the name, we can save it or if we want we can type in a different name like Ken and then we can press Cancel to change that. Or if we start typing in something and we try to leave the page, it'll actually ask us, do you want to cancel those changes? Yes or no? In this case I'm going to say yeah. So we're navigating around the application. We've also got vehicles in the application. Here we can see Millennium Falcon. We also have an admin section, which - oh what happened here? We click on Admin and it didn't go there. We've got a little bit of security using routing guards so we don't actually allow us to go to the Admin page, we have to log in first, and then once we log in, which we're faking in this case, it actually flips back over to our Admin page, so now we can flip around between vehicles and then back to Admin and then once we log out we'll no longer be able to get to our secured site page like Admin again. And don't worry if you change your data around, you can always click on Reset Data and that will reset all the data because it's just in memory. So let's explore what's actually happening in this application. And for that I'm going to flip back over to Visual Studio Code, but remember you can download the code too and look at it on your local drive if you just click this little cloud button in the upper right hand corner to download the whole directory, and it'll download the application as a zip file to your machine. I've already done that, so now we can open up inside of Visual Studio Code and here's all the examples. The storyline tracker is a larger app. If we look inside the app folder we can start with first looking at the app.module. Notice there's a lot more things we're declaring in this module. Here we are importing into NgModule or BrowserModule because we're going to run it with the browser. And we're telling it we're going to use HTTP and our login and we've got a lot of other things here too. It's bootstrapping our AppComponent, line 32. So let's go down a little bit to the dashboard because we knew that was the screen we were looking at. Inside the dashboard, we have this dashboard.component. Now you'll see a couple familiar things in here like an ngFor. We're looping through a list of characters and then for each one of those we're going to display this story-dashboard-button, that's our own component that we're creating. And then we're binding to it the character that we just looped through through a character property. So let's go look at that dashboard-button for a moment. That's going to be inside of here. Now we can see our dashboard-button-component, it's just a button with a lot of classes and styles on it and then we display the character name, pretty simple. So back out inside the dashboard-component, we may wonder how we got the characters. Let's look inside associated dashboard.component.ts. Here we can see we're importing a character service on line 6, well we're importing that from a different module and then down below inside of our DashboardComponent class, you can see our constructor on line 21 actually imports 4 different things, it's going to inject this router, this CharacterService, wait a minute - CharacterService, yeah that's what we were looking for. So CharacterService is being constructor injected using our dependency injection along with the Router and the ToasterService as well. So let's go take a look at that CharacterService because if we're going to inject it in this component, somebody has to provide it. We learned that earlier. So on line 6 we're going to the CharacterService in app/models. We'll just navigate using the tree for now, but we could use the editor too. So over here we've got a character.service. Now in this service, notice that we're telling it here we've got this CharacterService class, we're still not providing it, so who's providing it? Well back in our app.module, here we are providing the CharacterService on line 31. So our AppModule, which is the root of our app, is going to launch the application and it's going to provide that service, it's going to launch the series of components and when a component asks for, hey can you inject CharacterizedService, kind of like the dashboard component is doing here on line 23, it's going to say yep I have that on my injector and I'm going to give you that. We also saw some editing in the application. So what if we went down and looked at the characters themselves and then we looked inside of the character-list we could see a component, which is looping through again a list of characters, and then the character buttons in there are going to let me click on them, but what about actually editing the character like under a character.component? Here we can see a more complex component, which has got a bunch of buttons on it like save or click, but it's also got our ngModel. Notice here on line 12 we have an ngModel on an input tag, and there's our input. So that way we could actually enter a different name in if we want to and then we've got our click events to allow saving and canceling and deleting. Now the idea of this is just to show you that we've got a larger application that has a little bit of everything of Angular, just so you can see it all in one place. Throughout this course we're going to show little pieces of examples, small point examples, which will show all the different concepts on their own, isolated, and that'll make it easier to kind of grock what's happening with that little piece. For example, we'll look at services and just look at a service and how that works. But then at the end of the module we're going to take a look at this storyline tracker app and see how it all fits into the bigger picture. So hopefully by showing it in isolation and then showing it in a larger app, we can kind of learn how this works together. And remember, all this code is yours as well, you can grab it off Plunker or go to the GitHub page.
Angular 2 Resources
There's some great nuggets up on the Angular.io website that could really help you out. First they've got an Angular cheat sheet, which they have one for each language type. This one here is a snippet of the one for TypeScript. So if you're looking for a little bit of syntax here or there, this is a great one stop shop. They also have a tutorial called the Tour of Heroes, which will walk you step by step through building an application where the application is a list of heroes and we get to walk through creating components and services and go through all the basics of Angular. Here's the angular.io website and if we click up on Docs, we'll see over here on the left there's a developer guide and there's a tutorial. Let's click on Developer Guides and the first thing under there is the cheat sheet. If we click on that we can see down here it shows us how we can boostrap our templating syntax, it also shows all the built-in directives we have. Notice how short that list is. You definitely want to bookmark this. If we go over to the tutorial, you can see the Tour of Heroes, which walks you through the different steps that are there, and they're adding steps all the time. Of course there's also a 5 minute quickstart and some testing guides and API docs. In this chapter we saw how we can leverage our Angular 1 skills for Angular 2. While we can choose a bunch of different languages, TypeScript is the one we used for this course and it's the one I prefer because it gives me the most tooling support as well. There were over 40 directives in Angular 1 which no longer exist in Angular 2 because we combined any HTML element property or event. We still have all the great things that we learned in Angular 1 that map over to Angular 2, like our services, controllers are not components, we still have templates, we have data binding. So while there are syntax changes and under the covers things operate differently, the way we actually interact with Angular 2 is very similar to what we do with Angular 1, all those concepts are still there. This chapter was an overview of a lot of those concepts, but we'll take a deeper look at each one of those throughout the rest of this course.
Angular 2 Essentials: Components, Templates, Modules, and Metadata
Angular 2 Essentials
Every framework has a short list of critical players, players that the framework cannot exist without. In Angular those are components, modules, and templates. In this module we're going to introduce the essential aspects of Angular 2 applications. We're going to see how ngModules or Angular modules help organize an app. We'll also see how a component contains the application logic, the template represents the interaction with the user, and a series of component and template combinations are organized in modules. We assemble our application for modules, which exports something of value, such as a component. When we import and expert, we're using ES Modules for ECMAScript. We organize our application using Angular Modules, also known as ngModules. And a component contains the application logic that controls a region of the user interface through a template, which tells Angular how to render the component on the screen. Then we use metadata to tell Angular 2 about the objects we build, such as where to find a component's template, what directives a component will use, and what services and inputs are required by the component. We'll learn how to use these players in an Angular 2 application using good separation patterns to create reusable components and modules.
ES Modules
We'll begin by talking about ES Modules or ECMAScript modules. ES Modules are often referred to simply just as modules, you hear about them all the time in the JavaScript world. So what do they do? Well we use those to assemble our application. We can think of these as separate files that we use to contain different things, like services or components or shared values. Each file is a module and it exports the things that we want to use in other files, and those other files can import things from other files. So we import and export from different files or modules. Here's an example. We might have a vehicle service in a TypeScript file and maybe it's exporting an interface like a Vehicle or a class, like a VehicleService. That export keyword is what we're going to use to help show that this is the asset we're going to export from this module. And then when we want to use that somewhere else, maybe in a vehicle.component TypeScript file, we can import that ES Module by using the import statement. So here we can say okay import a component from an angular/core, which is part of Angular, or we can import the Vehicle and that VehicleService we just saw from that VehicleService file, and when we do this, we're actually using a form of destructuring. And that's what those little curly braces mean, we're saying go grab, reach inside of that VehicleService file, that module, and pull out the Vehicle and the VehicleService, and by using these modules we create a dependency chain that we can walk throughout our application to see which files are depending upon others. And that's ES Modules in a nutshell.
Angular Modules
One other reason I like to refer to ES Modules in the formal ES Modules is because there's another thing called Angular Modules. Now it's a good thing and a bad thing that it's named very similar. These are very specific to Angular and they do something that ES Modules don't do for us, they actually help us organize our application into cohesive blocks of related functionality and it's really going to become important to use these when we want to do things like lazy loading, which we'll learn later in this course. So how do they work? These Angular Modules, also known as NgModules, you can think of them like a container. Now in that container we might have multiple components, in our bigger application that we're showing throughout the course, we might have characters and vehicles in our stories, and maybe inside that same module we also have a service to go get the data for those things. So a module can contain components and services and directives and pipes, a lot of things we're going to learn about in this course, and usually we're going to put like minded things inside the same module. So we might have a module for all of our character stuff and maybe another module for our vehicles and maybe we have a module for an admin area. We'll talk about how we can split our app as it grows into multiple modules later. But you can think of these as raviolis, each module is like a ravioli, it contains certain things, maybe some meat, maybe some cheese, maybe some spinach too. And like raviolis, everything that we need for our feature area is inside that module. This makes it easy to identify, test, and extract for reuse when needed. So how do you know a module when you see it? An Angular module that is? Well an Angular Module is going to be a class that's decorated with this @NgModule decorator. Simple. The NgModule decorator takes a metadata object that tells Angular how to compile and run the module code. Let's review the roles that NgModules can do. First they can import other Angular Modules. They also help identify components, pipes, and directives that we use inside the module. And you can think of an NgModule as a feature area, so we can use that to define the feature and then export those features so other modules can use them. And these Angular Modules can also provide services to the Angular's injector. And we can also have these Angular Modules eagerly or lazily loaded. We're going to talk more about providers, injectors, and lazy loading later on in this course. For now we just need to have a glimpse of what an Angular Module does because we're going to be seeing it quite a bit. Where might you say? Right here. We're always going to have one module in our application at least, and that's going to be the Root Angular Module. So let's identify what these different parts are. This NgModule is going to identify the module's own components, its directives, its pipes and it's going to make some of them public so external components can use them too. So right here we can see that we've got importing modules that we depend upon, things like FormsModule or the BrowserModule because we want to run it in a browser. We can also declare those things that we're going to use inside of our module, like our VehiclesComponent, and here we're saying okay our VehiclesComponent might need a VehicleService so other things in this module can use it too, so there it is in the providers. And the root module has a special setup for bootstrap, this says where am I starting? We saw in there briefly, earlier in the course, where we bootstrapped the component in our AppModule. So every application starts with a root module and then we just identify the things that we're going to use. And of course, we define the root NgModule, and we're going to call it @module by convention, right here. And it's just a class. Now it's really, really important to remember that every application is going to begin with one Angular Module. And as an app grows, it can have many NgModules. Our app is small now, but let's start with just this one and we'll revisit Angular Modules later when it's time to expand the application.
Components
Now that we've taken a look at Angular Modules, we have to look at the pieces that go on the screen or our components. So a component contains part of the application logic that controls the region of the user interface that we call a view. Effectively when we want to put something on the screen, we want to put some HTML up there and have some logic that goes behind it. Those two things together make up our components. Let's get a better feel for how we write these components by looking at the anatomy of one. First we'll start off by importing from different ES Modules. So we're going to import the component out of the angular/core ES Module. Why are we doing that? Because we're going to use that inside of our code for that decorator, that's that metadata that's going to describe our component. We might also import other things like a vehicle from one of our services, our own ES Modules. Now that @Component decorator is decorating something, right? But where it is? It's right here. It's just a class and we define it and we name it what we want. By convention we always put the suffix of component on it so we can identify it, and that @Component identifies that this class right here is a component for Angular. And notice that we also set up a selector and a template URL, the template URL points to where the HTML in our template is for this component. And the selector is how we identify it in the HTML when we use it. And they way we assemble our application is we use multiple components to do this. We'll start off with one Root App Component, that defines the area where our application will live. And then maybe we have something like a header component that goes in there or a navigation for a menu or a footer. And then on the right hand side maybe we want some content. This is pretty common. All of these could be different components that when composed together live inside the App Component. So we can nest these. But we need a starting component too, right? So once you uncover all of these we have to get back to what's the starting point, and that's going to be our App Component. But how do we start it? Well that's where bootstrapping comes in. And by convention we create a main.ts file and we're going to bootstrap it with this one component to kick things off. It's our entry point, our starting place. Everybody needs a place to start, right? And this file is very, very small. We define the platform we want to run on, in this case we'll do the browser, and we'll import that ES Module from Angular, and then we import our NgModule, that's that first thing we created, remember that root module, this AppModule that's going to hold the application, and we put these two things together and we bootstrap the module and off we go. So how does all this compare from Angular 1 to Angular 2? Well the syntax is obviously different, but the concepts aren't so different. In Angular 1 we might have had a controller and a template, our logic and our HTML. And a router might have matched that controller to the template. We could also have done this by telling the template, hey this is your controller and it's called this. In Angular 2 we also have something, it's not called controller, it's called a component, and it identifies its own template. Remember that template URL setting that we had inside the AppComponent decorator. So we still have those same two things, they're just associated a little bit differently. Let's take a look at how all this fits together. Let's say we've got a scenario where we want to put a character component together to show a character on the screen. So first we might create character.component.ts for our logic and maybe that logic includes identifying the character component, which we aptly name, and then also setting a property like name to Han Solo. Now notice we have a templateUrl that points to a character.component.html. Well where's that? It's right here. That character.component.html is what is going to be rendered on the screen. In this case we're going to render the name using these curly braces, a very familiar syntax to Angular 1 developers and to developers with other technologies too like jQuery even. Finally, if we want to put this on the screen how do we do that? We just defined the component, but how do we get it to show up somewhere? Well there maybe we've it in our index.html, we could say story-character, like this with an element tag. Now that story-character has to refer to something, and that's going to be the story component we created or the character component up top. This is where the component is going to be placed. So let's take a look at this and how they kind of link together. That story-character element points to the selector that we identified in the component's ts file, the TypeScript file. And then the templateUrl points to the HTML file. Now that we've broken this down, let's go ahead and take a look at a demo of how we put components together.
Defining a Component
Let's launch our demonstration application again right here at this URL, angular2-first-look.azurewebsites.net, and let's slide on down to the simple component demo down here at number 13, Angular 2 Components, and we'll launch this. And up we've got a little component and it's going to show My name is Han Solo. Well how does this all work? Let's walk how it actually gets instructed on the page. First let's look at the index.html. Here we can see that the index.html has on it a my-character element right here on line 11. Well that my-character, what is it? It's not really an element that HTML knows about, it's something that we defined and we can see it's right over here, it's this character.component with the HTML template and then our TypeScript file. But how does this page know about it? Well we're loading Angular, but more importantly here, we're actually telling it to import this main file. And this main file is going to launch main.ts. This is our bootstrapping right here. Again, we're telling it we're going to launch inside the browser and our default root module is going to be AppModule, that's our NgModule that we defined. So where is that? That's our app.module.ts, again using naming conventions to help us find the files. Here we can see that we've got this NgModule that we import from the ES Module for Angular Core, and then we use that to create the decorator on line 6. The decorator is from line 6 to 10, and we're passing in the parameters for what are you importing? I'm going to import the BrowserModule so I can use things for the browser. And then I'm going to declare the components on my page, things like CharacterComponent. We'll take a look at that in a moment and then, of course, we only have one component so we're going to bootstrap that single component that we've got, this CharacterComponent. And then in the CharacterComponent, we've got the class on line 8, which defines the property Han Solo. So that's what's showing up on the page and then our template is pointing at the templateUrl here of character.component.html. We say hey My name is name, and that name matches the property right here for Han Solo. Well let's say we break this a little bit. Let's open up the developer tools so we can see some errors as they happen, and we'll resize it. Go ahead and follow along if you'd like. I'm going to clear out the errors that might be there right now, and turn off the phone mode, and we'll shrink up the different windows to make it easier to see. Now right now everything's working perfectly. What if I went inside of my index.html and instead of referring to my-character, make that go away, we've got our my-character here and let's call it my-character-foo and we'll make them match. Now notice on the right we're getting and error message and what's that error message saying? Well the error message is probably going to tell us, I don't know what my-character is, it didn't match any elements in this case. Let's go ahead and clear this out again and we'll rerun it by clicking on this refresh live preview, just to make sure we're looking at the right error message. Scroll up to the top and it's telling you - I can't find anything called my-character. Well this is a little odd right? We're referring to my-character-foo, which is effectively getting ignored, and then over here we've defined another element with a selector of my-character. Well let's say we go ahead and name that my-character-foo now, what happens? It actually found it and now it's launching it. So that selector right here on line 5, so it's matching what's in the index.html, and don't worry about actually fixing this code because when you re-launch it back from the demo, it's going to launch in the initial state. So we can do whatever we want here and just message around. And I'm going to clear out the console errors again. Now let's go ahead and say that inside of our component we've got Han Solo, but we don't want to say name, we want to do first name and last name. So what we could do is go inside of our template right here, and instead of doing this we can do firstname like that, my name is firstname, then we could do lastname. Now notice, nothing's actually going to show up on the right hand side. There's no errors because it just can't find those properties. So now we can come over here and inside of our object instead of doing name we could just do, although that's going to be firstname and we'll make that first name Han, and we'll do lastname, and what's the last name going to be? Solo. And now it should show up because we've matched those properties. So we're seeing some initial states of doing interpolation onto our component using firstname and lastname. Now we stressed something else a little bit earlier too and that was the importance of importing and exporting ES Modules. Notice our CharactersComponent is being exported, what happens if we don't export that? Let's find out. I love breaking code, don't you? Okay, we just broke the application. That's because now we've got a CharacterComponent that is no longer exposed outside of this ES Module. Down here we see an error, right at the bottom on the bottom right, it's saying we've got an uncaught in promise error, it looks kind of scary. There's an unexpected value undefined declared by the module AppModule. We keep clicking through there and we see a lot of information about this here. What's actually happening is there's somebody who's just unknown. What's happening, if we go over to the AppModule itself, remember, is in here, and I'll click off on the preview, we can see that we were importing CharacterComponent from character.component. Well, you can only import an ES Module if it's actually exported, and remember we just unexported it over here. So once we put the export back in place and then we show the live preview, the application should run again. So the rule of thumb is anytime you're going to import or export something, make sure that you actually have the export on that class because otherwise you will not be able to import it somewhere else. Feel free to play around with these samples as you go along throughout the course so you can get a good understanding of how these components work.
Templates
Components contain logic, but we still need something to render the page, that's where templates come in. HTML is great for rending pages. Sometimes we just need to give it a little bit of help to know what data to render in a list or maybe how to handle a click event. Together our HTML with data binding expressions and directives tell Angular how to render the component. Let's take a look. We've already seen some templates, but let's examine them a little closer. Here we can see an ngFor directive. This ngFor is looping through a list of characters and then it's going to display the character's name. We can using dotting to go into objects like this, character.name, and then perhaps when we select one of those names, we can set up some logic so we show the selected character down below. For example, if a selector character property exists on the model, then we could go ahead and show this my-character component. That's something we created. So here we're looking at looping through different things with a directive, ngFor, using interpolation to display it, and then also doing nested components. Our HTML is our templates and we use these things as needed, including template binding syntax. And remember we talked about how we connect the component to the template, we have that component and we have to associated with the template. We do that through either the template property or our templateUrl property. The template property allows us to inline a template and here we're using back ticks, again, that's not a quote, that's back tick, inside of the template property there. Those back ticks let us do multiline template strings so we can actually put a little bit of HTML there. These are awfully useful for putting in short little templates, so that becomes the template string. Now most often we're going to use a linked template and that's going to be using the templateUrl property. So we do that through setting templateUrl, we associate it to a file, which by convention we do vehicles.component.html to associate the vehicles.component.ts. So components have templates right, and they can use other components too. So here's a high level overview of how that could work. First we have our root component, that might be that app component we talked about where everything else lives inside of it, like our footer, our header, our navigation. Inside of there we might have other components, like Child Component A with its own template. Maybe we also have another component too, maybe this is like the footer and the header. And then each of those components might have their own child components as well with their own templates. We're effectively creating a component tree out of our application using these templates. Now let's take a closer look at how we can use these templates.
Nested Components
Let's go explore some templates inside of nested components in example number 14. We'll click on that sample and when it launches up we can see we've got various different components. Now before we only had one component, now we've got a couple. Here we've got our app.module, which is now declaring two components, Character and CharacterList right here on lines 12 and 13. Now the CharacterList, when we select one of these guys, shows that we select Luke Skywalker here. Or we can show that we selected Rey. We're bootstrapping CharacterList, which means we're going to show that first, so here we've got the list of components and we're going to show different characters, those are our models. And we also have a selected character right here. But let's take a look at the template. Notice that this character-list-components template has a my-character inside of it. So first we're looping through those characters and when we click on one of them, we're using an event binding to call the selected character, that sets a property called selectedCharacter, and that's going to pass it in here through an input property to my-character component. Well this my-character on line 7 is actually pointing down to the template here for my-character component. We can see that as a selector name, my-character. And then that renders out, we selected character so and so, right here in the h3. Now we can actually repeat this if we wanted to, so these components are reusable. We could effectively have a couple of these guys. Let's go ahead and put four of them on the page, it should rerender over here and we select, we can see that we really selected Luke Skywalker. So as you can see, we can build up a component tree using these templates and nesting our components and then using input parameters to pass values in. We'll learn more about inputs soon.
Metadata
There really are three parts that make a component work, there's the component code, then there's also the component template, but there's also the third part, the metadata, the lesser talked about part. It's always there, but we don't pay that much attention to it. The metadata is what goes inside those decorators. We're going to use the metadata to tell things to Angular about how to find the component's template, so that's one thing we use it for like the template URL. So we might have a template and then we've got a component, and then that metadata is that glue that kind of links those two things together, and it gives Angular information about that component, so it can operate better. We're going to declare our components, our directives, and our pipes, which we'll learn more about later, in an Angular Module or an NgModule. So let's talk about where that metadata goes. Once again we have metadata for our NgModule and that's the imports declarations in bootstrap for this root AppModule. First we're going to do BrowserModule as an import and BrowserModule includes the CommonModule. These are two modules that come with Angular. These are NgModules that they expose and give to us and the CommonModule includes things like that ngFor that we looked at earlier. And they're making it easy for us by saying okay if you're in the browser, you might want to use those so we're going to give you the CommonModule when you ask for the BrowserModule, so we don't have to list both of them, we're just getting them both for free by saying give me the BrowserModule. So things like ngFor and ngClass and ngIf are going to be in that CommonModule when we get them. But we do have to tell Angular about the things that we create. What about this CharacterComponent and CharacterList? We need to declare those and they go inside the metadata for ngModule. So we use the metadata to declare to Angular, I'm using CharacterComponent and CharacterListComponent, and then the ngModule knows about them and it tells Angular.
Examining the Component Decorator
Let's take a deeper look at the metadata for our component now. We first looked at the metadata for the ngModule, but in a component such as this CharacterComponent here, we have a decorator, @Component, right at the top, and this decorates our CharactersComponent, so the at sign is going to be indicating that it's a decorator and it's going to provide metadata that describes the component right here. And the component definition, it's just a class and it's going to be something that controls an area on the screen, a patch of real estate if you will, and we call that the view. Now there's other things in here too like templates and styles. The templateUrl tells it where to find that HTML in our template syntax and the style URL is plural because it can be an array of different CSS files or SASS or something else you might want to use. And those will all be associated with this component. Now we could also provide a service to this particular component as well. In this case we're saying this service called characterService will be registered with this components injector, we can actually have an injector for each component, but we're only going to go this once because we don't have providers all over the place for the same service. We'll learn more about providers and how to set them up in your application in a good design later on in the course, but a general rule of thumb is we want to prefer registering our providers in Angular Modules, the NgModules, as opposed to registering them in components. So what else is in here? Well we can also see that we can inject a service into another object through constructor injection. So as long as the characterService has been provided somewhere in our application that this component can get to it, and that could be right here, up above in the providers, or it could be in a provider of one of the modules, the ngModules that we have, then we can get to it. Now we also have output and input parameters in here. Here's an output parameter that we can use and that's going to be an output decorator decorating this changed member, and that could use an event and then we could emit that event down here. Or we can also use input decorators to define a member, like this storyId, to pass values into the component. Of course, any class could have properties too, things like Characters or the selectedCharacter. And by default they're public with TypeScript, so those are the things that can be accessed in the template. And of course we can have actions too, just functions that we can expose and bind to the template to handle events like maybe clicking or selecting onto a character. And as we saw here, some of the metadata is decorating the class itself and then other metadata, like the output and input, are decorating a member.
Input and Output Decorators
We just saw that we had input and output decorators that we can use inside of our component. Now they're going to allow us to identify properties that we can have things flow in or flow out of a component to communicate between a parent and child component. The way we set this up is we've got a component here and we might identify an output property, like changed, and maybe we fire off an event using something like an EventEmitter, and then we can emit that output using this.changed, our member, .emit, and then we can pass information like the selectedCharacter. So this way you might imagine this character's component could tell some parent component, hey this event fired, the changed event, and here's the information about it. It changed this selectedCharacter. So how might this interact with a parent component? A parent component might be defined like this down below where it's got this story-characters, maybe that's the guy up top, and we're passing in storyId as an input and right now we're just passing in the number 7, but it could be a bound property as well, and it's using that property and then there's a changed event that it's binding to. So the changed event is binding to some function and that function will grab the value out of this $event. So we might have a parent component there and it's got its own template and that template refers to a child component. So we use a property binding to get into that child component in the template and then we use an event binding to get back out. Make sense? Well that's okay, we're going to take a look at a demo now using our samples of component input and output to show how this flow works.
Component Communication with Input and Output
We'll scroll down in our demo to the input and output component sample number 15 and we'll open that guy up. And I'm going to reduce the font here a little bit, just shrink the size using this little minus sign so we can see the entire list, and the reason for that is that I want to show you when we click on an item here, Luke Skywalker, we can see the selector down below, or BB8 or Commander Snoke. I can put that back up. If we look inside of our characters.component, we can see that we've got a selectedCharacter, now we want to pass that in to our other component, our character.component, singular, so here in our template we've got that list and then we've got story-character, this is what's going to happen, we're going to take a character input, we're using binding, we have to do the square brackets around it to tell it we're doing a binding, and we're going to pass in the selectedCharacter. so the selectedCharacter right here, that's going to be the property inside of our characters.component TypeScript, right there on line 16. So line 16 maps over and it gets set when somebody clicks on something up top. Okay let's repeat that because it's important, inside this list we loop through the characters and then on this div when we click on any of those elements, we call selectedCharacter, that's the character from the loop. So now we call select, which is in this component, and there's our function down on line 25. We select the character and we set that up as a property and then we fire off a changed.emit, so if somebody's listening we can tell it, hey we had a changed event and we'll pass the character to them. There's the output. And then the selectedCharacter on line 26, if we go back to our template, is then bound to the story-character component through an input property called Character. Okay so that Character property is not on this component, it's on the CharacterComponent inside of here. Notice we have to decorate that with input. So what happens if we remove input here? Let's run this again by hitting the triangle, everything works, we'll select somebody like Chewbacca, scroll down there he is, but what happens if we don't have this input down here? Now it's going to rerender the page and the application should load right? Okay, so we've got the guy over here and he's not loading. Let's look at the error messages again. We'll remove everything from the console and we'll rerun. Now let's see what kind of errors Angular gives us to give us an idea what's going on. It says there's a template parsing error, which is a pretty good hint that you're doing something in the template that it doesn't like, right? So over here we happen to know that it's because we removed the input, but it's because this guy over here is referring to a property that really doesn't exist inside the other component. Well let's look and see what it tells us more. Here in the template errors, if we click on this, it says I cannot bind to the character since it isn't a known property of story-character. That's pretty darn good actually, isn't it? It's saying there's a story-character here and you're talking about a character property that doesn't exist. Not too bad. Alright so now we can go back over here and we can stick in that CharacterComponent's input and that's our decorator, it's a property decorator in this case, and don't forget the parenthesis, it won't work without them. If you do this, the application is not going to load because these decorators are actually functions. Now it's easy to remember them up here for component because you have to pass something in, with input you could pass things in, but we don't have to. But we still need to make sure we call it like any function. So play around with this example, that's what they're here for after all, and try to do some different things with input and outputs.
Parent to Child Communication with ViewChild
We just showed how we can pass input properties into a component and then also how we can get things out of a component through an output. But what if we need to access another member from a parent to a child, for example, the parent needs to call the child's function. Let's say that we've got a character list component, that's our parent, and we need to access maybe a child component, like a FilterComponent, to filter some data. Maybe we want to call the filters.clear function and that's over here on the left. To do that we need a little bit of help and that's where the viewChild decorator comes in. that viewChild decorator is going to let us call the child component's function. So this grabs the child right here and says, okay we've got a reference to it and now you can call filter.clear right there. Let's take a look at this with input and output parameters and also the viewChild inside of our storyline tracker demo application. We flip back over to our app and here we can launch the sample. It'll take a moment to load because there's quite a bit in there, and then inside the application let's go down into the vehicles and in the vehicles we'll look at the vehicle-list. So in here we've got our CSS, our HTML, and our TypeScript. Now before we look at the code, let's go look at our vehicles and inside the vehicles we've got a filter. That's what we're going to look at. So when I click on that I could type in something like falcon and I only get the falcon right here. Or I could change that and type in something like destroyer and I get the destroyers. Great. Well let's say I typed in falcon and then after I reset the data, what I want to have happen is new data is coming in, I want to reset the filter too. So I'll say yes to clear the data out and it should clear the filter too when the data comes in, otherwise I might have a wrong filter on here and it might be filtering the data that came back. Well let's close this window there and instead look at just the vehicle-list.component. Inside the HTML, the middle file, we can see here that we've got story-filter-text on line 6. We're not passing anything into the filter, but we are listening for when it changes, so whenever that filter changes, it's going to fire an event and we're going to do something about it. Well if we want to find out where that filter is, we go back into our TypeScript file and we can see here there's a ViewChild on line 20 of that FilterTextComponent, but then up top we're importing the FilterTextComponent from a shared filter-text folder, that's that ES6 module. So let's go look at the shared filter-text folder and here we can see we've got a component file and inside of it we've got an output, it's going to tell us when it's changed, it'll emit that on line 26, and then it's also got a clear function, that's on line 19. We might want to call that. So we're going to reach in through the ViewChild to get to that clear function and we'll use the output property so we can use the changed event and bind to it. Let's show how's that done back in the vehicle-list.component. The HTML just lists it here, that's going to be on the page, and because that's there somebody's got to declare it, right? Well that might be declared somewhere else inside of our application in one of our NgModules. And then the vehicle-list.component can use him, so here we're grabbing it by getting the ViewChild and saying there's our filterComponent, and then down on line 35 we're clearing out the filterComponent whenever we get new data. So what happens if we don't have this ViewChild up here? Well if we do that and we run the application, the application will try to load, and we'll make a little room to show more what's going on, and now when the application loads up it's not going to be able to clear out the data. So if you go over to vehicles and then we go ahead and try to use that filter, we'll type something in here, like fal, notice that we don't have what we really want. If we look over at the error messages, it's saying it cannot read the property clear of undefined. Well we know what that is because we just commented out the ViewChild. But it's trying to access something that it can't get to. So now we can go back and put them in and everything will work again. So that's why the ViewChild is important, it's a way to reach in and then call a function inside of a child component if we want to and then we can listen for that changed event. So here it was our filters, and we'll clear this out for a moment, on line 27 we're getting a list of the filteredVehicles. Great, and then we've got this filterChanged event, well what's that guy doing? This is for our code we're getting vehicles and we're also just setting up our subscriptions to listen to when our data changes, but where is that change coming in? Well if you go back to our component here inside of vehicles, vehicle-list, and then the HTML, we can see that we have a changed event, which we're listening to and we're going to call filterChanged, and that's where that other function comes into place, filterChanged right there on line 26. So our function here inside the vehicleComponent, that's our parent, has something that we're binding to inside of that filterTextComponent, so we listen to that other event and then we fire our own event here and run our own custom code. And that other guy, the filterTextComponent is going to give us the filter text string so we can go ahead and do what we want to do. And feel free to play around with the ViewChild or the input and the outputs again in the storyline tracker, or maybe add your own component.
Summary
We walked through several examples of how we set up components, talked to their templates and defined the metadata in this module. And we also looked at the storyline tracker, which puts it all together for us. Now remember, when we create modules in Angular 2, they're not like Angular 1, we're using ones that are defined as ES6 modules and they basically just encapsulate everything that's in that file for us so then we can export those and use them other places, for example we might export a component, which is going to control part of a page for us. And component is going to be the most often used piece of Angular that we create to define certain sections of the screen. And each of those will have some kind of a template, which is basically HTML plus a little bit of extra, that's going to help Angular render that page, and then we'll use the metadata to help Angular know more information about that component. This module was entirely about components and all the things that go with them and we took a little glimpse ahead at some things we'll be using, like interpolation and some data binding, and in the next chapter we'll learn more about those topics.
Displaying Data: Data Binding, Directives, and Pipes
Displaying Data
One of the most appreciated features of Angular 1 is data binding. We'll all glad to hear that these concepts are still present in Angular 2, albeit in a new syntax. We've already seen a few examples of data binding and built in directives, so in this chapter we'll learn more about how to take advantage of these features. We'll learn how to use one and two way data binding to help coordinate communication between a component and its template. When Angular renders templates, it transforms a DOM according to instructions from directives. We'll discuss the built in directives in Angular 2 and show how to format data in templates using pipes.
Data Binding
Let's explore some data binding. We'll use data binding to help coordinate communication between a component and its template, and that means that we can send property values from the component up into the template to display them, and then also we can take the values that a user types into the template and send them back down to a component. Let's look at that interaction just a little bit more. So in the DOM, that's where our template lives, and then we also have a component, that's where our code is. First we may use interpolation to send data from the component up to the DOM, that's those double curly braces. So we put an expression in there and then it renders in the template. We can also bind to properties, and really interpolation is just a short hand syntax which gets turned into a one way binding to a property. There we might say, okay we have the style.color and we're going to set that to an expression to set it to red. Both of these are one way communication from the component up to the template. Now let's say a user wants to click a button or do some other action inside of the template and communicate back to the component and we can take some action on it. That's where we use an event binding. So we'll bind to an event and there we use parenthesis around the name of that event and then we call a statement that lives in the component. So notice property bindings use square brackets and event bindings use the parenthesis. It's important to see that all the communication is in a single direction. We're either going from the component to the template or we're going from the template back to the component as a unidirectional data flow. But what if we need two way binding? Well there's a short hand syntax that we can use to do that. It's actually a combination of the property and the event bindings. There's a special built in directive that Angular 2 gives us called ngModel, which is very familiar to you if you've done Angular 1, it's the same name just operates a little differently. And it takes a value from the component, displays it in the template, and also accepts any input values that are in that binding to go back to the component. And to do that we use the square brackets and then inside of that the parenthesis wrapped around ngModel. Remember that thing in Angular 1 called the digest cycle? Well that was the basis of doing data binding for Angular 1. In Angular 2, the change detection is based upon unidirectional data flow. Unicycle root beer floats, what's that? Well unidirectional data flow means the data flows in a single direction, for example from a template to a component or from a component to a template. This makes it easier for the framework and for developers to know the state of the data at any one time. In contrast, Angular 1 went up and down the chain, for example, up the scope to the root scope and then back down. The largest beneficiary of this is improved performance. So what does it do for us? Do you remember when in Angular 1 you need to call $apply when you use a jQuery plugin? Well that's not going to happen anymore in Angular 2. We have much easier widget integration. In fact, there is no more $apply and there are no more repeated digest cycles, no more error messages related to it, and then all those watches we had, no more watchers either, which also means there's no more dealing with the performance issues related to the digest cycle and watcher limits. And this unidirectional data flow is the basis for the data binding in Angular 2.
Interpolation
When you just need to take a value, bind it to the template and display it, interpolation is a great way to go. Interpolation is one way in to the template. So let's say we've got a template here and we want to display the vehicle name right here in the h3, we can do that. We're going to evaluate the expression in those double curly braces. So we have an object called vehicle and it's got a property called name. So we must have that vehicle object with the property name in our component. All we have to do is wrap an expression inside of the double curly braces. We can also use this for an image source or an href. Let's take a look at some examples and how we use interpolation in an app. We'll flip over to our demo and we'll slide on down to number 16, Data Binding and Directives. We're going to be using the sample throughout this module. First we'll take a look at what we get out of the gate. It's basically bare bones in an application with not much there. We're going to fill this in throughout this module here. And if you want to see what you're going to get, you can switch over to the solution. Here we can see Boba Fett and we've got some data binding and some colors, like we can type in red and that turns red down there, or if you hover over it, it turns back to a different color. Well let's take a look at the starter and we'll flip over to the character.component inside the app folder. This character.component here is actually showing us that we've got a character in it called Boba Fett. So we slide on down to line 29, we can see there's a character called Boba Fett. Well nothing's actually showing up on this page because this is a starter, so if we go over to the character.component.html, which is the templateUrl for it from line 14, then we can come up to the top and we can type in the details. Maybe we want to put Boba Fett's name here. So we know we have a character object, so we can type that in right there, and then we can take that character and use the character's name after that. So now we should be able to see Boba Fett details over on the right hand side. Pretty cool. Well what if we had an object that was missing a property or a missing object? Let's say we had an object here called vehicle and there is no object called that in this particular model, and then we try to put name like that there. So we could say here is vehicle.name, like that. What's going to happen? In this case there is no vehicle name, and in fact it's kind of broken everything on the right hand side. It's going to tell us if we look at the developer tools that we have an undefined property name. Well why is that? Well we have no vehicle. But there's a cool little thing we can do if we're not sure we have an object or not and we don't want to break everything, like we could wrap this with an ngIf and other things we're going to learn, but let's use this cool operator called the Elvis operator. We put that right there after the vehicle and we're saying, hey if there's no vehicle just ignore everything after this. In that case we're still seeing here is and then the bang, but we're not going to break the rest of the page. So that's just a neat little tip that you can use when you're using dotting to do this interpolation. Okay let's get rid of that though because we don't want that here. Now that we've learned how to do that and we put the character.name in, let's get the character link and the character image URL and actually show them up. So down here in line 14, we'll go ahead and put in the character.link and then we'll go ahead and put the source in as the imageUrl. Now we have to spell them right of course, and there we go. So once we do this we should be able to see the href and the source. Now we can see the images right here, that's great, but what about the link? When I hover over it, you can see in the bottom left hand corner it says angular.io, that happens to be the link. And we can right click on that and say open in a new tab and it should open that up to angular.io. Great. If you ever run into trouble too, with interpolation there's a really neat trick you can do. Let's go back up to the top, let's say we didn't know what all those properties were on character. Well we can go look or we can kind of cheat. We can use this pipe called JSON and by doing this we can actually print it out on the screen. So this will show us the entire JSON object for character. If you want to format it, there's another neat little trick we can do. So we can do pre, like that, and let's copy that and put it inside the pre and now it'll actually format the JSON out for us. Obviously we don't want to do this and leave it in for production, but for quick debugging that's pretty darn easy. So here we can see interpolation inside of our application.
Property Binding
In chapter 2 we talked about how we used to need things like ngHref and ngSource and a bunch of other built in directives in Angular 1 to do property binding. In Angular 2 we don't need any of those, we just need to take the property for the HTML element and we put the square brackets around it, and that way we can bind to it. It's key to remember, we're setting the properties of the DOM elements, not attributes. Attributes initialize DOM properties and then they're done. So how do we set up data binding communication? Well we're going to start with a template, right, our HTML, and then we're going to have a component, that's going to be our TypeScript or JavaScript. Now we're going to use that metadata to communicate between the two so the component knows where that template is, but we want to take a property and bind it up into the template, maybe take a character's name like we just did with interpolation. And we want to do event bindings we can go back down to the component. Right now we're going to concentrate on the property binding side. It's really important to remember that we're setting properties of the DOM elements, not attributes. We'll see some examples of where this is important when we get to aria. Alright, how do we do one way binding? Well we looked at interpolation before, which actually is just a short hand for doing property binding, for example the text content property. But we can take any property and that'll be our target inside the HTML, and we put the square brackets around it and then we set it to an expression, that expression will be evaluated and then the value will go from the component into the template. Now that is valid HTML, but let's say you really wanted to use with the square brackets, you can do bind-target and set it to an expression and get the same results. That's just long hand. This is always one way unidirectional from the component up to the template. And then once we get to the template, we set it to the binding target. So let's see some code. Just like interpolation, we're doing one way in to the template with property binding, and here's three different examples. First we're going to set a property to an expression and that's going to bind to the element a component or a directive. So the top one here is an element. We've got an image element and it's got a source property. We want to set that to something like the vehicle.imageUrl. The next example is of a component. We might have a vehicle-detail component and it might expose a property, like an input property, and that might be vehicle, so we could bind to that and pass in a selected or currentVehicle. Finally we have a directive. We'll look more at ngClass a little later, that comes with Angular 2. It's a directive that they've built for us, which we can bind to and then it'll set the class. If the isSelected value is true, then selected will be the class that gets added. Here are some more examples. Now anytime you're going to be using an attribute you need to use attr. Things like aria-label do not have a corresponding property value, there is no HTML element property called aria-label. So instead we have to bind to the attribute, the way we do that is binding to the attr. and then the name of that attribute. This also applies to things like call span for our table. And we could dots for nested properties, so in a class we could just say class.isStopped and then if the value for isStopped is true, then the class isStopped will get added to it. So first we've got our attribute bindings and then we've got our dotting, but we can also do this with styles too, so we can set the color to red or blue based upon the value of isStopped.
Adding Property Binding
Well let's take a look at a demo using property binding. We'll flip back over to our application here in Plunker where we left it off and first thing let's get rid of this pre tag on line 6 because we don't actually want that to show up later. But we do want to do a couple other things. One of the properties we can bind to is class, let's say that we wanted to change different attributes about this div. Well let's do that here. Let's go ahead and say there's a class.selected. Well if there's a class named selected, we can actually set that using property binding by wrapping this inside of the square brackets and then setting it to a value. Now we have a value, which is a property inside of our component called isSelected. Let's go check that out over here in the TypeScript file. Right here on line 20, isSelected is set to false. Well let's set that to true and now when the component re-renders on the right hand side we should see that there's actually a border around this div right here with the name and then the icon in it. If we go look at the CSS, we can see there's a selected class right there that's just got a border. If you want to change that just to get an idea, we could actually put in a background color and we'll put red for the moment, and that should re-render the side over here with a really attractive red. Okay let's get rid of that red, right? So back over here in the HTML, we can now see we've got class selected isSelected. Awesome. Well let's hit that back to false, back in our component on line 20 because we're going to do that through another technique a little bit later. Where else could we use this property binding? Well that's a good question. Inside of our template we have been using href and source with interpolation, but let's say we didn't want to do that. We could actually use property binding right here on the source just by wrapping that with the square brackets. And in fact, this is the preferred technique. Now why might you want to do something like this with the interpolation? Maybe your href in this case happens to be a full href that goes to a link, maybe it's got just part of it, like maybe it's got the end of that href. So what you could do is put in something like http:// and then maybe Google.com or something like that. And you could actually tack it onto the character.link. So if I did something like this, like gg.com, now if I hover over this, when I see the link in the bottom left hand corner, we'll see the two parts got concatenated together. Now obviously this isn't what we want in this particular case, but it's showing you how you can use interpolation to kind of combine things together, or you can use the property binding like we did with the source. We'll leave one of each just to show an example. Now we mentioned that we're going to have the selected class, well we're going to need a button to make this thing get selected. So let's create a div inside of our application and we'll close the preview so we don't see it refresh every few moments. Inside of that div let's create a button and we're going to put a bunch of styles inside of that button and we're also going to put the word Select in it. So let's type a few of these styles in to give it a little bit of class. First we're going to have a class here and we're going to tell it it's a dashboard button. We're also going to use an mdl-button and mdl-js-button. We're also going to make it raise, we're going to use the mdl-button-raised, and then we're also going to give it a ripple effect and an accent. Now if you don't have those classes in there you can always flip over to the solution and copy those in. Next we want to put an aria-label here. So if we're going to use an aria-label, remember we only can bind to properties, so if I say aria-label, that's not actually a property, that's actually an attribute in HTML. So if I do this and then I bind it to a property called selectLabel over my component, which I should have in my character right here on 21 and I want to say select a character, well that's not going to work, it's actually going to produce an error if I run a preview on this. Let's go take a look by running the preview. Now if I do this and I show the developer tools, we should be seeing an error, and there's a template parse error, if we click down it says I can't bind to this aria-label thing because it's not a known property of button. Well it isn't, we know that, because it's an attribute. So the way you can access that so you can use aria is we can do attr, say I'm using an attribute and it's called aria-label and therefore it's going to bind the select label to it. Now if you want to check this out, we can go back into the developer tools and we'll grab the selection tool, we'll go down to the button itself. I'm going to go over here and I'm going to click the escape so I can see all the elements and then I'm going to drag this back over, get a little more room, and we'll slide up to it, right here, and notice we're seeing aria-label Select a character, and that's the value that we bound from our component. So here's just a few ways that we can use property binding, along with interpolation, inside of our application.
Event Binding
Event bindings are how we communicate from the template to the component. For example, we could wrap with parenthesis the name and event inside of the template and then set that equal to a statement, for example, a click handler. This is one way communication again and this time it's from the view target to the data source. So the target might be click or on mouse move, and we wrap that with the parenthesis and we set it to a statement, like on click handler. So let's see an example of how we do this with a button because we have a button in our demo and we're going to need to do this. So I'll wrap the click event inside a parenthesis and we'll set it to the statement Save, so we're assuming we have a save function inside of our component, which we do, or we will at least, and the button has a click event, so we're going to wrap that with parenthesis. So that's binding it to the statement called Save, which is going to be in our component. We can do the same kind of thing if we have a custom component. In the previous chapter we created a custom component and we had an event emitter, which then put an output property on that custom component. So for example, here that could be a changed event that we expose, and therefore we could listen to that and then handle it with vehicleChanged. And the syntax for this is to set the event target equal to a statement. In this case the element event is going to be click and the component's event, the custom one, is going to be changed. Now sometimes we might have some kind of message or information that goes along with the event, and for that we can access $event, it's a special word that we can use and it might contain a message about that event. So in this case as we type with input, that's an event on the HTML element, whenever something changes on an input, we can check the $event, in this case their target is the input, and then its value property to see what's happening. So the message is $event. So we can use that to grab different information on it. I mentioned custom events like using an event emitter. In this case we define an output property on a custom component and we're calling it onChanged, and then when we emit that with the changed function inside of our inner component, it's going to fire that off and then somebody can bind to the onChanged and then handle that. The cool thing about this is we can bind to any event that the HTML element exposes or any one that we create through a custom component like we did here with onChanged. This gets rid of a whole bunch of Angular 1 built in directives that we used to have, like ngClick, ngBlur, ngFocus, we had a whole bunch of them we used to have to use. Now we don't have to do that, we can just take an event and put the parenthesis around it.
Adding Event Binding
Well let's flip over to our demo for event binding. We've got this Select button down here, but clicking it is not doing a whole lot because we don't have any events bound to it. Well let's change that. Let's go ahead and type in the click binding here. We use the parenthesis as we learn because that's how we do event binding, and we're going to set that equal to a function that we have inside of our component. Let's go check that out. In the component we've gotten line 32 select and we're going to pass in the name, it's going to set it, it's going to put a console message out and then it's going to toggle the isSelected flag, which we've already bound somewhere else. Now the isSelected flag is going to toggle the class around the div. So cool. So all we have to do is type in here, alright select, and what are we passing in? We're passing in the character's name. So once we type that in, when we click on that button, it should pass the character's name in, it's going to log it out to the console and it should also put a box around this area because it's going to toggle that class select up here on line 6 inside the template. Let's try it out. Click it, we see it got highlighted, and we can unselect it as well. Pretty cool. Let's try out some other event bindings, up here on the image let's say that we wanted to, as we mouse enter, to change the color of this image. We'll just move down to another line and take a look at it. So if we want to change the color we know there's a style property, but what about style.background? That could work for us. Now for now we're just going to hard code a value inside of here and to do that I'm going to put in single quotes because we want to make sure we're actually getting the value and not binding to a property name. And we'll put in EE0. So now the image background of that icon should be whatever EE0 is, which is yellowish. So that could be a nice default one. Well let's go ahead and do a mouse enter, and if we do that we'll have mouseenter here, and then we'll change something in that. So when we mouse enter we could call a function or we could simply say, okay set a color property to a different value. So we'll say set this color property that we have, which is in our component and we'll go take a look at and we'll tell it to set that equal to EE0, like that. And instead of having a background defaulted up here, let's get rid of that and set that to be a property called color. So now when it first comes up it should be whatever color is, let's go check that out in the component, it's up here and it's actually set to blank, so it's got nothing. And then when we mouse enter onto the image it's going to change the color to yellow. So we do that, you can see it turned to yellow. Great. Well what if we wanted to do something on mouse leave? We could do that as well. So here, let's go back t o the mouse and we'll type in leave right there, and now let's change the color to a bluish color. So on mouseleave it should change it to this blue. And again, we're not actually changing the image right here, we're changing the color which happens to be bound to the images style background. So when we enter it's yellow, when we leave it's blue. Alright so we've done event binding with clicks and mouseenter, mouseleave. What about for data, like when we type in words here? Maybe I want to type in the word John and I want it to actually change the name that's up there. Well let's put some code in that's going to take care of that. We'll slide this over a little bit, we'll go back up to our input because that's what we need to be on, and we'll move it down a line. Now inside of the input, let's go ahead and use the value property. We know that the value property is existing on the input and we can bind to that. So here we could bind to the character's name, like this. So if bind to the character's name it should show up as Boba right here, or Boba Fett, but when I change this to John, it's not changing anything. That's because this is unidirectional data flow. I'm taking the data, and it's flowing in one direction, from the component up to the template, but not back down. So what we could do is say alright is there any event on this input that we could use? Well there's actually an input event in HTML and we could do it here, say alright set the character's name, when we have input, to something like the event object, and the target happens to be this input, and then we'll use the value property. So now we're saying when the value comes up, go ahead and grab it from the character.name, it's Boba Fett, and then when I change it to John it's actually sending it back down through the input which also happens to show up right above us here where it says John details, just like that. No problem whatsoever. Now don't worry if that's a little bit verbose, what's on lines 11 and 12, but next we're going to learn how we can make this a little bit simpler.
Two-way Binding
Handling two way data binding the way we just did, by setting the value property binding and then the input for the event binding, is kind of crazy and if not crazy, well, it's just verbose, right? Well there's another way we can do it. We can actually use this football in a box where we have the square brackets and then inside of it the parenthesis right there. And that syntax allows us to send a value from the component to the template and then back up. It's basically a short hand for what we just did. Here's how it works. We use an ngModel directive, which comes with the formsModule for Angular and we wrap that with the football in a box and we bind it to an expression. Now an alternative syntax if we don't want to use the football in a box is the bindon-ngModel, but I prefer the shorter syntax with the football in a box. Here's an example. We get value in and then a value back out. We create an input and instead of doing that crazy thing with the value and then the input where we do the property in the event binding, now we use the football in a box and just bind to a property. Not so bad. So that is a built-in directive that we can use with the formsModule, we just have to import that. How do you get that? Glad you asked. So to import the formsModule we go back to our rootApp module and right there inside the @ngModule decorator we have these imports and we had browserModule already, but now because we're using ngModel and that's part of the formsModule of Angular, we can import that functionality. So that pulls in that formsModule to our application. This is important. It's one of the ways that Angular keeps its size down, if we're not actually using these features, we're not going to import them into our application. So we just add it to our import list of our ngModule. And we can add other modules too, and we'll do that later in the course.
Adding Two-way Binding
Well let's flip back over to our demo and we'll add two way data binding to it. Well right here on lines 11 and 12 we have the value property binding and then the input event binding. Instead of just changing that right away, let's go ahead and copy that section, we'll make a whole another div and we'll use it for color. So copy and paste all that. And the only things we're going to change is change the name over here on the right to color and we're going to get rid of that value in input right there. So now we should have an input over on the right hand side for the color. Great. Now what I want to do is I want to type in something like green and I want it to change the color of this guy down here. Right now we've got the mouseenter and leave to do that, but maybe I want to reflect a color up there as well. So if we want to do this, we can take advantage of what we just learned and we can do the football in the box, there's our football and there's our box, and we're going to use that ngModel directive that we learned about and we're going to bind it to a color property, just like that. Now we already have a color property and if by default it's nothing, so nothing's showing up, well watch what happens if I mouse over. As soon as I do that I get the EE0, when I mouse off I get the other color that we had. Now I can come up here and I can type in the word green, and notice it turns to green as well. And again, if I mouse over off that works. Well now using that same technique that we just learned, we can come up here where the value and the input are and we'll put in our own football in a box for the ngModel and now we can use that to bind to the character's name, just like that. So we can either keep line 11 or keep lines 12 and 13, and I don't know about you, but I prefer line 11. And now we have two way data binding so we can come back over here and test it out. We might want to change the name to something like Rey Skywalker, hopefully, or we change the color down here to something like purple, and everything works.
Built-in Directives
In Angular 1 there were a whole bunch of directives that we had to learn. In Angular 2 there's just a couple that we need to use, one of which we already used with ngModel. For example, the ngModle just wraps up the logic for handling the binding the value to the template and then sending those changes back to the component's property. So in Angular 2 we have these directives and they're going to help us basically take care of some of the logic inside the template. Let's take a look at a few that you might be familiar with if you know Angular 1. In Angular 1 we had these things like ngClass and ngStyle, and we can see the syntax on the left hand side. We actually have something very similar in Angular 2, and these are pretty similar syntax. So we can see here that if we go to ngClass in Angular 2 we're using camel case to identify it, we wrap it with our box with the square brackets and then we use a very similar syntax that we had before where we set the active class if isActive is true and then the color class is myColor is true. Well what if you just want to do a style? Well we can have two alternatives here we can choose. We used to have just ngStyle and we can still do it with ngStyle with camel case with our square brackets and then bind it to maybe an object literal where we have the style of color and we set it to colorPreference, which is a model binding. Or we could just say style.color and bind that one property to colorPreference. Now which way do you go? If you only have one property I would use style.color, but if you have more than one, you may find it easier to set them with ngStyle or ngClass. Well here's an example with ngStyle. We might have a div and we can use ngStyle here and bind it to a function. And that function could return back an object literal with the style properties. That's just an alternative to the style.style-name. So if you have perhaps three different styles that you're setting, ngStyle would be easier than doing style.color, style.background, style.width, for example. So we can do this for setting multiple styles. What about classes. We can use that ngClass to do that. And again, we can set the binding equal to the return value of function. And that's, again, just an alternative to doing class.class-name in a binding. This is great for setting multiple classes. If we have one class we could just do class.class-name. We did that earlier with the selected class, but if you're going to set multiple ones, ngClass is the way to go. So ngStyle and ngClass are really easy to use. Well what about any other directives we might want to use? In Angular 1 we had things like ng-repeat, ng-if, and ng-switch. Well these familiar concepts are going to translate over to Angular 2. Ng-repeat is a way to loop through things and we've been seeing how we can use ngFor. So ngFor with the start is a structural directive that changes the structure of our DOM and puts in multiple items, very handy for the ul's and li's. ngIf is another structural directive, which optionally shows and inserts elements into the DOM. Now this is either going to put them in the DOM or remove them from the DOM. It's not just going to show and hide it. And then ngSwitch is a way of optionally doing multiple levels of conditions. So we had that before in Angular 1, we still have that in Angular 2 as well. All three of these are structural directives. Let's look at how ngIf works. We've seen it before, but let's break it down. First it's going to conditionally remove the element from the DOM or add it back to the DOM. So when the current vehicle is true or false, you will then see the div appear with the You selected currentVehicle.name. This is very handy if you only want to show a message or some kind of content based upon a condition. And again, this is a structural directive, identified by the asterisk. If you did just want to hide or show something, you could do style.visibility to hide something. So the ngIf is going to evaluate the truthy or falseyness of that expression that we have. We've also seen how we can repeat a template using ngFor. This is also a structural directive because we're not just going to get one li when we're done, well only if we had one character would we, but if we had multiple characters we'd have multiple li's. So it's going to show an element and number of times. In this case we're going to iterate over the characters and the let is going to declare a local variable for us and that variable happens to be character. So then we can say character.name. Let's explore the local variable for just a moment. Maybe we want to do something a little bit more with it. Now that let declares a local variable, we did it with the character earlier, but we can also do let i = index. In this case i is going to be a local variable for the template and the index is a keyword that's going to automatically set that to the index value. So now the i there before the character.name is going to print off like an index value for showing the characters. We just talked about a bunch of ways we can use these built-in directives. But to actually use them, we have to pull this functionality into our application, right? We did it for the formsModule with ngModel. To use ngModel we had to import forms. So what do we have to import for ngFor and ngIf and ngClass to be available? Well the answer there is nothing more than we've already done. Why is because all those are in the common module. These are common things, things we're going to use in pretty much every Angular app that we use. So when we're building these apps, the common module is automatically imported by browserModule. So we were already importing the browserModule, that's the ES6 module of it, and then we put it into our import statement in our ngModule. So by default here, when we use the browserModule, it's going to pull in the common module and we get access to all the ngIf and ngRepeat and ngStyle and we're good to go. If we wanted to, we can also explicitly import the common module, that's okay too. But Angular already sees that we have it.
Adding Attribute and Structural Directives
Now that we've learned how to use built-in directives, let's go add them into our demo. Our template already has a class up top, on line 6 we've got class.selected we're binding to isSelected. And we can see if we click the button, it's actually selecting the Boba Fett color in the icon over here with the shadow. Well we just learned we could use ngClass to do the same thing. Let's look at the syntax side by side. With ngClass we could actually set more than one class, we could do selected here inside of an object literal and then use isSelected as the property, kind of matching what we have at the top. The difference here is that if we had a second property like foo, we could set that to something else if we wanted to. So that could be a foo class that we've got set. So let's remove the initial one, we'll leave the ngClass in place, and let's see if our functionality still works. Over here on the right we click Select and we still have the selection, we're good to go. Well let's take a look at some other features that we can do too. We learned about ngIf and ngFor, at the bottom of the screen when we select something, what if we had a div down here and inside of that div we only want to display content if the guy has been selected or not. So we'll create a div and we'll set a class equal to row for our styling, and then inside of there, let's use an ngIf. Now the ngIf we could set it to something like isSelected again. So if they select it we can display something like okay Your character has these vehicles, and we'll go ahead and display these vehicles after this. So right now, once we select it, we should see that text at the bottom of the screen. If we don't see it, click Select, now we should see it down at the bottom. Perfect. Now we can put the character's name in here too, make it a little bit better just to show what character was selected, so we could say character.name, so that would render that. And then inside of here we could create a ul and then li and for each li we'll display the vehicle's name. So to do that we're going to take advantage of ngFor, like this. Now the syntax here is we have to loop through something, so we're going to go right to left here. The thing we're going to loop through is a list of vehicles. Now let's go back to our component just to see if we've got that. Back in component over here we should have a list of vehicles right there, and we've got three of them. Now let's go back into our template. Once we have our vehicles we need something to loop through them with, an iterator if you will, and we'll say let vehicle of vehicles, like that, and then inside of here we're going to vehicle.name because that's the property on that guy. And yes I like to type vehicle the wrong way all the time, the vehcile. So once you spell that right, you've got it in here, we've got our vehicle which we're going to loop through, and it's only going to display once I click Select. I've hit Select, there's my character and there are my vehicles for that character. And if I change Boba Fett up top here, it should change the name to let's say Poe and then it's going to reflect in all the different places on the screen. And as a reminder, remember we've got the star down here for the ngIf and ngFor because those are structural directives, they're actually adding and changing stuff in the template. If this isSelected is set to false, everything gets removed from the template. If you go into the dev tools you will not see that HTML in the page, but once it's true again, all that stuff will appear. Same thing with the ul and li, it's changing the structure, it's adding multiple li's, that's what the star stands for. At the top we don't do that ngClass or even for ngModel because we're not changing the structure, we're just changing styles, classes or even content on the page. And that's how we use built-in directives.
Pipes
Another feature that we can use in our templates is a pipe, and a pipe allows us to take data and format it on the screen, maybe for dates or numbers or other values. This is important because sometimes the data that we get doesn't come in the value format that we want it in. Now we had something similar in Angular 1, they were called filters, these things are called pipes in Angular 2 because they flow through a pipe, and because we use the pipe character. So the syntax works something like this. When we use pipes with like a string, there are two built-in ones called uppercase and lowercase. And it allows us to either uppercase the character.name in this case or lowercase them. All you have to do is put the pipe symbol and then the name of the pipe right after it. What if you have a date? Well we've got a date pipe, which actually takes some parameters. Now these parameters allow us to pass in a date first and then the format of that date. And there's some standard formats with names like medium, and there's also others where you can actually pass in the format, like year and month and day. There's an extensive syntax for this you can check out in the docs. When we use the date pipe, just like there's the pipe, then date and then the format, we actually output the date in that format. We also have numeric pipes and these allow us to format for numbers and currency and percentages. The percentage the number allows us to pass in digitInfo, and for those what we do is we pass in first the number for the minimum number of digits you want to display, and then after a dot or a decimal, we pass in both the minimum fractional and the maximum fractional digits we want to use. So with this number pipe here, if we had a number that had 10 digits after the decimal, only 3 of them would display. Pipes are just for formatting of data, we can also use them for more powerful things too. There's a built-in pipe called the async pipe and this allows us to format data and stream it using RxJS and observables, or with a promise. We'll learn more about this async pipe when we get to the chapter about getting data and displaying it on the screen. But wait there's more, we can also build custom pipes. Let's say you wanted to create an initCaps pipe where only the first letter of each word is initially capitalized. You could actually do any custom pipe that you want, taking a value in and then outputting another value. So here with the custom pipe we actually use another decorator called the pipe decorator, so we pull that out of the ES6 module for Angular Core, we pass in a value to transform and the transform function when we implement that interface of PipeTransform, and then we also have optional arguments that you can push in, think about how the numeric one worked. The numeric one, the value would be the number and the args would be the digit info. So here we're just replacing our own values and arguments, creating our own pipe and using regular expressions to create our own InitCapsPipe. Don't forget to implement the PipeTransform interface, because if you do that it'll guard you in your code to make sure that you spelled and used the proper implementation of the transform function and its arguments and its return value. And all these pipes are great for formatting values on the screen.
Exploring Template Syntax in Storyline Tracker
Now let's flip back over to our storyline tracker demo and see how we put all these concepts together in that application. And here we can click on the View Sample for number 0 here, Storyline Tracker, and when it opens up, here's the application. Now let's click over on Vehicles, we're going to examine the vehicles list and then each button here. Each one of these guys, 30 for Millennium Falcon or the X-wing Fighter, those are separate components. Well let's examine the tree, it's nice in Plunker you have these tree views, which you can open and close the different folders like that. So I'll close them all, just show you where we are, we'll go into the app and then vehicles, and then down there we're going to look at the vehicle-list. Now the third one happens to be the TypeScript file and we'll make the preview a little smaller. Inside of this file we can see that we're using a couple different concepts we've already seen, such as the ViewChild to get that FilterTextComponent, and we've got a list of vehicles that we're getting as well in the getVehicles. We'll learn how all this works to get the vehicles later. But over here we've got our VehicleListComponent and that's going to be our HTML template and in that we can see we've got the title of Vehicles, as it's showing up over here on the right, then we've got an href for the routerLink for vehicles, and that's going to be the new button right here, the Add button. Then we've got a story-filter-text. This is the filter component right there where we can type in like Falcon or maybe wing. And then below there we've got our ngFor that we just learned about. On line 9 we're looping through a list of filteredVehicles and then we're going to have each vehicle be displayed with this story-vehicle-button component, and we're going to pass in the vehicle using input property binding. So let's go check out the vehicle-button right there, and that's going to be inside of shared and under vehicles and under vehicle-button, and here's our template. So this template right here, lines 1 through 12 of the vehicle-button, is going to be displayed for every single vehicle in the vehicle list. This is why we componentized things, because we wouldn't want to repeat all the stuff everywhere, and it makes it easier to reuse it. Let's examine what we've got here. Over on the right hand side we see Millennium Falcon with the number 30 next to it and then a button over here, a little icon of an arrow. Here we can see that we've got the name, that's the vehicle.id with the dot, and then the vehicle.name, and ew're using a pipe called initCaps, that's a custom pipe that we created. And then we've got an href here for the routerLink for the going to the vehicles vehicle.id. We'll learn about how routing works a little bit later, that's going to bring us to the details page. But for right now, just know that it's a button with an icon on it. So right there we've got our names, we've got our buttons, and it all works great. What about editing? If we click on this button and go to the Millennium Falcon, we can see we have inputs. Now you might expect that we've got an ngModel there, and you'd be right. So let's close the shared folder and go into the vehicle folder for our vehicle details, and we'll go look at the template for that. So the template on this guy, you can see we've got the vehicle.name and we're using the uppercase pipe, that's the built-in pipe, so show Millennium Falcon in uppercase characters. And then you might expect we've got ngModel over here and we've got one for the Millennium Falcon and another one for the type, and we're binding that to the editVehicle.name and the .type. EditVehicle happens to be in the model, right here associated with it, down there is the editVehicle, which is of type Vehicle. And going back to our page, we also have some bindings for the buttons, like Save, Cancel, and Delete. The Save button, when we click on it we call the save function, and likewise for the Cancel and for the Delete. And we also have not displayed classes, if I'm in AddMode you couldn't be canceling it. Let's back out for a minute and show. We're going to cancel those changes, now we're going to go back one page. We'll go back to Vehicles and if we click on Add, notice we're on the same page but we're not showing the Cancel or Delete buttons because we're using class.not-displayed and we have an AddMode flag. Pretty cool. Let's go check out that initCaps pipe because we used that. The uppercase pipe up here is built-in, but the initCaps pipe is something that we wrote, that was in the shared vehicle-button, just as a reminder, it's up here on vehicle.name. So when we click on the individual button right there, Millennium Falcon or X-wing Fighter, only the first letter of each word is capitalized. Well let's go check out how that works. First, we're going to go into a shared module. InitCaps is something that we want to share across our entire application and multiple pages might have one on them and maybe a single page might have more than one as well. So we're going to put in a shared module that I intend to import every time we need to use it somewhere. And the shared module has init-caps.pipe, which we've seen the syntax in the slides for this, we use the PipeTransform, we pass a value in and then we transform it. And then to tell the application about it to let Angular know what this thing is, we called it initCaps right there in the name, that's what we're going to refer to it in the template, and then we have this shared.module that the InitCapsPipe is declared in. Let's take a look at that. So here's another ngModule we've created. This ngModule is pulling in CommonModule because that's where the pipes and things are located. We're also using other things like our FormsModule in there, and we're declaring the InitCapsPipe, so we have to declare it to the application so now Angular knows about it, and then the shared.module is then imported by our main app root module. Now because we imported these things, that's great because we're going to use them, but we want the people who are importing the shared module to be able to use it too. So if the appModule, the ngModule at the root of our app, is going to import shared.module, it needs to know about the InitCapsPipe if it's going to use it. And to do that, what we do is we export the InitCapsPipe here on line 18. And don't worry, we're going to learn more about how ngModules work and how we can create a hierarchical structure like this storyline tracker application later on in the course. And as we've seen throughout this course, we learned about each individual features, such as event binding or property binding or pipes or templates or metadata, and then we go look at them in the storyline tracker at the end of the chapter so we can see how they fit into the big picture in an application.
Summary
This chapter was all about our template syntax. Once we have a component we have to have something to render. We learned about data binding - one way, two way. We learned about unidirectional data flow and how the data only goes from one direction or the other, for example from a component up into a property value on the template or from the template back down to the component via an event. We learned about attribute directives, things like ngClass and ngStyle. And then the structural directives, like the ngFor, the things with the star in front of them, they're the ones that actually change the DOM. And finally we learned about how we can use pipes to transform values. And this gives you a good first look at the template syntax in Angular 2.
Services, Dependency Injection, and Lifecycle Hooks
Services, DI, and Lifecycle Hooks
Our demo application, the storyline tracker, retrieves data about the characters and stories and it does this from several components, so it makes sense that we don't duplicate that kind of code. In this module we'll see how to isolate data management in reusable services and use dependency injection with Angular 2 to make the services available when and where they're needed. Our storyline tracker also needs to load character data as the character list component is loaded and its template is rendered. This will be accomplished using lifecycle hooks, specifically the ngOnInit hook. This module is going to introduce how to share logic across the story tracker application using a service. A service provides anything our application needs, such as access to character and vehicle data. We used good separation patterns in Angular 1 that we're pretty familiar with, and we're going to see that again here in Angular 2, specifically separating features such as components and services into their own modules using dependency injection to provide an instance of a class to another Angular feature. And we're going to explore how to answer questions such as how do we load data before a component starts or how do we run code whenever a change is made to a data binding? The answer to these lies with a component lifecycle hook, which is going to allow us to tap into specific moments in the application lifecycle to perform logic. All three of these features play an important role in the storyline tracker demo app, so let's learn how to use them.
Services
We need a place for shared logic in our applications. Services fulfill that role. A service provides anything our app needs and then we can share that across the entire application. They're the ultimate form of code reuse. Let's take a look how things have changed from Angular 1 to Angular 2. In Angular 1 we had factories and we had services and providers and constants and values. All of them were ultimately a provider, but we had to pick and choose how we wanted to use them. In Angular 2 we just have a class, so instead of having to pick what we want to use, we just effectively create a class and we're good to go. There is no service object in Angular. Let's take a look at some code. Here we've got a vehicle service and we're just pulling out a list of hard coded vehicles. Notice that are VehicleService class is just a class and we're exporting it and it provides something of value, in this case it's a getVehicles function which brings back an array of three vehicles. This logic could be shared in multiple different components that might need vehicle information. And we can use this for a variety of things, we could use it to get data, like we're doing here, or we could use it as a logger or exception handler or message service, any place we need to share data or logic. And you notice there's no Angular code inside this class, it's simply just a class. And a service plays an important role inside of any application, especially our storyline tracker. Let's take a look how we can use the service to go get some data and share it across our application.
Refactoring for Services
It's time to apply what we just learned about services to creating a demo app. So let's go down to our demo in line 17 here, Need Services, because it needs some services. We'll open it up and it's got a list of four different characters, we select one, we see the selection. Pretty simple. For now, let's go ahead and close out the preview and we'll open up the character-list.component TypeScript file. Notice in here on line 12 we're actually setting a hard coded list of characters. We don't actually want to do because, well multiple reasons, one of them is that we don't want to have a hard coded list here because if we want to use that list somewhere else, well now we've got to copy and paste it where you might have multiple components that need to use this. And we may actually want to put this into a backend service, which we'll do later on in the course. But for now, let's abstract this out to a service that provides this list of characters. So first, we'll right click on the app and we'll create a new file and let's call this character.service and we .service as a suffix because that is one of the conventions in the Angular style guide and it makes it easy to identify it. Now in our service let's go ahead and first pull in and injectable, and this is a decorator we're going to need, and it's going to come out of the Angular Core ES module. Now once we have that, we're going to define our class called CharacterService and we're going to use that injectable right up here and decorate the class with it. Don't worry about this guy too much right now, we'll learn more about why we did this later on in this particular module, but for now it's a good idea just to know that we always use injectable on the services. Then we needed to have a function on this guy, we want him to return our characters. So we'll have a getCharacters function and he's going to return an array. We'll go ahead and define that array in just a moment, but before we get that array we need to know what type it's going to be, that's going to be a character, right? So we're going to go back into our service and we'll import the type character. Now where is that coming from? That module is relative, it's one I created, and it's coming from the character file. Cool. So we're going to return back a character array. Now that we have that type, let's go back to our component list and let's copy out the array, just the array itself, we'll leave characters there and we'll come back to that guy in just a moment. Our character.service now, we're going to remove the empty array and we're going to paste in the array that we just grabbed and then I'm going to indent these just a little bit so we can see what they look like. Now you can see why we grabbed the character on line 3 because we're actually using that as a constructor to create our four characters. So now our service is ready to go, but how do we use that over inside of our list component? Well if you go back to the list, the characters is nothing now, we don't even know what type it is. First let's define the type of this guy, he's going to be an array of character, and that's a generic array of character type and the character type is still here on line 3, so we're good there, but we have not yet set it. So the next thing we need to do is we need to create a constructor and in that constructor we'll create a private instance variable of characterService and that's going to be of type CharacterService, like that. So what we're telling Angular is go look up in your Angular injector for this thing called a CharacterService, if you find one, please put it in this local variable here, this instance variable of this class. So then we can say, okay I want to set my characters and I want to use this new characterService and call this getCharacters function and if you're anything like me, you're probably getting tired of typing the word characters. So right here, we're saying go get that characterService, pull it in if you find it, and then use it to go ahead and set and initialize my character list. Now we haven't told Angular in this file where to get CharacterService, we still have to import it up here. So we want to go to the relative file to get this CharacterService out of that ES module. And that would be ./ again and we can use the name of the file, so it'll be character.service. Now there's one more thing we have to do, but just to demonstrate that and kind of show how the error messages work inside of Angular, let's run this and then we'll take a look at the developer tools. Okay nothing rendered, good. We've got our error and if I scroll to the top we're going to see here, if we scroll down a little bit to class AppComponent and inline template had an error. We'll that's not telling us much other than there's an error, but now here's the good part. No provider for CharacterService. It's actually yelling at us, no provider for CharacterService! That's exactly what it is. We know we created a CharacterService, but Angular is saying I don't know what that is, you didn't provide it to me. And think about the words, the words are very important in the error messages, it's saying you didn't provide it. So there's a thing called providers in Angular, and we're going to learn more about these, but first let's create one and use one. Now there's a couple ways we could do this. This component needs to know about that service, so we need to provide it somewhere. Angular has an injector at the component level, which means that this component, if we provide the service here, will be able to use that service and any child component that's created by this component. So we could say provide the CharacterService to this component, and look what happened, as soon as I typed that line in. The right hand side just lit up and we are good to go. We've got our list and our application is functional. Now the problem with this is, let's say we had another component like the character.component down here, if that's not a child of this one, it's not going to be able to get to this characterService and we'd get that same error about there's no provider. So how do you deal with this? Do you provide it again? Well that's not a great idea because you may not want to have multiple instances of this service everywhere. The whole point of the service is to share it, in this case. So we're going to take this line out of here and we're going to break out app, and instead we're going to go to the app.module. The app.module also has a way to provide things. So at the app.module level we're going to say go ahead and provide the CharacterService. Now it's not going to work here because we haven't imported it yet, so I'll go back to our character-list.component, we'll copy that import statement on line 4, go back to our app.module, and now we'll import it right there. Now as long as that's the same path our app should work. So you might be like, well what's the big deal? What's the difference here? The big difference here in this app isn't so big because it's only two components and one module, but what we're learning here is that each component has its own Angular injector. Angular has a hierarchical injector tree that matches and parallels the components tree. So each component where you provide it will then have a service and any child it creates can access it. But if you don't want to deal with that, if you want it to be available to anybody in that module, you can provide the service in the app.module, and that will make it available to everybody who's in that module. So in this case I might want to use characters on multiple different components, I'm going to put it in the app.module and that's going to save my day. So let's review our service real quick, we defined our CharacterService, we've exported it, we defined a function that goes and gets some data, and then our character-list.component will set up the constructor to inject it, it's going to ask for that CharacterService on line 17, which is going to go look in the injector in this component, it's not going to find it there, and then it's going to go up to the app.module and go, hey I found it in my injector, it's going to give it to us, that instance will then be used to get the characterService and get the list, set our characters and display on the screen. And that is how we create a service.
Dependency Injection
Now we've created our first service. We can understand how the storyline tracker could use these services to share the logic for making data calls throughout the app. We've also learned how to tell Angular about the service and how to let a component gain access to a service by using constructor parameters. Welcome to dependency injection in Angular. Dependency injection is also known as DI for short, it's how we provide an instance of a class to another Angular feature. It's how we got the characterService over into the character-list.component, right? Well let's take a look at some more examples and break this down. When we create a list component, sometimes we need to inject other services into it, maybe to get that list. So here we're going to inject a service into a component and Angular is going to locate the service in the Angular injector, then it's going to inject the service into that constructor, right here. And then name of that variable that we're highlighting could be any name, we just happened to by convention name it the same thing as the type with a lowercase v in this case. The type is important though because that's what it's going to go look for. Alright so visually, let's take a look at the same thing. We've got a component and inside that component we might have a constructor where we're saying go get this service please. Well Angular is going to go out and say yes siree, it's right here, there's my service. So that service is going to be injected into the component's constructor for us. Now if this seems new and you've been with Angular 1, it's actually not too new. There was dependency injection concepts then too. In Angular 1 we did this thing called $inject to help minify save our code. So here we used injection with this $inject to say there's a thing with the string name inside of Angular known as VehicleService, please grab that and match it up with the first parameter of the vehicle's controller function, and that's how the injection went out and got that. In Angular 2 we don't need that string thing. Let's look how this works over here. We've got the injection, we're saying that type is VehicleService and we're putting it into this property called VehicleService. That's how we actually inject in Angular 2, we didn't need to worry about a string name, which is also an easy way to make some kind of a typo. But what about when we want to get a service and inject it into another service? This is a pretty common scenario. Well Angular comes with a service called HTTP, let's get a preview on how that works. This is the same concept as when we're injecting into a component. In this case the @Injectable is kind of like that Angular 1's $inject, but now we're using a decorator instead of a funky property name or a member name like $inject. And we have strong typing instead of strings. So here what we're saying is go get this thing called HTTP, which is an Angular service and it's going to inject it into our constructor. What about that @Injectable? That is going to provide metadata about the injectables. Whoa, wait a minute here, now the name of this is a little weird because it sounds like this VehicleService is injectable, and while the VehicleService is injectable, that's not really what it means. This @Injectable is basically telling us that this VehicleService may have things that are injectable into it, and now it does, right? It's got this HTTP service, which is going to be injected into it. So that @Injectable, why do we need it? We need it because our service has an injected dependency. We need it because Angular requires a constructor parameter metadata in order to inject it. TypeScript only generates metadata for classes that have a decorator. Ah-hah. So because TypeScript will generated metadata for us about this class, metadata, again, something that describes the class, it'll go ahead and do that because we stuck this @Injectable on top of it, just like we had @Components or @Pipe, the @Injectable is going to provide information to Angular about this HTTP type that we're injecting into it. Well that's going to be key because now Angular can learn about the HTTP and know where to find it. Now if we want to be picky, we actually don't need the @Injectable if our constructor doesn't pass anything in, but if we have something later, let's say we added the HTTP to the constructor later and we forgot to stick that injectable on, we'd be in trouble, we'd get an error. So the general rule of thumb and the convention we follow in Angular, and check this out in the style guide, is all services we stick @Injectable onto it. It really just future proofs our code and it's quite simple to do. We need to provide that service to the Angular injector. If we don't provide it to the Angular injector, it's still not going to go anywhere. We learned that when we saw the error message earlier in the demo. In Angular 1 we still had to do this, but in Angular 1 it was a little bit different. So Angular 1 we provided a service by saying hey there's a service called VehicleService and we're going to give it a string name of VehicleService so you know how to find it. Angular 1 only had one global injector so we just told it right away, hey there's the thing you need, go get it. Angular 2 has a hierarchical injector tree and it's got one at the app root, as we learned. We used both of them in the previous demo. So how does this work again? We're going to provide a service in Angular 2. First, we're going to list out our AppModule, and notice we have providers here. The first provider is going to show us that the service is available in the application's root injector. So now VehicleService is going to be available anywhere to any component or service that is inside of AppModule. And then we can inject it into one of those guys. Angular is going to register all startup module providers with the application root injector. The services created from that root injector providers are still available to the entire application and this makes the VehicleService available to any module that is eagerly loaded and don't worry about eager and lazy loading, we'll learn more about that when we get to the routing chapter later on in the course. We talked about this component that we have and a constructor, let's see how this actually works with the injector this time. There's this thing called the injector we've been looking at and let's say it's the root app injector and we go ask for one of these services. If we had registered and provided these services in the app ngModule, then if we ask for one of them, the injector can provide it for us. And this means that each of these services in this app root injector that are provided throughout the application, we're going to get a singleton of those in this case because there's only going to be the same instance being used by all of them. And that my friends are the fundamentals of services dependency injection with the Angular injectors.
Injectors
We just learned how to create and service and provide it the app's root injector and inject into a component or service to use it. Let's learn a little bit more about injectors. We learned about how each component has an injector and Angular's application root has one. Well let's talk about this a little bit more because when Angular goes and looks for a service, it's actually going to look in the appropriate injectors for it. So it's critical to know that it's got one injector for the application root. We did this in the previous demo when we injected the VehicleService into our component and it had to go look for it and it looked for it in the app module's injector. So by registering the service in the appModule, the app's root, it lands into the root app injector. And what does that really mean? It means that everyone within that module has access to it, so Angular has that one injector for the app root, but remember it also has a hierarchical DI system with a tree of injectors that parallel the application's component tree. Whoa, what does that mean? Okay, let's look at a picture. So in the component tree, we might have a root component. That root component which has a template and it's also got other components that it uses like Component A and Component B, each component also has its own injector, which means we could provide, using the provider's array, into each of those components. Now let's say that we had this tree here of Component A having C and D as well, if we provided a service at the Component A, only Component A, C, and D would be able to get access to it and inject it. If Component B tried to do it, we'd get that funky error that we saw earlier about hey there is no provider for this service. If Component B provides a service, A, C, and D won't be able to get access to it either. So how do we make it available everywhere? Well one way to do it is to put it at the root component itself and then anybody in that tree will be able to get to it or we could put it in the Angular module, that in this case would be our app root, the main ngModule for our application. Angular has a very powerful DI mechanism. So it's important to understand the different ways that we can work this through, but it's also important to try to keep things simple, right? So you might be asking yourself, where do we actually set the providers John? In the component or do I do it in the Angular module? Let's try to make it easy for these both. If you provide it in a component it's going to be available to the component and anything in its tree, like this here. You'd want to provide it here in the component. A good rule of thumb is to register the service in the component's providers array only if the service must be hidden from components that are outside of this component's tree. I find this is a rare use case. Now the way I like to go is to provide it in an Angular Module or an ngModule. Here lazy-loaded modules and their components can inject the AppModule services and they cannot inject the AppComponent services. We're going to talk more about lazy-loading later, because it's a great concept inside of Angular, when we get to the router chapter. But by using the providers at the module level, that means our modules can access it whether they're eagerly or lazily loaded, and we don't have to worry about services being boxed into a certain component tree if we really want them to be available everywhere, because Angular is going to register all the startup module providers with the application root injector and they're available to the entire application. So again, we had that vehicles.component, that list, and we can provide it to the component, and that makes it accessible to this component and its tree, but not outside of it, or we can do it inside the app.module right here in that provider's list, which makes it accessible everywhere inside of that. So I'm big on rules of thumb and conventions and style guides, and what I like to do is I prefer registering my providers in the Angular Modules, and you really only want to do this once, not twice, because providing a service once will allow you to get a singleton and in this case I'm getting data from other places, I only want one copy of that service. Well the storyline tracker retrieves data about characters and stories from several components, so let's see how to isolate data management in reusable services that use DI to make the services available when and where they're needed.
Changing Where the Services are Provided in Storyline Tracker
Let's go take a look at some providers in action and how we can tinker with the injectors to see how they can behave differently. We'll do this by looking at the storyline tracker demo inside of our samples. Notice on the dashboard we see a list of characters, that component is using a characterService. Well our character-list also is using a characterService and it shows the list right here. So how are they both sharing this? Well let's go ahead and close down the preview and let's explore inside the app folder, we see characters, character-list, here's our component, and then on line 21 we're injecting the characterService, but notice we're not providing it here, so it's coming from somewhere, right, because line 21 is saying Angular give me that characterService, so somebody has to have it. Well the dashboard also has to use that characterService. So right here on line 23, he's injecting it as well, but nobody's providing it inside the @Component. So somebody's got it. Who has that service? Well the service is under the models folder, right here, that's our characterService and it's got that addCharacter, deleteCharacter, getCharacter. What we're doing is we're providing it down at the AppModule's ngModule decorator, right on line 31. So now everybody gets it because it's at the app root injector. So let's prove this out. Let's go into the characterService and inside of the constructor, right here in between lines 18 and 19, let's put a console statement. In that console statement we're just going to say the characterService was created and then we'll run the application and we'll open the developer tools and when we open those tools up, we'll clear out the console just so we can see everything happening, and you notice we've got a characterService created right away. We'll make this a little bit bigger. Right down in the bottom right hand corner. Alright well let's click on the Characters screen up here and we click on Characters, it's not creating another instance, it's using the same one that was already there. So the first time the injector gets asked for the service, if an instance has not been created, it creates one and gives it to you. The second time, it gives you the already existing instance between we're only sharing that same one, so I can go back and forth and we're not recreating that characterService, we only have one of those messages. But what if we put this inside of the providers for the component? Let's try that out. So back in app.module, we've got this guy right here, right. Now let's go ahead and take him and let's also put him inside of let's say the dashboard. Alright so our dashboard is going to be up here and we're going to put a provider statement right on line, well between 13 and 14, let's say 13.5, and we don't have it, yes we do, okay we've got the characterService 14 and we're importing it on line 6. So now we're providing it twice there, once inside the app.module and once inside this particular dashboard component. So let's clear this out again just to see it and we'll rerun it with a refreshing of the live preview. Now when it's loading up here, we loaded the characterService for the dashboard, now let's go back over to characters and notice we got a second instance. The first one got loaded for the dashboard. Now what happened is the dashboard, the way it works is it says hey, you asked for a characterService down here in my constructor, does my component have that or one of my parent components? This component has one provided to it in line 14, so it used that one. The characters component didn't have this so it used the one in the app.module. And just to prove that these guys have to be at a level where they can access them, let's go back to the app.module and let's comment out the provider's down here. The only one we have is the characterService, now the dashboard has its own, remember, but the character component does not have a way of getting to it. So the application will load, giving us the false sense of security here that everything is going to be okay. And we can see here we get the characterService created in the console. Clear the messages out, now we click on the characterService and when we do that we're getting an error and we're going to get that famous no provider for characterService. And this is how providers work.
Component Lifecycle Hooks
It is really helpful in application development to know when things are being created, when they're being destroyed and other moments in time. In Angular 2 these are referred to as lifecycle hooks. Let's talk a little bit about component lifecycle hooks. These are hooks that allow us to tap into a specific moment in time in our lifecycle to do things like go get data when the component starts up or destroy any references we want to get rid of before the component goes away. Let's take a look at how these work. First using TypeScript, we can implement an interface like OnInit. There's a lifecycle hook called OnInit that we can use. By implementing that interface, we'll get a little bit of tooling help to tell us, hey you didn't implement a function called ngOnInit. Oh wait, here it is right here. So when we implement that, we won't get the error anymore and not it tells us, okay so now when I see this ngOnInit I'm going to fire up this function as soon as the component initializes. This makes it an ideal place to do things like going and getting data to initialize my component. Now I don't need to use the interface OnInit, but I like to do it. Why? Because if I don't do that and I left the implements OnInit, let's say I spelled ngOnInit wrong, I can name a function anything I want to, let's say I called it Ng with a capital N, it's not going to actually get picked up by Angular because it's not spelled right, it's case sensitive, or maybe I spelled it wrong completely like I called it foo or activate. It's a valid function so there's no errors here, at runtime it would just never get called. That's because Angular looks for certain keywords during its lifecycle. So by using the interface it'll actually tell us right at development time, hey wait a minute. Now you might thing, hey should we call getCharacters function inside of the constructor? And the answer to that is a no. Why? Because years of experience and many shortcuts have taught us all to keep complex logic out of the constructor, especially anything that might call a server, like data access method is sure to do. We should be able to create a component in a test and not worry that it might do real work, like calling a server and getting data before we tell it to do so. So the way we avoid that is to not put it in the constructor, but somebody has to initialize our data, right? Well Angular will call it if we implement the ngOnInit, so that's what we do. Angular offers a number of interfaces for tapping in a critical moment in time in the component lifecycle. Some key ones are like onChanges, that'll come up whenever an input property changes. There's also the time of creation or initialization, that's the OnInit. And there's things like AfterViewInit and maybe we have a different change to that data binding value again for the input. And then when the component goes away, it's OnDestroy. And these are the most common lifecycle hooks we use for a component. There are a few others, you can check these out on the Angular io docs. And remember, while you don't have to use the interface, it definitely is going to help you out so you don't make any mistakes or any typos. Now that we've learned more about the lifecycle hooks, let's go back into our demo app and instead of getting our characters and our vehicles inside the constructor, let's use the new component lifecycle hooks to do that.
Implementing Lifecycle Hooks and Their Interfaces
Let's take a look at our example number 19, the Component Lifecycle Hooks. We'll click on View Sample and it'll open up. And over here as I select on somebody, it's going to change the selection and I can also clear out the selection. Let's take a look what's actually happening inside the code though. So if I have this list right here of character components, and we'll close out the preview, we can see that we're getting the characterService and then we're going to get that character list on line 22, set a local property called characters, and we're also going to set a selected character property when we click on Select inside the template. So here's my template and when I select somebody by clicking on it up here on line 3, that click event is going to fire the select, select the character, and notice on line 9 we're actually using a my character subcomponent, a nested child. We're passing in the selected character to him and then he's going to accept it and we'll take a look at him, he has an input parameter, and then we just log out the messages of what we did with that character, which particular lifecycle hook actually changed. So let's watch this happening in the console because we're console logging all of these. We'll open the developer tools up and we'll go back to our preview and we'll close the code there, and again we'll clear out the console, which makes it easier. First I'm going to click on Han Solo. Now when I did that, notice we're seeing all the different events that are firing off. First we saw an onChanges happened and then onInit. So first of all we changed the value of the input and then the onInit fired and then we hit AfterViewInit. Now let's change it to Kylo. When we did that, we didn't create a new component there, we just had the onInit fire the first time, but now the only thing that fired for Kylo was the onChanges because we changed it. So we change it for Rey now, it goes down to Rey. We'll click on Rey again, nothing's happening because nothing changed. Now what happens if we clear the selection? What we're doing in the code is we're actually taking the selected character on the parent component and we're setting it back to undefined. That's going to pass it in and it's actually going to destroy that child component. So the child component has only been created once at this point. Now we go back and we select Luke and it recreates it, has the onChanges, OnInit, and AfterViewInit. Now this is pretty cool, but let's take a look at what happens inside of our code if we play around a little bit. First we'll go inside of our character.component because that's where we're tracking the lifecycle events, and over here what if we changed ngOnChanges to something else, like NGOnChanges, like that? It's still valid code, right, that's just a function. Or what if you change the onInit down here, we'll change that to NGOnInit as well. Now let's run it, we'll clear out the console again, and when we do this, what happens over on the right? We click on Han and AfterViewInit happened, notice nothing's happening now. It's because the onChanges and the onInit are not found. Angular is going to look for those particular names, those events, in a lifecycle of a component and if they're there, it'll use them and fire them. Now we can call this function ourselves if we want to because it's just a function, but if we name it this way, Angular will find those. So you see this implements up here on line 10? We're implementing interfaces for OnChanges, OnInit, AfterViewInit and OnDestroy. Each of those has a corresponding function that we see here starting on line 13. The advantage of implementing the interface is that when you're in a tool, an editor like Visual Studio Code, which we just happen to have here because I've downloaded the code locally by clicking on this download cloud button and opening up, and we've got an editor like this and we implement OnInit, for example, in this particular place. What happens if we change that to NGOnInit like this? Notice we've got a red line on line 11. It's telling us that this CharacterListComponent is incorrectly implementing the interface OnInit, and very specifically it says, hey look, there's a property called ngOnInit that's missing in this type. Now you don't have to implement the interface, the code will still work without the interface, but in this case it's going to run and it's just not going to know what's going on because it's not going to fire this. However, you can also run it without the interface if you spell them correctly. But obviously the advantage to having the interface there is to protect us. So in a place you get a lot of interfaces especially, like here in the character.component. Here we've got four different interfaces we're implementing. If I don't implement those and I spell each of those wrong, let's say I go to each one of those, we'll do that real quick, and I type in something like foo_ in front of each one of them. Now it's going to tell me up top that you've made a whole lot of mistakes here. We're incorrectly implementing everything. Basically, start over. But if we delete these implementations up top, we don't get that error message, so that doesn't safeguard us. So I like to implement those interfaces and I like to make sure it helps me so I don't have to worry about spelling things correctly. Now where do you get those from? They come out of Angular Core, you can see them, I'm importing them up on line 1. So when we're in a tool like Plunker, we're not getting that IntelliSense and all the help, but when you go to a tool like a WebStorm or a VS Code, you're going to get that help because TypeScript is going to help us out. And this is how the lifecycle components work and how the editor helps us write better code.
The Role of Lifecycle Hooks in Storyline Tracker
We just saw how we can use the lifecycle events in the application and log out some messages, seeing when they exactly happen, but let's see them in a larger app. When we click on the storyline tracker here in Plunker, we get this application, and then we're going to click this download button right here, and then we're going to download the zip file and then we're going to open it up inside of a folder. So once you've done that, open it up in a tool like Visual Studio Code. Now if you use an editor like Code or Atom or WebStorm, these things are going to automatically give you a lot of cool features. For example, inside of the vehicle-list.component, which is in the app, vehicles, vehicle-list folder, we can now hover over different things and we get a little bit of IntelliSense. So for example, when I click on top of this vehicle-list.component with the Command key or the Windows key and I hover, I can see the implementation of this class. Well it's even more helpful if I do something like this, alright there's a VehicleService, if I hover over that now I can look inside that other file, and if I click on it while holding the Command, it'll actually take me to that file. So I can navigate back and forth just like any editor would do and there's a lot of cool features here. Now one of the nice things about implementing interfaces like the OnInit is it helps us do things the proper way. Notice that we're in the constructor, we're just injecting things, we're getting our filterService, we're getting our vehicleService, but we're not running any code. There's nothing between these two little curly braces on line 24. So how's the data getting there? We're implementing OnInit and we're using the ngOnInit function right here. So it's going through and doing our startup logic for the page, doing a little DOM interaction. It's going to get our vehicles and when there's a subscription back, which we'll learn about subscriptions and RxJS in the upcoming chapter. We can go get our vehicles and return them. And then we get those vehicles and it's going to load them onto our page, here's our local getVehicles function. So ngOnInit is allowing us to have a moment in time when the component is ready to receive information and do something with it. And we'll use the ngOnInit pattern for getting data in a lot of our different components. For example, if we go look at the vehicle.component right down here, we can see that there we also have a constructor and the constructor is injecting all these different services. We're implementing different interfaces up top and if we slide on down, we can see there's an ngOnInit, which is going to go get the particular vehicle that we need for whatever parameter was passed in. It's a widespread pattern with Angular 2 to do because it allows us to capture a moment in time with ngOnInit where we can use this to get the data or do something we need for that component.
Summary
We just saw a demo how we put together all the services, the DI, and the lifecycle hooks in our storyline tracker application. All these features really help us build out a robust application and the services and DI especially help us make it more reusable. We learned a lot of things in this chapter, we learned about how to separate things with services, so we can get our character data in multiple different places, but we don't have to worry about duplicating that logic, or any of the instances because we're sharing those too. And the cool thing about dependency injection is that we just have to ask Angular for it. As long as we register the services with the providers, then the injector knows about them and then we can inject them with constructors. And of course, if we want to tap in at any moment in time, like when we're creating a component or it's going away, but whenever any changes happen we can tap into the components lifecycle where we can perform any logic we need to and be guaranteed they're going to run exactly when we need them.
Routing and HTTP
Getting Data with Http
While building components and services are central to Angular applications, the app wouldn't be very useful without data and we often get data from remote sources through asynchronous communication. In this module we'll learn how to connect with the server to get data using http. We'll see how to do this with promises and with observables using reactive extensions. We'll kick things off by taking a look at how we use http now in Angular 2 and see how it differed from Angular 1. Then we'll explore observables and subscriptions and how we use those with reactive extensions, and you may remember we covered pipes earlier, there's a special one though called async, and we're going to take advantage of this one here with the new things that we learn and how to get data from http. And if you used Angular 1, you definitely took advantage of promises, so we'll take a look at how you can use promises in Angular 2 as well. Our storyline tracker app needs data and in this module we'll learn how to use http to do that.
Http
We are definitely going to need to get and send data over http for our storyline tracker app. Well let's learn how that works with Angular 2. We will need http for our gets, posts, puts, and deletes. Now we could use either promises or observables with RxJS and we're going to learn about both of these in this chapter. First let's take a look at where we came from with Angular 1 and how this compares to Angular 2. And you'll be happy to know, either way, when we want to do a get, it's very similar. We have a service called http in Angular 1 with a dollar sign in front of it and in Angular 2 it just lacks the dollar sign. So we go ahead and get http.get, we pass in the URL, and the difference is actually in how it's returned. We can return a promise if we want to with Angular 2, but by default we get back an RxJS observable. Before we actually execute the http calls, let's learn how we establish our project with what we need to use http. First we need to pull in the provider. Why? Because http is just a service like we use any other service in the application and when we use a service we need to provide it to Angular. So we have to give Angular the http service and it's actually contained within an HttpModule. So we do that right here. We go get the imported module, http, from the ES6 module that Angular exposes, and then we import it into our NgModule. Now our application knows about it. Next we define a service. We can go create a vehicle service and instead of hard coding the list of vehicles or characters like we've done earlier, now we can actually take advantage of it back end. Here we make our call for http.get against an API for vehicles, and then we're going to map this observable response so we get out the data that we need because we get back a response and the response isn't just the data, it's got other stuff in it. In this case the response has a JSON function which is going to then give us the data in JSON format and we're going to dive into there and get a data property. And of course we want to handle any errors. I recommend you always, always have an error handler on all http calls. Alright once we have our service, now we have to listen to it. So we might have a component, like a vehicle-list.component here, and we inject our vehicleService. Now notice he doesn't inject http because the service is doing that, it's handling all the http calls for us. Now in the component we just get back our raw set of vehicles. So we need to subscribe to the observable that is exposed by the service. The component's handed that observable, right here, and we subscribe to it using the subscribe function. And then inside of there we pull out the vehicles that we need, and we can also display an error if we want to, maybe put it on the screen for the user, we could do some logging, pretty much whatever your user experience team wants you to do with it. Now we just showed the code and how to make all this work, but let's review because these are important three steps. First we need to make sure that we import the HttpModule and we'll do that in our app root. That way all of our services in the application can use it. And then we call http.get in a service and return that mapped result. Finally somebody's going to have to subscribe to that, probably in a component, we'll subscribe to that result from the service and then do what we want to do with that data. Well it's time for a demo. Let's go ahead and code up some http in one of our examples.
Using Http in Angular 2
Let's take a look at our demo application and slide on down to Needs Http, number 20. Before you click on that, this is the one where we're going to add http to the app. If you want to see the completed solution, click on number 21 and you can just follow along. But I'm going to click on 20. We're going to open this guy up and right now we've got a list of fighters, basically the X-Wing, B-Wing, and Y-Wing from our vehicles-list.component. And those are all coming in from a service. So let's move this over to the right and we can see our vehicleService is being injected and we're getting it back synchronously. We'll go back to the VehicleService now and there it is. We don't actually want to get them like that though, so we'll comment that out. Let's change some things up. We'll kill the preview for now. Now first we said we want to use http, so let's import http and the response from the Angular ES module, for angular/http. Now we've imported that module here, we're going to inject it into our constructor for the VehicleService. So we have to add a constructor because we didn't have one yet and we'll create that right there. We'll make it private lowercase http variable of type Http. Once we have that, now we can call http and we need to have a place to call to. For ease of use in Plunker I've got this vehicles.json file right here. So we're going to call that. So back in this guy we're going to say return this.http.get and then we need to pass to it the API call. So mine's going to be API as a folder and then vehicles.json. If you have a backend like ASP.NET Core or Node Serve, NGINX or Java, you could just point to wherever that backend happens to be. Now once we get that response we're not quite done because we could return this to our components, but we should really shape the data up and make sure we got what we need. So we're going to use a function called map, we're getting back an observable, we're going to map in the response and that's of type Response, and we're going to use a lambda here, this is just a function that returns something. We want it to return a list of vehicles, so it's going to be a vehicle array and it's going to be the response.json. So we're going into the response, we're using its JSON function to get the JSON out, and we're going to go get the data object out of there and then we're going to cast that into a vehicle array. And then we can end our command. Now looking inside vehicles we can see there's a data property right there, that's how we said data. So now our service has what it needs to handle getting the data from a backend and vehicle is right here, we have our model defined on line 4, 5, and 6. We've got a response and our http that we injected in the constructor and they're imported up at the top of the page as well. Now before we could use our vehicleService we had to provide it to our application, so we flip over to our AppModule and we can see it right there on line 17. Perfect. But we're also using http now, where is that coming from? If we flip back into the vehicle.service we can see we're asking for it on line 10, but right now the way it's written, Angular is going to say I don't know what that is. In fact, let's just see what happens over here if we run it and we look at the error messages. Right now it's telling us, um we've got a problem. The application component is caused by no provider for http. Yes, exactly. We need to provide it. So I'll go back into the AppModule and let's do that. This looks like a good place, up at the top of the page let's go get the HttpModule and we're going to get that from, there's a nice convention for these, it's going to be http just like that. You can see all these things are in @angular/ and then the submodule. Now what do we do with it once we pull that reference in? We have to import it inside of our imports list for the NgModule. So we'll stick it right there at the end, I happen to like to alphabetize them, makes it easier to find. Now once we have http, it's actually going to make that call. We still have a problem because our component isn't hooked up to talk to our service using the observable yet. So it shouldn't run quite yet, but let's check out the error, we should get a different error message this time. Alright so now our error message is this.http.get...map is not a function. That's true. What happened to the map? Well if we flip back over to our vehicle.service, we used this map function, that is a function that RxJS helps us with. So how do we use that function? One way to do that is to import it directly from RxJS. So we're going to import everything inside of RxJS, don't worry, not the whole library. We're going to go specifically into add/operator, and then we're going to look for map. So we're going to pull out just that one operator. Now let's run it again, make sure we've got what we need. We're going to get a different error message this time. This time after the map error message we slide on down and now we're seeing that we have an issue where the NgFor is only supporting binding to iterables such as arrays. This problem was happening inside of our component. We can see that right here, the vehicle-list.component. That's because we're returning an observable from here on line 16 back to our vehicle-list.component and this guy is expecting a synchronous array, well that's not what we're getting. So let's change this line up. We'll comment out that out so we can see it side by side. We're still going to go out and call the vehicleService, like that, and it's still called getVehicles. That part didn't change. But now we need to subscribe to this. And the subscribe is going to return to us different things that we can operate on, and the first one is going to be, okay if it works, what do you want to do? Here's the function that you insert and handle. We're going to get a parameter called vehicles and we're going to pass it in and set our local instance of vehicles to that. Now we could have called this v and that v as well, but I like to make it more explicit to make it easier to read. So here our subscriber is saying got get the vehicles and set those for me please. Now the reason that we have this subscribe in here is because we're returning back an observable, and make sure you don't say vehciles, like I did there. We get that observable back and we're subscribing to the response and it's taking a function where the parameter is vehicles and we're setting our local this.vehicles equal to that. Now if we run our application let's see what happens. Here's our demo, and there's our list. Perfecto.
Adding Exception Handling for Http
Our code is only as good as our error handling, right? So down here we have no error handling so we should add in a catch statement. So we'll do that and we're going to call local function to handle that error, just to make it a little bit cleaner, and then we'll make a private local function down here and it's going to accept a parameter for the error, that's of type Response, which we already have imported on line 2, and then we're going to console out the error message and we're going to use a message variable, and we're going to go grab that error message object now. So we're going to say let msg and we're going to use template strings, those are back ticks, not quotes, and first we're going to say although what's the error message? Status coe is going to be what? We're going to use this replacement for error.status and we're going to say it's on URL of what? And here we're going to use error.url. Both those are properties inside of the error object. Great and for right now we're going to do that and we have to do to handle it even more down here. But there's some clean up we have to do. For example, right now we're using the catch statement right there, but we're not pulling it in from RxJS, that's another operator. So we've got to pull that add/operator/catch into our code as well. So now we've got our catch, we've got handle error, we're just console erroring the message out and let's go ahead and put something in here like a bunch of X's before vehicle, let's open up our developer tools and we'll run the live preview. Now let's see what kind of an error message we get. Should be consoling out to our station here. So we scroll up a little bit, status code 404 on URL and here's the Plunker URL at the end of it with all those X's vehicles.json. So still not great, but now we know how to get the information out. So the next step is what do we do with it? Well remember the caller is expecting an observable. One common mistake is to do this and then after this line 23 we console out, we don't actually do anything after it. But the problem is the component is going to get back nothing and it's not even observable at this point really. So what we want to do is return back an Observable.throw, and we're going to send the same message back. Now to do this, we don't yet have the observable symbol so we're going to pull that out up here, out of RxJS, and that's going to use destructuring to pull it out of RxJS, and on the Observable we're chaining the throw message, so that one's going to need to go get the throw. So here we're going to add in not operator, but observable/throw. So we're pulling in just the pieces of Rx that we want. Now there's a couple of lines of code to do that through lines 4 through 7, really 4, 5, and 7, but the nice thing about this is we're not pulling in all of RxJS, we're just pulling in the pieces that we want to use, which will make our size of our app a little bit smaller. So now our application is returning that observable/throw. So what do we do with that? Remember back inside of our component over here, vehicle-list.component, we had a subscribe. Well the first parameter of subscribe is what happens if it works and the second parameter is, yeah you guessed it, what happens if it doesn't work? So we're going to get an error object back, that error parameter right there is the response from this observable.throw, so we can get to that message. So let's take that and do something with it. Here we happen to have an errorMessage property, which is up on line 12, which is a string, that we can show on the page. So we'll just say it's of type any and it's an error because we don't really know what we're getting back in this case. So now if we run the application and we get an error because we still have a bad URL, we're looking at the error URL on the screen, which is a little bit easier. Now obviously you don't want to display this exact thing to your user, but this gives you an idea of how you can flow errors back through your application and then do something with them in the component level. I recommend logging them at the service level and then at the UI level making the choice of either do you retry or do you show it to the user or what do you do at that point?
RxJs
We were just dabbling in the world of RxJS with our Angular code, but what exactly were we doing and how does it work? Well RxJS is not part of Angular, but it's something that's widely used throughout Angular 2. And it's pretty darn cool actually. You can learn more about it at this reactiveex.io website and there's Rx for many different languages, this is RxJS, but there's one for .NET, for Swift, for Java, and so on. So you can learn more about those other languages too. What it really does for us is it implements an asynchronous observable pattern and yeah we can do the same kind of thing with promises if all we want to do is just go get a value and then find out what happens when it comes back, but RxJS adds more to it, as we started to get a glimpse of when we saw the mapping and the catching and throwing. One way to get RxJS was to go get just the individual operators that we had, another way to do it is to import all of RxJS. Now that's one way of going, but then you're going to get everything that it's got and when you actually go to bundle and deploy, that's going to be a lot, a lot, a lot of code, right? Because it's a large library. So for production you only want to import the modules that you require, like we did in the demo previously. So here's the technique I like to do. I usually create app.module.ts anyway and inside of there I'll import this file, rxjs-extensions, it's a file I create, and then I'll go in that file and I'll import all the different RxJS operators that I need to pull in. So this way I'm preferring to only import the things I'm actually going to use and I get the smallest possible payload when I bundle and deploy my application. So our catch and our map, those were things we had earlier and we also had the throw, which came out of RxJS at observable. You can put any of the ones you want in here. Another way of going is what we did in the demo where we just did each one of the ones that we needed inside of the service that used them themselves. So really, it's just your preference. But how does RxJS operate? In RxJS you're going to define an observable and that observable is going to have different people listening to it. In this case maybe the RxJS observable is going to be something that delivers a message of here's your data, and then the other guys, over here on the right, are people subscribing or listening to that observable, and it doesn't just have to be data, it could be some kind of a messaging system where you're saying somebody logged out so you want to let other people know in your application that that log out occurred so those components can react to it. Alright so that message just happened, when those pipelines are there, those pipelines allow those guys to subscribe to the observable and then when a new event occurs the observable gets it and that subscription is sent to all of the listeners, the subscribers. Now this is an eventing system so each one of those subscribers needs to basically unsubscribe later. The great thing about the http object, the service that Angular gives us, is when it gives us back the observable, it'll automatically unsubscribe when it's done. So we don't have to worry about cleaning up that particular one. If we create a manual observable and subscription, then we're going to have to clean up our own subscriptions. We'll take a look at that a little later too. So we mentioned http, let's take a look again and what we did. We used http.get to go off and get our data and we mapped back the response, that was part of the observable we have. We don't return the response it, we return the JSON that came out of it. The service does all the work and the consumer simply gets whatever data we wanted. This is our chance in the map to take that data and basically manipulate it and massage it a little bit and bring it back to our components. Let's not forget about exception handling. So here we've got our map, we also have a catch, which calls a local function, it does some work for us to gather the information, and then we'll pass some of that information back to the component to the consumer for some presentation. So what about that component? Well that guy is listening, right? He's the one subscribing to the observable and he uses that subscribe function to do it. And then we use the vehicles and then the error parameters for both the success and the failure functions to handle those different cases. And these are the basics of using RxJS with Angular 2 and http.
Async Pipe
We learned about pipes in a previous chapter, but we didn't learn too much about the async pipe. And this one works really well with promises or observables. Let's take a look. The Angular async pipe is a remarkable example of how you can receive a promise or observable as input and then subscribe to the input automatically. Eventually it's going to return the values. So as values change and come back through the pipeline, you're going to see them on the screen. Now the cool part is, if you want to use a pipe and take the existing code we had, very little has to change. First our service stays exactly the way it was, which is cool because now our service just emits an observable and in our component, instead of writing the code to handle that observable, we just get an observable and return it to the screen. Wait, how do we do that? So here instead of having vehicles of type vehicle array, it's going to be an observable of vehicle array. So we're going to grab the observable and set it to a local property, and then we're going to bind that property to the screen. So the component is simplified, there's less code here. So what changes in the template? Very simply we add the pipe up there and we say async, and that will subscribe to the vehicles and return the stream right to the template. The async pipe is a self cleaning pipe, async will automatically unsubscribe to the observable when the template goes away. Well let's take a look at our existing example and add an async pipe to it and show the differences.
Adding an Async Pipe with an Observable
It's time for us to go play with some pipes, so we go down in our demo here, we can see that we've got 21 that's Http and then 22 is the completed example with the pipe already in it. So if you want to look at the complete one, go to 22, but we're going to add together on line 21 here, the http example, we're going to add the async pipe to it. So I'll go into this guy, he's already getting back a list, we're good to go, and he's got a service, which is returning back our observable. Perfect. Let's go inside the vehicle list because that's what we're going to change this pipe. We'll just pull the preview over for now, and first we know that if we're getting back an async pipe we don't need to process and subscribe like this inside of here, so I'll comment that out just to show what it looks like, and instead of calling that and then doing a subscribe, instead we'll set that equal to vehicles, like that. Now we've got vehicles, but right now the vehicles is an array of vehicles, we don't want that. We want an observable of vehicle array. And because we're referencing observable now, we have to come back up to the top and import that from Rx, so we'll pull that observable from rxjs/Observable. Now we've got an observable coming out of our service and we remove those four lines of code, so let's go into the template itself and up top here we can see we're getting a vehicles list and we're going to say async like that, after the pipe character. And now you can see we've got an Imperial Star Destroyer. You might be wondering though, what about error messages, if something happens? Well we can still go back inside our vehicle-list.component and we can put a catch on here, and then handle the error. So we can chain the catch off of this with no problem. And we can see with the async pipe it makes it a little bit easier to flow the data from the service through the component up to the template.
Promises with Http and the Async Pipe
Well it's time to take a look at how we use promises instead of observables, because that's just another option we have. So let's flip back to our demos, and inside of our demos we can see we've got the Http example in 21 and the Http with Async Pipe on 22, well 23 is completed with Http and Promises and let's click on that one and see how the differences are. Now our service over here, for the same kind of application, looks slightly different, and in that sense what it's doing is we're saying return http.get, we're still mapping it, but there's one extra line, line 16, toPromise. So we're going toPromise instead of returning an observable. Now because we're using toPromise here, we have to make sure that our Rx extensions is actually pulling in toPromise, right there on line 6 of the Rx extensions file. So we've got that. He's returning a promise, let's check out what the component does with that promise. Now we have two options here, just like with observables, we could take the observable and stream it up to the template using the async pipe, which is what we're doing here, or we could do a .then. So let's use the async pipe here. We've got the this vehicles equal to our promise now. So line 19 sets the vehicles to a promise, it means line 14 has to change to be a promise of vehicle array and then we have to make sure that we're good to go with this vehicles list by looking inside the component, and notice it's exactly the same code up here. The async pipe on line 2 can handle a promise or an observable. Now if we wanted to use a promise and not the async pipe, we would remove that async here, go back to our component, don't make it be a promise, just make it be a vehicle array, like that, but now we couldn't do this line of code, instead what we'd have to do is type in, although go get our vehicles, and then with a then, we have a function here where we pass in our response for vehicles and then we could set the vehicles inside of this call back. Then we could also do a catch statement here too. Just kind of similar like to what we did with the observable here. But the async pipe makes it a little bit simpler to do. So what does all this mean? It means that we have options and options are pretty good. We can use observables or promises and we can use it in code or we can use the async pipe.
Http in the Storyline Tracker
Well let's take a look now how we put all these things together inside of the storyline tracker using the async pipe and the observables. Flipping over to our example demos, if you haven't done so already, once you open the storyline tracker, you can click on this little cloud with the arrow on it to download the file or directory and then it pulls down a zip file. And then you can take that file and you can open it up inside of a folder. If you'd like to follow along inside of the Plunker, that's fine too. But I'm going to open it up inside of Visual Studio Code. So first let's take a look at the vehicleService, if you can't find that go ahead and hit Command+P and you can type in vehicle and then you can type in part of the word, like type veh.ser, like this, it'll actually pattern match it, you can find the vehicleService. Scrolling down we can see we've got a getVehicles and we've got a getVehicle and then we've got an updateVehicle, we've got delete as well and we've got an add. All of these actions are in here for handling our http requests, and you can see right here on line 42 we're actually going off and calling http and we're getting the vehicles by URL, we're mapping the response, we're handling an error, and then we're hiding a spinner with a finally at the end. The map, the catch, and the finally are all different functions we can operate on the observable. So notice we're returning an observable of vehicle array on line 42. The point of this is we're going to do something with that observable and that's going to be handled in the component. So let's go look at the vehicle-list.component. We can either navigate there over on the left to the vehicle-list or, again, we can hit Command+P up top and then we can type in vehicle and maybe type in list, like that. Now we find the vehicle-list and we can see on line 30 we've got a getVehicles function. He's calling the vehicleService getVehicles and then he's subscribing to it, taking that response, and then manipulating it and then showing it on the screen so that this.vehicles on line 34, that's getting set, is a property of this class and that property is set right up here on line 18, and that's bound in the template. Well there's another way that we can handle these, right? This is not using the async pipe, but we do have a place that does that. Let's go check out our characterService and that service, if we go up and look for him, it's going to be character.ser, he also has an add and a delete and a getCharacters. Same kind of code we had with the vehicles, and how's that going to be handed in the character-list.component? Let's go find out. If we type in car list and then we go look at that guy, he also has a characters array here and he's going to pull them out by subscribing to them, but characters are used by more than one screen. There's the character screen and there's also the dashboard. So let's go find the dashboard component and the dashboard component, notice on line 18 we have a characters property and that's an observable of character array, so down in getCharacters, we're just setting this characters to the getCharacters function, and then we're using a do on there that's a side effect that we can use to say okay, show up the toaster and then we can handle any errors here, but what's nice about this is it looks a little more straightforward, looks as little less asynchronous in a way, so we're just saying take this property and set it to the response of this, which is going to be an observable of character array, and then our template for dashboard HTML, we can go see the async right there on line 6, so we say let character of characters pipe async. And that's going to pull the observable in and every time we get the data back from that service to the component, it's going to stream it up to the view. So here are a couple different examples of how we're using observables with and without the async pipe in the storyline tracker.
Putting It All Together
We learned quite a bit this chapter on how to get our data for the storyline tracker app. We pulled in characters and vehicles using http. Let's look back at how we used http because we got that library, we pulled it in, and we imported it, we told ourselves about the http providers, but then we had to use observables and subscribe to them. When we use http.get we get back an observable and then we subscribe to that inside of our component. But we also have the option of just linking an async pipe directly to it. So we tried that too and that make our code a little bit cleaner. And for when we want to use a promise, we can also use that from http.gets as well by just doing the toPromise method. And by using what we learned about http in this chapter, we no longer have to rely on getting hard coded values for vehicles and characters, we can go call API for that and we also have additional power because we're not just getting data, we're putting and posting and deleting our characters and vehicles, which lets us build a more robust app.
Routing
Introducing Routing
The storyline tracker has a dashboard, vehicles, characters, and a series of detail views. We need a way to get from one view to another. Routing is that vehicle. This module is going to show how to configure routing, which is going to enable us to navigate between our vehicle and character components. So we'll define our routes and we're going to use a concept called routing modules to hold those routes. Sometimes we need to be able to pass parameters from one place to the other, we'll learn how we can do that through routing. And sometimes we want to stop certain routes from happening, those things are called guards inside of Angular. We can inspect the route at a key moment in time, right before it's about to transition, to either get some data to inject inside of its destination or to check a certain value, maybe if you're authorized or not, and then prevent the route or let it continue onward. We'll learn about all these concepts and much more in this chapter on routing.
Routing Essentials
Angular allows us to navigate between viewing component pairs with a router. Routing is how we allow the users to navigate from one point to another. Let's take a look at how routing compares from Angular 1 to Angular 2. In Angular 1 we used a routeProvider object, which had a when function. In Angular 2 it's a little bit simplified, we just have a Routes object, and we'll use that to define our configuration for our paths, when I see this URL, go here. In Angular 1 we had an ng-view element, which is where we would place the destination of the route, so when that thing that we're going to show, the view in the component, shows up in the screen, the ng-view's be the placeholder for it. Angular 2, it's now called a router-outlet. Where we used to use ng-href in Angular 1 to define the link to go to a route, in Angular 2 we have a routerLink directive and we use that with the property binding, with the square brackets. If we want to access routing parameters, in Angular 1 we use routeParams and in Angular 2 we use the ActivatedRoute object. And of course we had a router object in Angular 1 and we still have a Router object in Angular 2. So as you can see, some of the names have changed, but the basic concepts of routing are still here and there's actually a few new features too, and we'll learn about those as this chapter progresses. But first, let's talk about the things we need to get started. In our index.html, we want to make sure that we've got a base href of slash, that base element is really important for routing to work. And there's five basic steps to routing. The first step is going to be the import the RouterModule, just like we had in HttpModule and a FormsModule, we have a RouterModule. And we'll pull that into our project and then when we want to do things with routing, to get that routes object, for example, we're going to go ahead and import from the ES6 module angular/router. Of course to have routes we need to define that. That's going to be our configuration that we set up with paths that lead to components. And where does our route go? For that we're going to need to declare a router-outlet somewhere on our page. Those routes we defined in step 3 are going to have to go somewhere. They're going to show up in the router-outlet, and if we want to create like a menu somewhere for the application, a great idea for that would be to use the routerLink bindings. By following these five steps, we can get routing going pretty quickly.
Essential Routing Code
Let's begin by taking a look at the code that we're going to need to get routing moving in our application. First we'll define a file called app-routing.module. Now that's going to match the app.module file. Effectively these are the routes for our root of our application and in here we're going to pull in the RouterModule from the angular/router ES6 module, that's going to give us access to all the routing things that we're going to want to use. The first of which is the routes object itself. And we'll use that to declare our routes. And how do we do that? In the same file here, the app-routing.module, we're going to define that list of routes with a path and then where does that path lead. So we define the path, the first one in this case happens to be blank, that's the default path, and we're going to tell it to redirect to characters path. So if we go to blank or we go to characters, we're going to end up at the character-list.component. We can also use a colon to identify parameters and the key here is notice that all these paths end up leading to a component, that's our destination. Then we'll define our own module and I'm going to call it app-routing.module because it's for our app root, and we're going to import in that RouterModule and we're going to use this function called forRoot and we're going to pass to it the routes that we just configured. So we're using the module that comes out of Angular and basically injecting those routes into it. And we're wrapping it up into our own class called AppRoutingModule. This makes it easier for us to use the routing in our own module, such as our AppModule. Be sure that you only use this forRoot function in the root module's routes though, that's why it's called forRoot. In our case our root module is the AppModule. Well let's look at the stuff we just did. We have our list of routes, these are our paths, and we configure them all up, now they're inside of this routes variable. Then we use the route to make an NgModule. We pass those routes in to the RouterModule.forRoot and we're really paying attention to this AppRoutingModule we create. Now as a convenience I like to actually export the component list that I'm going to use and I'm going to have to declare it in my main module, it just makes it easier so I have less of those ES6 import statements in all my files. Now after I'm done with this file I'm going to be exporting two things, the AppRoutingModule and my routable components and then something else, as you might have guessed, is going to import those. That's going to be our app root module. So we're going to define this routing module and then import it in the that app root module. We could also do it into a feature module and we'll learn more about that in the next chapter. But for now, we're going to have one module still, the app root. So how does that look? In our app.module.ts I have my standard stuff as always and I also have this import statement up top that's going to import in my AppRoutingModule that I just created and my routable components, then I'm going to pass the AppRoutingModule as a parameter to the imports array. This gives my app module, my application if you will, access to the routing features that Angular provides and the routes that I have configured. And notice that I have routable components in here in the declarations. Remember we have to declare any component we use, this was just a nice easy way to pass them along to give to the app module. If I didn't export those in the previous file, I'd have to reimport them and then list them in the declarations one by one. So this was just a convenience feature. Once we have the code set up we want to work on how we put routing in our templates. First we might want some kind of a menu, so let's say in app.component.html we've got this navigation section and we can set up these routerLink directives. We'll use data binding with them and one will go to characters and one will go to vehicles. That routerLink is going to help us navigate to the path and then we'll pas to it the link parameters and those link parameters are an array which contain the different parameters for the different route. In this case, the route that I'm going to is going to be called /vehicle and that gets matched against the path. When somebody clicks on one of these hyperlinks here, it's going to activate the router link and then it'll go and look for the router-outlet and that's going to define where I put my components. Now that we've learned how to do routing, let's go take a look at it in our sample applications.
Adding the Routing Module to an App
Let's take a look at our sample applications, we'll slide on down to number 25, Router. This is going to show us how routing application works. We're going to build this in just a moment. So here in our app we've got a list of characters and a list of vehicles. If I click on vehicles I can see them and characters and I can also click on an individual character and go look at details. All the different components are already in my application. Now let's close those two samples and we'll click on the Needs Router, number 24. We'll open that sample up. This one doesn't have any routing in it yet, but it has the same components, as we can see here. Let's close down the preview so we can type for a little while, and let's go add a new file. We mentioned that we have to add in this new file earlier called app-routing.module. So I'll add that alongside the app module. Now let's click inside of here, we'll start by importing NgModule because we're going to create our own NgModule for the routing and that comes out of Angular Core, just like we've done before. And we'll pull in the routing features. So I'll import Routes and RouterModule. That's going to give us access to those different features. Now let's go ahead and create a constant called routes and we'll define it of type Routes object and that's going to be an array. This is where we're going to put our own custom routes. Each one of these is going to take an object, we're going to give it a path. Now let's think about it like this, the path is when you see blank, what do you want? Well I want to make sure their path matching everything because in a blank it could be, anything could start with a blank, right? So we're going to do full. So it's going to have to match that exactly and then redirectTo in this case a new route. I really don't want to name a route that's called blank, so instead I'm just going to make the blank route, basically the slash for my application, go somewhere else. I'm going to make it go to a route called characters. Perfect. So the next one that would make sense to create is the path for characters, otherwise we're not going to be redirecting anywhere, are we? And when it gets there, we're going to say go ahead and find a component called CharacterListComponent. Now I just told it to go to a place that I haven't imported yet. So now I have to go import that CharacterListComponent. So I'll import that guy and I have to know where to get it from. Well in our application it's in the characters folder and it's right here. So let's go ahead and type that in, we'll do ./ to do a relative path, it's under characters/character-list.component. Make sure we got the name matched up and we are good to go. Now we have a few more paths we want. We also want to go to vehicles, so we'll copy and paste this one here and we'll say alright make the path vehicles, and this time we'll call it VehicleListComponent, and then up here we'll copy and paste and we'll go get the VehicleListComponent out of that folder. Now our vehicles also has a parameter for vehicle, which is a vehicle detail page right here, so we could get that one in there as well if you'd like to. We'll go ahead and add it for now. We'll copy the vehicles again and this time we want to say when you go to vehicles/id, don't go to VehicleListComponent, but go to the VehicleComponent. So yet again we're going to go create another import up top and this time it's going to get the VehicleComponent. Perfect. Now that we have our routes, let's create our NgModule. So we're going to export a class and it's going to be called AppRoutingModule. Why did I pick that name? Well I picked that name because it is the name of the file, but also because I have an app module right here. So this is the app module's AppRoutingModule. And I'm going to decorate that class with my NgModule, like this. And inside of there, one of the properties is imports and the other one is exports. Now we want to import the RouterModule, that gives us the features for the routing that Angular provides and we want to tell it go ahead and use the routes that we just defined right here. And we also want to export to expose the routing features to whoever imports it. In this case the guy who's going to import this AppRoutingModule is right over here, we want him to be able to access the RouterModule. So we have our exported class and next, so I don't have to copy these three import statements here and then also declare them in the app module, instead I'm going to create an export of a constant here called routableComponents, this is just a convention that I like to use. We could, by all means, just copy and paste those, and then I'm going to say okay put the CharacterListComponent here, the VehicleListComponent, and then the VehicleComponent. Great. We now have an AppRoutingModule. Now let's go over to our app module, we're going to need to import that file, so let's come down to the bottom of this import list and we need to pull in the things that we just exported from the other file. Well those are going to be the AppRoutingModule, that was the one we defined, and then the routablecomponents, and we have to tell it where to get those from, and that's going to be a relative path, it's going to be our app-routing.module. Once we have those, we need to import this AppRoutingModule into the NgModule down here. So I'm going to put that last in my list. If you'd like we can separate these out, make them a little bit more readable. It makes it longer, but a little bit more readable. And then where does this routableComponents go? Well those are just other components that we could use in our application. Now right now we've already imported CharacterList, VehicleList and VehicleComponent, I'm going to delete those and do this instead. Yes I could have left them there, but look what I can do up top now. I no longer need to import that line, this line or that line. Those three components up top were part of the routing, so I don't need to import them in two different files. It just kind of cleans up my code a little bit. Okay, now my app module is pulling in the AppRoutingModule, it's declaring the routable components, so all those components are there, and then it's going into my AppRoutingModule and defining these different routes, all that gets set up with what we just did. Let's take this opportunity to look over our code. We did a lot of stuff here, we're importing NgModule from Angular Core and Routes and RouterModule, well they actually come from angular/router, so we should type that in here at the end of line 2. That was a typo I had. And now let's make sure we've got the CharacterList, VehicleList and VehicleComponent in the right files. I have a tendency, as you've noticed, to type in vehcile, so that's actually vehicle right here. The important part is to make sure it matches up with whatever you put your paths. So those three components are going to be used for the destinations of the route. And then we have our four routes, the default route, which will go to characters, and then vehicles and vehicles/id. And we have the CharacterList, VehicleList, and VehicleComponent, those three different paths. Next up, we create our AppRoutingModule class and we import in the router module and its routes and we export the router and then we created a simple array of routable components that we're exporting. Back inside of app module, we import the AppRoutingModule and the routable components on line 11. We no longer needed the declarations to be imported for those components, instead we just imported the routable components and used it on line 21. We defined the import for the AppRoutingModule on line 17 and our app module is good to go. If you're typing along with me, go ahead and take this moment to catch up and then we'll move on to how we get them into the templates.
Adding Routing to Templates
Now that we've added the routing code to our app, let's have a place for it to show up inside of our templates. Go ahead and open up the app.component.html and in this section right here we're going to add a router-outlet, just like this, and that'll be where our templates are shown when we route to them. Well how do we route to them? Let's add some navigation for that. We'll create a nav tag and inside of there a ul, and then we'll create one li first with an a and then inside of the anchor tag we will create a routerLink directive right there, and we're going to do data binding on this, so we learned earlier that we use that with these square brackets, then a double quote here and inside of the double quote is going to be an array and inside of that array the first element is going to be the path we want to match it to. So this will be characters. So make sure you've got all your quotes in the right places, we've got a quote around the value, which is an array, and that array has a string of /characters, and that's got to match what we have back in our routing module for characters, for the redirectTo and the path from line 10. We're also going to need one for our vehicles in a moment. But first inside the a they have to have something to click on, so we'll make the menu item say characters. We'll then copy and paste it because that never gets us in trouble, right? And then we'll type in vehicles for the second path and Vehicles for the title. And then once we do that, we should be good. We can now just click on the preview and if everything worked out okay we should see our data shows up and both of our menu items. If I click on vehicles, we go to the vehicles, if I click on characters we go to characters. If you were coding along with me and it worked out, awesome. And if it didn't, you feel free to go back and try again or if you'd like you can go off and click on the Router number 25 example in our main demo app, it's the conclusion of what we just did.
Sending and Receiving Route Parameters
Now that we know the routing fundamentals, let's take a look at how we can define parameters. Inside of our routing module we already set up one parameter for the character ID. This is how we define a parameter, we use colon and then the value. Now once we set up that parameter, it's going to be interpreted by the router to say, okay if I see character/ then a value, it's going to mean go to this path and it'll go to that particular character component. But how do we pull the data back out once we get there? Well there's a couple of ways that we can get data to another component. One is by using the snapshot. This is the easiest as long as the parameter values aren't going to change. It's one line of code and it makes it easy to pull that value out in the destination component. Another option is to use an observable. This will get new parameter values whenever the component is reused, for example, let's say you had a character detail component and on there you wanted to navigate to another character detail component, well then you're actually activating the same component again. So you'd want a way to make sure that you can get that new value, the observable will be able to stream in the new values for you. It's a little bit more code, but it's a little more flexible. So snapshot is great if you're not going to go like detail to detail, because the parameters aren't going to change, the next you come into the detail component you'll probably go back out to a list, select it, and then come back in. But if you're going to go from detail to detail, the observable is really key. And there's also a third way, it's called using resolver. This is a way we can pass data to a route before the component is actually loaded. Let's explore these three. In the destination component, let's say it's a SessionComponent where we want to pull out the id that was pulled in as a parameter. We first inject the activated route. This is an object we can inject that's set up by pulling in that router module. We don't have to provide this particular one because this service comes with the router module. Once we have that, we can use that route object to go into the snapshot property and look for the parameter named id. As I said, this is the easiest way to get them. As long as that id isn't going to change while you're on the component, you're good. If the id is going to change, because we're going to go from a detail component to another detail, we could use observables, or if you just want to be safe. Here we go to the route.params because that's an observable, so we'll map the response. Now that parameter comes across as a string, so now I'm using the do to say, alright take that id, do a parseInt on it and put it into a number, this id. Now I've got it locally in my class and I can subscribe to any of the changes. So whenever these values change, if the id parameter does change, I'll be able to get it and it will go get the correct session for it. So we just learned how we can grab parameters using the snapshot technique or getting a string with them by using observables. Let's go take a look at our demo apps to see how that works.
Subscribing to Route Parameters
Let's go back to our demo application and click on the Router Completed example, and we'll take a look at where we have parameters in our application. When we click on vehicles we can see we've got the Millennium Falcon and then we click on that and we see the details for that Falcon. If we go back to vehicles, we click on X-Wing Fighter, we can see those details. Well let's look inside the vehicles folder and here on the vehicle component we're receiving a parameter. Notice on line 17 we're injecting the activated route, that activated route is how we're going to access the parameters. Notice line 26 inside of the ngOnInit is going to say alright look at that route, look at its parameters, and then we're going to map those parameter's id, and this is just a shortcut way to make it turn into a number, and then we're going to subscribe and when we get this value, when this comes through this pipeline, that stream, we're going to subscribe to it and then run getVehicle. And down on line 35 it'll call the getVehicle, passing in the id to the service and it'll come back out the other end and we set our vehicle locally. And the parameter name on line 28, id, has to match what we have in our routing module, right here on line 15, vehicles/:id. And that's how we set up routing parameters in our application.
Basics of Route Resolvers
Earlier we talked about a third way to pass data to a route, that third technique is using a resolver. Resolvers are a way to get data prior to navigating to the route. Let's take a look at how we define one of these resolvers. These are key for the scenarios where you want to get data before you actually go to the particular component. In this case my resolver is just a service and it's going to implement the resolve interface, which comes from the angular/router ES module. That interface says we must implement the resolve function and one of the parameters there is the route, which is the activated route snapshot. That will allow us to grab information about the parameters before actually going to the destination. And we can use that to call an existing service, like the Vehicle service to go get the vehicle and when it comes back, if it has a vehicle we can return it, if not we can create a new instance of it. We probably want to have some kind of error handling here as well because what if things go wrong? In that case, we'll head back to the vehicles list, or we could put an error message up for the user, it's really up to us. But here's our chance to inspect things in the midst of a routing action. Once we have this service, we can go ahead and implement it and apply it to the route. So inside of our route we add a resolve down here as a property of that route, so we had path and component, we take the resolve and now we specify the data values we want. They'll be an object called vehicle that we resolve to. So we define this inter route configuration and remember, if we're going to create a service called VehicleResolver, we still have to provide it somewhere, because that's how the dependency injection finds it. And we can define more than one of these if we want to. We could have a VehicleResolver and maybe another resolver too. Most often one is enough. And then the way you get that resolver data back inside of your component is to then take that activated route and then look at that data value. So we're going to subscribe to that and then we can grab the vehicle that we decided we wanted to pass in, that vehicle property is the one we defined in the route configuration and it's of type vehicle. Let's go take a look at our application and see where we can use resolver.
Route Resolver in the Storyline Tracker
The storyline tracker has several different routes in it. One of them is a vehicle-routing.module, and here we can see a path for parameter for id is going to go to a VehicleComponent and on line 23 through 25 we can see a resolver for the vehicle. This means that when they go to that id for the vehicle, we're going to go down to this vehicle.component and it's going to receive that value. So if we look inside of here for the ngOnInit, which is on line 67, we can scroll on down beyond the comments, which is explaining the resolver here, and we can see that we're getting the route and then it's data property and we're subscribing to it, and in there we're getting that data object with the vehicle. And then once we get that, we can then perform any local logic we need to do, like setting the local vehicle variable or grabbing the vehicle's id. Up above we can see some other ways we could have grabbed the values. If I wanted to pass a parameter we could have done so. For example, we could have used the snapshot, right here on line 73. That would have allowed us to pass the parameter, the difference between passing the parameter and the resolver is the parameter would have gotten to this page, it would have shown the page, and then we'd have to go get the data, so then the spinner that we could show up on the page would show up on the destination page while waiting for the data. The same thing with using the second technique here with the ActivatedRoute where we go ahead and use an observable and we subscribe to that to get the parameter value, we'd have to then go get the data as shown here on line 81. So when we use parameters, we have to go get the data after we get to the destination. With a resolver, we're waiting before we actually traverse to the destination. So it really depends what your user experience needs to be. If you want to get the data before you go on the route use a resolver, if you want to use it after, use a parameter.
Route Guards
When a user goes to our vehicles page or our characters page, maybe we want to check first to see if they've been logged into the system. For that we might want to block or at least inspect that route or guard it. That's where routing guards come into play. They allow us to make decisions at certain key points in that routing lifecycle and then we can either continue, we can abort that action or do something different. When we're at that moment where a user can navigate anywhere in an app at any time, that's not always the right thing that we want to do. Maybe the user isn't authorized, maybe they can't navigate to the target component because of that. Maybe the user must log in first. Maybe we need to fetch some data before we display it, like with using resolver. That's one type of guard, but there's other types too. For example, maybe we want to save some pending changes before we leave a component or at least ask the user if it's okay. Let's explore some of those different types of router guards. We've already learned about the resolve, we'll use that to pass some data into a target component. Another kind of a guard is a CanActivate guard. This one is one we can use to say do we want to go to that particular component. For example, we want to go to /characters, well before we do that maybe we want to make sure that they've been authenticated first. So we can use the CanActivate guard to check to see if authentication has occurred. If it has, let them continue. If not, we block them and maybe show an error message or reroute them to a login page. Like CanActivate, we also have a CanActivateChild. This is for child routes, which we'll talk about very soon. And maybe we're on a particular component, but we don't want the person to leave until that they've answered a question. For example, they might be editing a character, and maybe in the middle of editing that character, they try to leave. Well if the state is dirty, we can implement a CanDeactive guard to check that state and then ask the user, do you want to save these changes, cancel them, or what do you want to do? And then there's the CanLoad guard. This one's similar to the CanActivate where we get an opportunity to inspect some information, to check to see, for example, are you authenticated before you go to the destination, but unlike the CanActivate, the CanLoad will not even go get the contents, the HTML and the JavaScript, for that module that you're going to until it's been satisfied. This is really ideal for things when you do lazy loading, which we'll look at more in the next chapter. For now, we'll concentrate more on the other guards. Let's take a look at how we implement a CanActivate guard. Often we'll use this for an auth guard for authentication. Have you been authenticated yet? We'll implement the interface for CanActivate, which means all the function called CanActivate with the ActivatedRouteSnapshot and a RouterStateSnapshot, and then we'll either return true or false to let them either proceed with the route or to get out. Notice in this logic here, if the person isn't logged in, we're going to route them to the login page and then return false. So we're going to cancel the current route and introduce a new one. This allows us to really change the way the application behaves. Once we define the guard, we have to apply it. Here we've got a dashboard route and we're applying the CanActivate with the AuthGuard. Notice that it's an array that's because we could apply more than one guard if we wanted to. Now that we've learned about using routing guards, let's go check out an example in our demos.
Applying Route Guards
We'll go on down to number 26, Route Guards, and we'll click on View Sample. Here we're going to have two routes for vehicles and for characters once again, but now we've got a login as well, so we can authenticate. Notice the default route is characters and it's showing the login page. That's because we have a guard in place saying hey you're not authorized so we're redirecting the login. However, vehicles is allowing us free reign to come in, it's not guarded. And then of course we can go straight to login. The behavior we want is if you click on characters it should take you to login, but remember you wanted to go to characters, so after we login, which we're just delaying and doing a quick fake login, here we're going to then go back to the characters route. Let's take a look at how this guard is implemented on the characters and let's also apply it to vehicles. Now our routing is inside of the app-routing.module, we'll open that up, and notice that we have a route for characters and for vehicles. On the characters we're using CanActivate and CanActivateChild and we're putting the same AuthGuard on both of them. The guard for CanActivate on line 22 is making sure that if you go through characters, the main page, that it's going to guard it. The CanActivateChild is guarding the child pages. So if we try to do a deep link to one of those, it would guard one of them. But we're not guarding the vehicles at all. So one way we can handle the vehicles is just to put the guard on it. Let's go ahead and copy CanActivate right there on line 22 and let's put it inside of the vehicles, just like that. Now nobody can get to the vehicles directly. However, they can still get the vehicle's id. So we could put that guard here as well. Here's a case for why we might want to use child routes as well. Notice in the characters we have the characters route as the path of characters and then we set up two children. The first one goes to the blank path, which is CharacterList and the second one to an id for the CharacterComponent. By breaking this out into child routes, we can now take advantage of the CanActivateChild to guard all of the children. Because we didn't do that with the vehicles, we have to go ahead and make sure we're guarding the CanActivate for both specific routes. So if we had multiple child routes, this is really helpful in implementing the guards. We could just do a CanActivateChild. Well let's test this out real quick. If we press run, now when the app loads, again it's trying to go to characters so we try to log in, I can't go to vehicles either, I'm clicking on that, it's not happening. Once I log in though it goes right to the vehicles page and I can go back and forth between the two different places until I log back out again. Now how did this guard get applied? The guard is called CanActivateAuthGuard, it's really just a service, right. Well our AppModule down here happens to have a providers list and one of those happens to be our guard. So make sure that you provide your guards as well.
Child Routes
We just saw how we can guard different routes and got a sneak peek at child routes. Child routes are a great way to create hierarchical sets of routes. We took at look at some routing we had with characters and child routes. We defiend the URLs for those parent routes and then for the child. They get put together to create the end route. So above here that first path is characters and the second one would be character/72 if that happened to be the id. Let's step back and take a look at how this could look in an application. We might have a root route for our app and that might redirect to the dashboard route. So we could have one route for dashboard. We might have another one for vehicles and a third for characters. Well in what we just defined for those routes we could have characters/ and /id for 21 maybe, for a different character id for a list and a detail page. Those could be child routes for characters. And then vehicles could do the same thing. We saw this in the previous example and it was a very subtle, but important reminder in that last demo. Do you notice where we provided that guard that we showed? We did that in the module providers, that was our CanActivateAuthGuard. We did it in the root injector and the reason for this is if we're going to have a guard, it cannot be provided at a component level or a level lower than where it's going to be used. These guards are being used by the routing before they actually get to the component. So they had to be put into a provider of something a little bit higher level. Most often these guards will make sense in the root injector. Don't worry though, if we put it in the wrong place and Angular can't find our provider, it will give us that message of cannot find provider for CanActivateAuthGuard and that's a good hint that maybe you don't have it in the providers at all or it's not in the right level. In that case, just push it up to the root injector. Let's take a look at all the things we've learned about routing in the storyline tracker. The storyline tracker has a dashboard, characters, and vehicles. It's also got an admin area, but if we click on there, it's got that guard in there. This is where we've got the CanAuthGuard, which is on the CanActivate of the admin, which kind of makes sense in a real app, right. You don't want to get to an admin page unless you have permissions. Maybe you want to not let anybody get into anything until they have permission as well. So you can really manipulate how you want these guards to work. And then once I log in, I can then say okay you're good, go back to the admin page and do great things, and then you can go anywhere you want in the app. There's different kinds of guards too. We mentioned that we can have a CanDeactivate, so let's go inside of BB8 and let's change BB8 from the light side to the dark side. And before I press Save, let's just go back to the dashboard. When I try that it's saying, wait a minute - do you want to cancel your changes? Why do you think it asks us if we want to cancel the changes? Exactly, because there's a CanDeactivate guard on this route. Well let's hit Cancel and it's going to stay right here. If I hit the dashboard again and I go to OK, it's going to cancel the changes on me and go back to the dashboard. Now if I go back to the characters and BB8, he's still on the light side. Let's take a look at how this is implemented. Now where might this me in the code? Let's think about this. We have a characters route, so let's go check out the characters themselves, there's actually a routing module in there and we're going to learn more about how you can create nested routing modules in the next chapter, but for now we can see down here that on the characters child route we have an id on line 19 and then a CanDeactivateGuard on line 21. Perfect. I'll bet you there's the same kind of guard on the vehicles too. Let's go over to vehicles, we'll try the Millennium Flacon and we'll change this from space to land and then we'll click on characters and the same kind of question comes up. As you can see, guards can be extremely helpful for implementing different kinds of logic. I recommend that you tinker with the guards for this application to get a feel for how they can work in different scenarios.
What's Next with Routing
This chapter we learned quite a bit about routes. We started with the basics and then we showed how we can define different kinds of routes, then we defined the routing module, which encapsulates all that information about our routes. We learned how to define route parameters and pass information along to the target component, and then extract that using snapshots or using an observable. And remember, the pros of the snapshot are it's easier, but with the observable you're always guaranteed to get the updated parameter information. And then from there we learned how we can use resolvers to make sure we get data before we actually go to the destination of the route. That was one kind of guard. Can you name any others? Yeah, there was the CanActivate, which we used to make sure we could go to a particular route. Often you see that with authentication scenarios. And then we saw a CanDeactivateGuard, which prevented the user from leaving the screen until they met certain criteria, like making sure they didn't leave the screen in a dirty state, and they either saved their changes or cancelled them. And to make it easier to apply guards we actually set up child routes, which helped us create a hierarchy of the routes. In the next module we'll continue exploring routes, but in the context of modules, ngModules. When we combine these two features together we can do things like eager loading and lazy loading of modules, and we can even apply guards so we can only load the content of a lazy loaded module when we want it. We'll learn how to do that and much more with ngModules in the next section.
Angular Modules
Types of Feature Modules
As an application grows it becomes really important to be able to break your application up into different sections or pieces of functionality. And when that time comes, we create Angular modules. In this chapter we're going to learn more about Angular modules. We've already had one, our app module, but we also can have routed modules. For example we can eager or we can lazy load our modules. This gives us an advantage so we can decide how we want to load the different content of our application. And we also have options on how we can do our preloading strategies with lazy loading, and beyond routed modules, there's other types of feature modules and we'll learn about those because they become important as we design larger applications. And we'll revisit how providers work inside of modules so they can understand the decisions that we make and how that impacts the design of our application. Angular modules help us divide our app up into cohesive blocks of functionality. It's a great way to organize our application. Before we dive into the details of these modules, let's take a high level overview of the different kinds of modules that we can have. We have domain feature modules, this might be an ngModule that was directly imported by the app route module. No routing involved whatsoever. And then there's routed modules, these are ngModules that we would route to. In our storyline tracker application we might use this for the characters or the vehicles. Those could become modules that we route to. A third type of feature module could be a service feature module. We may have a message service or a logger service or even an exception service in our application. These services are core to the entire application and we might want to make them available everywhere, but only make them singletons. This is a common technique in building an application and we might just directly import this into our app route and make it available throughout the app by providing those services in the app routes providers. And a fourth type of feature module could be a widget feature module. Our application might have a calendar control or a filtering text box control or any kind of a custom control, and those different widgets could be aggregated and placed into a single module or a widget module. That widget module might be shared throughout the application, but unlike the service module we actually want multiple instances of each widget. For example, if I have two data calendars on the same page I don't want them to share the same instance, they should have their own state and their own behavior. Throughout this chapter we'll talk about all four types of these feature modules, but first let's start with the routed module, because we can eagerly or lazily load them.
Eager Loading
When we define a module that we're going to route to, the easiest way to get there is to eagerly load them. We get all those modules right up front. Eager loading is when we load a feature module right at startup. We're getting it eagerly, right with the route module. Ideal candidates in our application would be the characters or the vehicles areas, those could become feature modules that we eagerly load. When we eagerly load modules, we're getting them right away. This means they're ideal for things that we need to have for the application at startup, things that the user expects to be there to make the application functional. If we have several components that make up our dashboard and that's the first thing our users see when they launch the app, we could make that a dashboard module and eagerly load it. So when designing our application, we keep in mind the things that we want the user to use right away. Let's take a look at how we define different modules. If you wanted to take our characters feature area and turn it into a feature module, we could define character-routing.module, like this. We separate our routes out and we create an ngModule for it. Very similar to what we did earlier with the root module. So our routes are good to go, but one big difference is we make sure we use the forChild feature for any feature module routes. Remember the app route module used the forRoot, that's because it was the root. For any features modules we use forChild. Once we create that router module, we then import that into a feature module called characters module. So just like we did this pattern with the route where we had app routing module and we imported it into the app module, we're taking the character routing module and we're pulling it into the characters module, and we do that right over here. The characters module declares all the components that might be used inside that characters feature module. It also provides any services for that module. It's a way of encapsulating all the different functionality that characters are going to need, whether it's characterList or characterDetails or characterEditing, all that information is contained inside this one module, including its routing module. Now that we have the characters module, that gets imported into our roott module directly. So we go back to the AppModule, which we always have, and we import the CharactersModule and we get its routes automatically. The nice thing about this is when we have different feature modules all we have to do to pull them in is go to our root module and just import that feature module. One point in case, order does matter here. If you have routes in different modules, they actually get traversed in the order they're added. This becomes important if you have a star route. A star route is often looked at as a 404 route or a page not found route. You probably want that one to come in last. Now let's go take a look at one of our demos and see how eagerly loading modules works for us.
Eagerly Loading Routed Modules
Let's flip back over to our demo application and go down to number 27, Eagerly Loaded Routes. In here we're going to see a routed module, a feature module, for the characters and for the vehicles. Notice the application still has routing, characters, and vehicles here. And we still have our AppRoutingModule, but in this AppRoutingModule I only have my routes for the default route, which is going to redirect to /characters, and notice that's not defined here, and I also have a star route, for the page not found. So where are the other routes? Well let's go inside vehicles and here we can see the entire vehicles folder is contained with this vehicles feature module and this vehicles feature module has the declarations for all the routed components, what are they? We'll go look at those in a moment, and then a VehiclesRoutingModule. Both of those are inside of my VehiclesRoutingModule, so I have my ngModule here and I have its routing module there and I define the vehicles and the paths for the different vehicle list and vehicle component, and notice on line 20 I'm using forChild for the routes. And those routed components that's just that convenience that we used earlier for the other routing modules we did where we take these different components, we put them in an array and we export them, that way we don't have to repeat these three import statements back in our vehicles module. This makes the ngModule file really short and small. So now our routing is really self contained and what makes it eager is because we go back into our AppModule and the AppModule is actually referring directly to that routed feature module for vehicles and one for characters. We can see those here being imported with their ES6 modules on lines 9 and 10, and then we're putting them in the imports of the ngModule down here on line 20 and line 16. So now our AppModule pulls in the VehiclesModule and the CharactersModule along with its routes and all of its components and all the functionality. And because there's a direct reference to it using symbols, all of it is eagerly loaded, and notice we have AppRoutingModule listed last, that's important because remember that is where we had our star route and that one needs to come last because that matched first, everything comes after it would be ignored because that would satisfy pretty much anything we pass in to a route. So now we run our application, everything is eagerly loaded and we get all the data up front. Everything's just there and ready to go. But sometimes we don't want it all to be loaded up front, and we'll talk about that next with lazily loaded feature modules.
Lazy Loading
We want to make our applications really snappy for our users, so we'll provide all the data they need up front to be eagerly loaded and then content they might need later to be lazy loaded. Lazy loading of modules is on demand, we get it just in time, right when we need it. This is going to lower the initial payload and make our application feel much faster for the user. Let's picture this scenario, we're got an application where all the components that the user wants to use right away, like our dashboard and our menus, they could be loaded eagerly, there's the ones over here on the left. And which ones those are need to be identified by you and your design team to figure out how the user's behavior is. And then we could have a router where when they click on a particular link, we go and we lazy load another module and that contains more functionality for the user. When the user clicks on that link and the lazy loading starts, what's happening is a fetch is performed to go get that content. So we can route to modules eagerly, which means they get the content at startup and they can use those features right away. Or we can use lazy loading for some of the modules. That means some of it'll come on demand. This is more ideal for anything that's not in the immediate workflow for the user. Let's take a look at how lazy loading would be implemented. For lazily loading modules, we want it to find those in something that's eagerly loaded. Let's pause on that for a minute because this is important. Our app route module is already there, it's eagerly loaded. We need the app route. From there, things could be eagerly or lazily loaded. If we're going to lazy load from there, that content isn't there yet. So if we want to go get that content, it makes sense that the app route module would know here to go get those lazily loaded modules. That's why we define those paths right here. Notice we have characters and vehicles here and we're using the loadChildren property and then we define a string path and where to find those modules. It's got to be a string and not a symbol because if you use a symbol here and define the component, like we did with the page not found, it's going to eagerly load them. Because it's a string and we're using a loadChildren it knows, okay this is going to be lazy loaded, and we use the hash to define that's the name of the module you want to get from that file. So the characters and vehicles are going to lazily load and they're not going to be directly imported. Now let's go back to our demos and we'll take a look at the lazily loading modules to see how that works in our application.
Lazily Loading Routed Modules
We flip back to our demo app, we'll slide on down to demo 28, Lazily Load Routes. Here we'll click on the sample and we're going to see the same kind of application, but now we're going to use lazy loading. First we see we get our characters right away, now let's click on vehicles. I'll tell you when I'm going to click, 1-2-3-click, and notice that we have a slight delay right there. Now we go back to characters, it's instant, go back to vehicles, it's instant. Can you guess what's happening? Yeah, the lazy loading is happening for the vehicles. Let's go check the network tools. If we come over here and we'll hide the file list because we want to see the entire network bandwidth. Now let's reload this by looking at the characters first and now clearing out the network content, we'll get rid of the console as well by hitting the Escape key in the bottom, and now all of our network traffic is gone. Now it's refreshed by clicking the refresh live preview and we'll see the content come across. Notice all the files are getting loaded. Now let's clear that content and let's click on the vehicles. Notice we're getting vehicle content at this point because we lazy loaded it. Awesome. Well we want to explore both sides of the pros and cons here, let's open the File Explorer up and go look at our code. If we look in the app.-routing.module, we notice we have vehicles here lazy loading, but characters is not. So we'll go back to the app.module itself because remember he's the guy who controls everything, he's the first one that gets loaded up. Notice we have a CharactersModule eagerly loaded on line 17. That one's coming up front and that makes sense in this app because that's the first thing we see when the application loads. But notice there's no sign of vehicles in this app.module. In fact, the only sign of it is in the app-routing.module because we have the lazy loading reference here on line 8. And then inside the vehicles.module, it is just a normal module. It's got its own declarations and providers and looks just like any eagerly loaded module would look too, and it's got its own routes as well. The one difference here is that the route has a default path. Not that default path isn't the same as the default path of the app-routing.module, because I'm in the vehicles-routing.module, this default path actually takes on everything that the root module had and then puts this on it as well. So let's take a look at that. Back in the app-routing.module, if I was at path blank, that would go to characters. If I'm at path vehicles, that would lazy load this module. So now I'm at path/vehicles and I go into the vehicles-routing.module. So /vehicles is my starting point and then tack on the empty string, and I'm still at /vehicles. Then my child routes are /vehicles and /vehicles id. So now that we know how to do this, let's take a look at the pros and cons again for a moment. When the application loads, it loads relatively quick because characters is all we're really getting up front. Characters and then the app.module itself. So we don't have to wait for the vehicles content to come across the wire. That's the pro of lazy loading. Now imagine we had 10 different menu items. We don't have to wait for the other nine if we just load the dashboard of the characters first. The downside is the first time that the user clicks on one of these lazy load module links, it might take a moment to go get that content. What if we could have the best of both worlds? Wouldn't that be great? Let's talk about that next.
Defining Preload Strategies
We want the user to have an awesome experience by getting the content quickly so we eagerly load. But we really don't want them to have to wait for that lazily loaded content when they click on it. What if we could take that lazily loaded content and preload it with a different kind of strategy? That's where preload strategies come into play. A preload strategy is designed to help the problem where a user clicks on a link that goes and gets a lazily loaded module and there's a slight delay. With a preload strategy, the router can go get that lazy loaded content in the background and this can improve the user experience. The user gets all their eagerly loaded content right away, and while they're interacting with that, in the background Angular is going off and preloading the lazy loaded content. Let's see how we can do this. Out of the box we get some preload strategies. We have PreloadAllModules or NoPreloading. We import these from the Angular Router ES module. And then we pass that strategy to the forRoot function. So we could say preload strategy is PreloadAllModules and if we do this by default, anything that's lazily loaded will start to preload in the background, but it won't delay the user's experience of using and interacting with the eagerly loaded modules. Pretty cool huh? Now what if you wanted to just preload some things but not others? Well we can do that too with a custom preload strategy. For this we have to implement an interface. We create a preload-strategy class and we can name it whatever we want, and we implement the PreloadingStrategy interface, which has a preload function. Once we do that, we can write any logic we want that just determines how do we load things, and if we want the content to preload based upon our logic, we just call the load function. Now how do we use this class? We go back to our app-routing.module and in here we specify a data property and we use the preload right there, which matches the preload function in the preload-strategy. And we can say okay for this speakers route, it's lazy loaded, I know this because I see the loadChildren and it's pointing to a string path, and I know it's going to use this strategy because I'm setting the preload to true and then I have to tell the application that I want to use this strategy. So in the AppRoutingModule we passed to the forRoot this preloadingStrategy of PreloadSelectedModulesList, which is the one we defined up top. Now let's go back to the storyline tracker application, which has a lot of lazy loaded content, and we'll see how preloading can really help the user experience.
Preload Strategies in the Storyline Tracker
When we launch the storyline tracker application we can see that we've got dashboard, characters, vehicles, admin and login. These are all different modules, feature modules, and they all happen to also be routed featured modules. Let's go take a look at how we've defined them. In the app-routing.module, we can see there's an admin, dashboard, characters, and vehicles, all are using loadChildren, all are lazily loaded. Now we also had a login, that's got its own module and that module is not lazy loaded. How do I know that? If I go back into the app-module itself, notice I have a direct reference to the login module. This kind of makes sense from a design. If we look at our application, I don't want to lazy load any of those four, but the login is something we definitely want to be available for users. And when I click on those menu items, notice even though they're lazy loaded, I'm getting them immediately, there's no delay. That's because we're preloading these modules. If we go back inside of our app-routing.module, we can see here at the top, if we close out of the app, we have PreloadAllModules on line 2. And then we're using that same strategy down in line 32 by passing it to the forRoot. Well let's run this application and let's close the code and go into the dev tools and we'll watch the network traffic. And you can see these bars going across the top as it loads the content. The application is still loading, it's taking a while because we're loading file by file at this point and not doing any bundling or deployment strategies, but right through here you can see different gaps. And if I look at those gaps, you'll be able to tell different content that's occurred. So let's start over here. This content is going to show us basically all the stuff that Angular needs to run by default in RxJS. Now if we scroll back over here, we're still getting some of that. And then we can see that we're getting our navigation and our login, all that stuff that comes up front, that's part of the app-route.module and the login.module, the eagerly loaded stuff. Now we're getting the dashboard, but wait the dashboard was lazy loaded, right? Our application was actually usable right about this point, right after it got all this nav content in our app and then we started getting our lazy loaded content. Now if we see that again, and we'll refresh from scratch, right around this time period, we should be able to use the application. So we should see it on the left hand side like this, we'll clear out the content and let's refresh the app. So the application is loading and we can see that it's getting the content, and you'll notice after it becomes usable, on the left hand side they'll still be content coming across the wire. See the content is still coming, and that content over here was all of our lazy loaded content. And I want to stress that it's running slow here because we're running everything inside of a Plunker and we have not done any build process whatsoever. When it becomes time to do our deploy of our application, we'll use tools like AOT, which is an Angular tool to do ahead of time compilation, that'll use the Angular compiler on the server to compile the templates here and then send across the wire those compile templates. So it doesn't have to do that in the browser, it'll still get the data on the fly, and that'll make the application faster, and we'll use things like tree shaking to shake out some of the dead code that we're not using. And we use code splitting so we can split our bundles up in case we want to use eager or lazy loaded modules. And we'll use things like bundling and minification and other standard web practices. A lot of these are built into the tools that Angular is starting to provide. If you want to learn more about these, you can check out the documentation or you can take a look at the Angular cli, which has this built into it, or check out one of our Angular 2 courses that covers deployment.
Feature Module Types
Our application is made up of various ngModules, Angular modules. These different pieces are features of our application. We call these feature modules. Earlier we talked about the four basic types of feature modules, there are domain modules. These are the most basic types of modules, they represent a domain of logic where we encapsulate a certain feature. These could be our characters are or a menu area with navigation and other pieces that go with it. We also have routed feature modules. Routed feature modules are actually a type of domain module. They just have one additional characteristic, they're domain modules that can be routed to. In the storyline tracker application we have the characters and vehicles ngModules, which are domain and routed feature modules. The third type of feature modular are the services, these are the ones that hold things like our logging and our messaging or our exception handling, anything that's a service that we want to use throughout the application. And the fourth type were widgets. This is where we put our components. We talked about the kinds of domain modules that we could have. These are typically going to be imported once into our root application, and there's no routing associated with them. Things like a menu module or navigation module, could be other examples, domain modules. Once we apply our route to them they become routed domain modules. These are ones that have a target using a route. So we put some kind of navigation with them. In our application, our CharactersModule is a routed feature module. What about the service? A service is one that holds different services we can use. Generally this type of module contain all providers and no components, and we'll import it once into the app's root module. I often call this the CoreModule because it's core to the application. Things that should go in here, we talked about being like a logging service or messaging service. Things that probably wouldn't go in here are components. Why? Because they're going to represent a singleton of our application. And we'll see when we get to talking about how providers work in modules that this is an important concept. You do not want to import the CoreModule into other modules. This is key to maintaining it to being a singleton. The final type are for the widgets. We often have these in applications, these are for our components or directives or pipes, things that we're going to use across an entire app. I usually call my widget module the SharedModule and I will import the SharedModule in every other module that needs to use these widgets. Next let's see how our application can be applied using these feature module types.
Identifying Feature Modules
I find it helpful to be able to apply the feature module types to a real application. This helps us identify the types as our building apps. The dependency chain might look something like this. We're on the left with the black lines, those four modules are effectively imported into the AppModule. So that AppModule imports the other four because it needs all of those. It has to have our services out of core, our menu, of course, to show the menu, and then the characters and vehicles modules so we can get there. And then our SharedModule is actually used by the characters and vehicles. Those are the widgets that are actually shown on those different pages. Our MenuModule might have a MenuComponent or maybe other filters or directives. Our CoreModule might have services in it, things like messaging or exception handling. Our CharactersModule is going to have some routing module in it and a service for getting characters and maybe components for showing them. Our vehicles will look very similar, these are the most common in our application and as our application grows, we'll have many of these different kinds of routed modules. Our SharedModule will contain things that are reusable like a FilterTextComponent. We may want more than one of these in our application, different instances, or maybe a pipe that we create. We'll also import commonly used things like the CommonModule and the FormsModule right from Angular. Why? Because we want the ngIf and the ngFor or ngModel, and we're going to use those throughout the app. So all of our routed modules will import the SharedModule. Let's look at this a different way. We have our four basic types of feature modules, domain, routed, service, and widget. Modules must declare their components, their directives, and their pipes. Of these different types all of them could have declarations but a service module probably shouldn't. Why? Because we're going to share that across the app and we don't want to share the same date calendar everywhere because if I choose May 24th on one particular page, we don't want it to have that same state on another. Service modules, remember, are great for services, not components. What about providers? Where do services really live? Well they're ideal for service modules. You can use them in the other kinds, but it's more rare. What do we export from these modules? Do we export anything? A domain module might have some, routed ones probably wouldn't have any. Why? Because you're routing to them for a reason. They're a type of domain module and they're usually encapsulating everything they need, so you're not going to be exporting other modules. Same thing goes for service modules. You've encapsulated those services on purpose so we can import the entire service module into our app root, and yes, our widget module must export. Why? Because if we're going to use components inside the widget module and we're going to share them around the app, we have to export them so the app can use them. Let's look at this from the other angle of who's going to import these modules. Well if we have a domain module, a feature module might import it. Maybe it happens to be another domain module. Same thing with widgets, pretty much anybody can import those. The service module should only be imported by the app module, the root, because we're going to share those across the app, that's part of the core module we talked about. And routed modules should not be imported by anybody if they're lazy loaded. Let's apply these to concrete examples. A domain module could be like a menu module or even a character's module and then a character's module could also be a routed module. A service module, I generally call mine the CoreModule and make that contain all my services in my app, but another example is the HttpModule that comes from Angular. It contains a bunch of services we can use. And the widget module examples might be the CommonModule, that's the thing that comes out of Angular that gives us ngIf and ngFor, and we might create our own SharedModule with our own components and directives. Now let's go look through our storyline tracker application and we can see different examples of feature modules.
Feature Modules in the Storyline Tracker
Back in the storyline tracker we can identify the different kinds of modules that we talked about. First we have domain feature modules, things like vehicles. This is our vehicle-module and it contains everything we need to know about vehicles, our services, our components, and we happen to route to this feature module, which also makes it a routed feature module. We have other examples of routed feature modules, such as the dashboard. We route to him as well. He happens to be a little bit smaller than the vehicles module. And we also happen to have a characters routed feature module. What about those service modules we talked about? Well I like to name mine core and inside of here you can see a lot of things that are really generic for an app. You might see yourself creating an exception service or a message service or a user profile service. All these things would have singletons in your app, usually only have one user logged in or one exception handling service. We define a core.module at the root of them and that core.module would then import all the different files in there and it would also re-export the things that it needs to expose. This core.module is an example of as service module. Now back in our app.module we would import the core.module. Notice down here on line 27, that's one of the things our app.module gets. Now we have all those services available to the application, without having to pollute the app.module with a big list of them. So if we go back to our core.module, we should see a bunch of providers, like the EntityService, the ExceptionService and MessageService. What about a widget module? I like to call mine shared, we could also call it widget. Inside of here I've got a pipe and I've also got a filter-text component. And these go into the shared.module. Notice we have declarations of the InitCapsPipe and I happened to break out the filter-text.component into its own module and it's got a declaration for a FilterTextComponent, so this module actually gets imported by the shared.module right here on line 17. And all of those get re-exported on line 18. Now the shared.module is not imported anywhere except where it needs to be used. It could be imported in the app.module, but the app.module is not using it so we're not bothering with it. However, the shared module is used by the characters, so if we go to the characters-module, we should see here importing SharedModule. That way we can take advantage of the pipe and the FilteredTextComponent somewhere in this module if we need to. And we also might import the shared.module from the vehicles.module, right here on line 11. So the shared.module gets imported in multiple different places because we may want to use different instances of that pipe or that component. Now these labels what we've put on the types of feature modules, they're just labels. But I find it's easier to organize my application and design it by thinking about them in these terms. The first step of designing the app is taking different components and pipes and services and things in the application and deciding which ones are like minded or related, they make up your feature modules. We can then decide which ones are services, which ones are widgets, and which ones are domains or routed domains. As a reminder, there are just ngModules in Angular. These words we're using, they're not part of Angular, they're just a way for us to help think about how to divide our application, how to organize it. You'll find these terms mentioned in the official style guide on the Angular website in their docs.
Provider Tips
Sometimes our feature modules have to have providers. We need to make sure their services are available to those modules. There's a couple important notes I've learned along the way about using providers in feature modules and I want to share them with you. It's really important to consider how we want those providers to behave in our system. So let's think about a couple different angles. Let's say we had a component and it's got a bunch of child components. Now we have a service that's going to be used by all those components, the parent and all the children, but those are the only things using it. We could provide that service in that parent component, that makes it accessible to all of its children. An example of this might be a character service that's only used by the character component and all of its children. However, once we decide we want to use that service outside of the component tree, this isn't going to work. So a safe example of this might be like a login component. That login component might use a login service to check to see if you're logged in. Nobody else is going to use the login service, but that login component. If that's the case, we could provide that login service to the login component's providers and feel really safe that nobody else needs it. We just talked about putting providers at the component. More often than not we're going to want to provide at the ngModule level. This will make the services available to everybody in that module, but keep in mind when you import an ngModule and that ngModule has providers, anything importing it is going to get a new instance of that service when we do dependency injection. This is why the CoreModule in our storyline tracker app, which has a bunch of services in it and it provides those services in that module, is only imported into the app root module. If we imported it somewhere else we'd get multiple instances of those services and we don't want that. Now that feature is there because there may be cases where we do want multiple instances, but just be aware of how that works. And as a reminder, we want to be really careful putting any providers in a module that could imported more than once, this is why we don't generally put providers in our widget type modules. So let's look at an example. We just mentioned a login.component. The login.component is probably going to be the only thing that uses the LoginService, and if that's the case, we could provide that LoginService in its providers, right here. If somebody else has to use that LoginService, we wouldn't do it here, we'd do at the module level, and that might become part of the core module. In this case, right here, the LoginService is only used in the component so we provide it at this component, so the LoginComponent can use it and any child of LoginComponent could also use it. What about module providers, which are far more common? Here we have the app.module, and notice we have several different providers listed. There is a RouterGuard for an AuthenticationGuard, CharacterService, UserProfileService and a VehicleService. These are all different types that could be used throughout the application. So we provide these to the root injector and this makes them available everywhere in the application. NgModules help us organize our declarations and our providers. Just keep in mind how those providers work and when in doubt, provide at the module level. And these are just some tips to help you with providers as you're designing your application.
Wrap-up
In this module we learned quite a bit about eager loading and lazy loading of different modules. Whenever we're routing, we have to decide which of these types we want to use. Eager loading gets them on demand up front, lazy loading allows us to delay that load so we can front load everything we need for the user with the eager loaded modules. We can gain better performance out of lazy loaded modules and remove the delay of when a user clicks on a route and then it has to go fetch that information for the lazy loader module by using preload strategies. Then we learned how to identify different kinds of feature modules so we can categorize the types of ngModules we might create and find in an application. This helps us design our application better. And last, we learned some good tips about using providers inside of our application. All the demos in our application can be found right here at the angular2-first-look-azurewebsites.net website. Here we'll keep these demos up-to-date as Angular progresses through Angular 2. I encourage you to click on the examples, play with them, change the code around, and we can discuss them and live fire on the Pluralsight website. And finally, please check out the official style guide that I'm helping author on the angular.io website. This is a great place for you to learn new tips about designing your applications. I truly hope you've enjoyed taking this Angular 2 first look as much as I've enjoyed presenting it to you. Thank you and have fun with Angular.
Course author
John Papa
John Papa is a Principal Developer Advocate with Microsoft and an alumnus of the Google Developer Expert, Microsoft Regional Director, and MVP programs.
Course info
LevelIntermediate
Rating
(1054)
My rating
Duration4h 31m
Updated9 Nov 2016
Share course