Angular Material
  1. What We'll Be Building By the end of this course we will have built this beautiful-looking Contact Manager, displaying contacts in a sidenav to the left, and the contact details in the main contact area on the right. And each contact displays the contact's Bio along with the Notes. And the Notes section is using the data table where we have implemented pagination, sorting of the column headers, and filtering. We'll also be able to add a new contact using a pop-up dialog with a form. We'll be able to select an SVG icon, have some simple validation, since Name is required, let's enter that. Use the date picker to select a date, and the text area to enter a user's Bio. And when we save a new user we'll get a snackbar that the contact was added, we'll be able to execute an action to navigate to that user. We'll also implement custom themes, and be able to toggle between the themes. And we'll also take a look at right-to-left and left-to-right support. To summarize, this course will be packed with awesome samples of how to use the components provided to us by the Angular Material team to build beautiful websites in almost no time at all. You'll be able to follow along and jump into any module if you follow my GitHub repo. Each module will have its own branch. So if you'd like to jump right into module 6 you can go ahead and check out module 6. The files will also be available as exercise files at Pluralsight.

  2. Course Overview The layout of the course will be as follows. You're already watching this brief introductional module where I'll give you some quick background context on prerequisites and the tools that we'll be using. The Material Design module is the only theoretical module where we talk about the core concepts of Material Design, along with some concrete examples and illustrations of what Material Design is all about. From this point on the course will be almost exclusively code demonstrations. I'll show you how you can quickly set up your environments and get up and running with Angular Material in minutes. The following couple of modules after that is where we actually build our application, and my goal is to leverage as many components and services and possible from the Angular Material library. We'll be switching back and forth between the official documentation and the code editor. I want to teach you how to build any application, not just this specific application. And for you to be able to do that you'll need to be able to navigate and understand the docs. The last module, we'll wrap up and briefly look at the parts that we've overlooked and talk about where the Angular Material project is headed for the next couple of releases. If you fell that you know what Material Design is, feel free to skip the second module, which gives you a brief introduction to the fundamental concepts of Material Design. And, if you already have your development set up and used Angular Material before, feel free to jump over module 3 as well and jump right into module 4 where the real coding starts. Even if you don't need to be an expert, this course assumes that you already have a basic foundation of HTML and CSS, and Angular 2 and up. If not, there are numerous course in the library you can watch to get up to speed. In this course, we'll be using Angular 5 along with Material 5. As for our tooling, we'll be using Visual Studio Code as our editor, which is a free cross-platform editor that works on Windows, macOS, and Linux, so you can follow along on any OS. We'll be using Node.js, which is an open-source, cross-platform, runtime environment to get the tools that we'll need to scaffold and host our application. All our components will be written with TypeScript. Angular itself is written in TypeScript; TypeScript has great tools. The biggest selling point of TypeScript is tooling, it provides advanced auto-completion, navigation, and refactoring. Having such tools is almost a requirement for large projects. Since TypeScript is a superset of JavaScript, you don't need to go through a big rewrite to migrate to it for existing applications, you can do it gradually, one module at a time. If you want to learn more about TypeScript after completing this course, there are plenty of other courses on the topic in the library you can watch.

  3. References and Links Here's a list of links that might come handy, both throughout this course and afterwards. Feel free to dig into the Material Design specification in its full length at material.io/guidelines. For me to go through all the details of the spec would be overwhelming, and to be honest, quite painful to listen to for several hours. As I stated earlier, my courses are dead-straight to the point and code-oriented. Furthermore, you can find everything you need to know about the Angular Material project at material.angular.io, including the docs, which you'll see me use quite extensively throughout the course. And everything is open source. Feel free to familiarize yourself with the code and the samples at the team's GitHub repo. Or even better, try to contribute with a pull request. On the GitHub node you can find the source code for this application we'll build at my GitHub page at the following repository. Each module will have its own branch, so it's easy to jump right into any module and follow along. And, if you like my style of teaching and want to get updates on what's going on with web development today, make sure to subscribe to my YouTube channel, where I try to post as frequently as possible. And finally, make sure to follow me on Twitter to stay posted on updates. If there are any course updates coming up this is where you'll hear it first. Now, let's find out what Angular Material is about.

  4. Material Design Introduction Hi, my name is Ajden Towfeek, and this is Angular Material. In this module we will learn about the core concept of Material Design. We are only on the second module and I've already used the word beauty a handful of times. So, why is beauty important? Because beauty improves you user experience. In the book Emotional Design by paragon of modern cognitive science and user experience, Don Norman states the following, attractive things work better. Don points to research done in Japan and Israel where people not only perceive beautiful interfaces to work better, but they also achieved better results in terms of time to close completion and amount of errors. But, and there's always a but, designing beautiful applications is hard. Making beautiful things is not easy, and that's why it's awesome to take advantage of existing visual languages like Material Design. Material Design is a complete design language that helps you to build beautiful applications. It was developed by Google with two goals in mind. First of all, to synthesize classic principles of good design, with the innovation and possibility of technology and science. And secondly, to provide a unified experience across platforms, device sizes, and ways of interacting.

  5. Key Principles Material Design has three underlying principles that guide the design language, and which will help you understand and apply it when you're developing applications. And these are that materialism metaphor. The material is inspired by the study of paper and ink. Bold, graphic, and intentional. This can be clearly seen in the color palettes, the aggressive use of white spaces, contrast, and large-scale topography. Material Design uses motion to convey meaning and function, to support and respond to user interaction, and to guide a user between transitions within the application environment. Now let's take a closer look at what they mean by this with some concrete examples. Just like material in the real world, Material Design happens in a 3D environment. Here's an example of how shadow depicts the relative elevation between material elements. We also stated that motion should provide meaning. Motion and animations in Material Design are not something gracious, they have a purpose. For instance, transitions should be meaningful. Let's take a look at this sample. First, we have a good sample of how incoming material elements may expand into view, but content should only fade in. The opposite to this would be hard cuts that are jarring and require the user to do all the work in order to understand the transition. In Material Design things move the way they move in the real world. That is, motion feels natural. So much so that behind Material Design lies a physics engine that replicates motion in the natural world. Let's take a look at how natural acceleration and deceleration is implemented in Material Design. Here we can see that asymmetric acceleration and deceleration creates a more natural and delightful motion than a symmetric one.

  6. Summary The key takeaway are the three underlying principles that guide the design language. The first one being that material is a metaphor. The material is inspired by the study of paper and ink. Bold, graphic, and intentional, which can be clearly seen by the large-scale topography and in the color palettes. And that motion should provide meaning. Material Design uses motion to convey meaning and function to guide the user between transitions within the application environment.

  7. Getting Started Overview and Tooling Hi, my name is Ajden Towfeek, and this is Angular Material. In this module we will install and set up all the necessary tooling to get up and running with development. And if everything goes well, by the end of this module you'll have an Angular app bootstrapped with Angular Material, hopefully something similar to this one and it being served using the Angular CLI from the console. Now let's get on with installing our environment. I'll be using Visual Studio Code as my code editor. It's free, open source, and it runs everywhere, on Windows, macOS, and Linux, but feel free to use your editor of choice. I already have VS Code installed in my machine, you can simply get it from the website at code.visualstudio.com. And, at the download page, just pick the OS you are on and you are ready to go. Before we can create our Angular application we must have Node.js installed on our machine. This is so we can leverage npm, or Node Package Manager, for the installation. And also, we can leverage the local node command line tools. Once again, I already have node installed in my machine, but you can simply get Node from their website at nodejs.org, and you can find all the installers and the binaries under DOWNLOADS. Now TypeScript is a little bit trickier. If we visit their website at typescriptlang.org, and come to the Download page, we can see that it's super easy to install TypeScript as a Node.js package by simply typing npm install -g, for global, and then typescript. But, things tend to move fast in the web development community these days. It is very likely that by the time this course is released that very same command will install a completely different version of TypeScript for you that's not compatible with Angular and Angular Material. So, let's switch over to command prompt and install a specific version. For the time being, both Angular and Angular Material are at version 5. And the best compatible version of TypeScript for these versions is 2.4.2. So let's simply install that version by typing npm install -g for global, and then typescript, and then to specify an explicit version just go ahead and put an @ and put down the version that you want, and hit Enter. And we can easily verify the version by typing tsc --version, and we should get 2.4.2. Alright, so we are almost there and ready to scaffold our first Angular application. Now, all we need to do is install the Angular CLI, so let's talk a bit more about that next.

  8. Setting up Angular CLI Angular CLI is a command-line interface for Angular. It makes it easy to create an application that already works, right out of the box, that follows best practices, awesome. And, just like TypeScript it's very convenient to get the latest version as a Node.js package, but for the sake of compatibility and to make sure that you can follow along in this course without any hassle, we'll explicitly tell npm which version to install. Also, Angular CLI has a peer dependency to something called yarn. Yarn is a somewhat faster alternative to npm, even though that's something being argued about in the community. So the idea with yarn is that it caches every package it has downloaded, so it never needs to download the same package again. It also does almost everything concurrently to maximize resource utilization. This means even faster installs. Having that said, let's stick to npm in this course; nevertheless, we'll still need to install it globally. Once we have that down, we can simply scaffold our application by typing ng new, and then the app name, jump right into that folder, and serve our application. So, let's switch over to our command line and install the Angular CLI. You might have earlier versions, or even later versions, of the CLI installed on your computer, so let's begin by first uninstalling whichever Angular CLI version you have on your computer right now and cleaning the npm cache and then installing the version we're going to use in this course. And, if you're on Windows, make sure you command prompt is running with elevated permissions as an administrator, and on a Mac or Linux use pseudo. So let's start by uninstalling globally whichever version we have right now. Alright, so once we've done that there's also a possibility that you have an even earlier version of the Angular CLI before they changed the name of the npm package. In that case, make sure to uninstall angular-cli because this was this tooling's name before they changed the name to be consistent with all the other Angular npm packages. Now we want to clear our npm cache. We do that by typing npm cache clean. And, once we have that done now we can simply go ahead and install globally @angular/cli, and the version I want you to install is 1.5.3. Alright, everything looks good. Now let's clear the screen, and let's also not forget to install yarn, which was a peer dependency, otherwise, we'll see an annoying error when we generate our application later. So, let's go ahead and install that by typing npm install -g and then yarn. Alright, so it looks like we are ready to create our Angular application. But before we do so let's just make sure that we are using the correct version, and if everything is good here you guys should see 1.5.3. So we are good to go. Let's create our application, ng new angularmaterial, and let's create the folder structure for us, and now it's installing all the packages from tooling via yarn. Once that is finished, let's change the directory into our create a project and type ng serve. This will serve our application at local host port 4200. And if everything went fine you should be able to browse that URL and see the following app. And I'm using Chrome, and by pressing F12 we bring out the developer tools and we want to make sure that we don't have any error messages in the console, and it looks like we are good to go. If you want to learn more about the CLI, John Papa has a great course here at Pluralsight, which will teach really everything you need to know. I'm just going to use a couple of basic commands and I'm going to explain each and every command that I'm using, so don't worry if you haven't used Angular CLI before. Now, let's see what we need to do to add Angular Material to our application.

  9. Installing Angular Material We can load Angular Material into our application within six simple steps. First of all, let's start by installing Angular Material and Angular CDK. Wait a minute, what did I just say? Angular CDK? CDK stands for Angular component development kit. I won't put much effort into explaining what the CDK is, I'd rather quote the Angular team. The goal of the CDK is to give developers more tools to build awesome components for the web. This will be especially useful for projects that want to take advantage of the features it Angular Material without adopting the Material Design visual language. So it's pretty clear that the CDK is comprised of a bunch of services, directives, components, classes, modules, etc. to make our lives easier when developing Angular components. The implementation details of the CDK is out of the scope for this course, we're just going to go ahead and install it so we can get up and running with Angular Material. So, let's switch back to command prompt and install Angular Material and the Angular CDK. And we achieve that by simply typing npm install --save @angular/material and @angular/cdk. You'll probably get UNMET PEER DEPENDENCY, just like I did here, but you can safely ignore that error as long as it's coming from the codelyzer library, which it does for me right here. Codelyzer is a tool to lint our TypeScript code, and we'll still be able to lint our code, even though we have a couple of unmet peer dependencies. To be able to do more advanced transitions some material components depend on the Angular animations module. For these animations to work in our app we'll have to install the Angular animations module and include the browser animation module in our app, so let's go ahead and do that. Once again from the command prompt, let's install our module by typing npm install --save @angular/animations. Now, once we have that down, let's go ahead and open up the code for the first time, and once again, I'm using VS Code, feel free to use any editor you like. Let's start by opening up package.json file, and we can see all the package versions that we've installed. And we should be able to see that Angular animations installed. Now let's go ahead and import that module into our app. And we'll do that in app.module.ts. So, right after BrowserModule let's go ahead and import the BrowserAnimationsModule. And, for us to be able to do that we're going to need to import that module from @angular/platform-browser/animations. Alright, so that was easy enough. So, what's next? Now we want to import the ng module for each component we want to use. So, let's switch back to the code and see what that means. For instance, if we want to leverage the material button module and the checkbox module, we're going to need to import those into our application. And we do that by first importing them from the Angular Material library and then passing them right into the Imports declaration at the NgModule annotation for the app.module. (Working) But, we can see that declaring each module like this will be quite cumbersome. I'd rather declare a separate ng module that imports all of the Angular Material components that we'll use in our application. And then we can include that module wherever we'd like to use the components. So, let's do that instead. Instead of creating a separate TypeScript file here in the editor I'm going to jump back to the console and generate a new module using the Angular CLI. And we can do that by typing ng g, g is short for generate, and then a module, and we want to call our module the material module, So let's just go ahead and type material, and if we want to see what this will generate for us we can go ahead and run a dry run first, and we can see that it wants to put the material module into src/app/material/material.module, but I'd rather put it in a folder called shared. And now we can see that it tries to put the material.module under shared, but it also keeps the material name. So, to get around that we can pass in flat as a parameter. So, once you're satisfied with where you want to put the files that are going to be generated, go ahead and remove the --dry-run, and the CLI will create the files for you. So let's switch back to code and see what just happened. So we just got a new folder called shared, which contains our new module. And, instead of importing the modules in our app module, let's go ahead and do this in our material module instead. And this module itself won't have any decorations, it'll just import all the material modules and then export them. So you won't need the CommonModule neither. So let's import these guys, and we won't have any declarations, but we will export these modules. Let's go ahead and save that up, switch back to app.module, and now, instead of importing the modules we're going to go ahead and import our MaterialModule. Now, before doing anything else, let's make sure that this works. So, let's switch back to command prompt and serve our applications, and we can do that by typing ng s, which is short for serve, and then we want to open a browser and we do that by passing in -o. And, we're not really using any components yet, so let's just go ahead and take a look at how we can add our first material component.

  10. Our First Material Components The best way to learn about how to use these components is by exploring the documentation at their site. So at material.angular.io we can go ahead and browse Components, and let's go ahead and scroll down to the Button documentation and try to implement this button here. So we can go ahead and view source, and it should be as simple as just typing button and then declaring the attribute mat-button. So let's try that. So let's open up our app.component.html, and instead of having all this boilerplate code that was generated for us from the CLI, let's replace that with a simple button. We also imported the checkbox, so on the documentation site, let's go ahead and find Checkbox and see how we can use that component. And, once again we just view the source and copy/paste the code, and back in our application let's go ahead and add a checkbox. So, let's see how this looks in the browser. And in the browser I'm glad to see that the console hasn't logged any errors for us, but I'm not quite satisfied with how the button and the checkbox look. So, let's see what we can do about that. As we could see, including a theme is required to apply all of the core and theme styles to our application; without including a theme it doesn't really look good at all. So, to get started with a prebuilt theme we can include one from the Angular Material's prebuilt themes globally in our application. So, let's switch back to code, open up our styles.css, and import a prebuilt theme. Let's import indigo-pink. You can see which themes are available by simply browsing the prebuilt themes folder in the node_modules folder. So under node_modules, @angular, material we can find prebuilt-themes. And we have a couple of choices, let's stick with indigo-pink for now. So let's switch back to our browser. We can see that the browser got refreshed for us, since we're serving the application using ng serve, and now it looks a whole lot better. Now when we click the button we can see we've got some nice animations there, and when we check the checkbox we get a whole new experience here as well. Cool. So, what else is there? Now that we have included a theme, let's also enable gesture support. Some components rely on Hammer.js for gestures. In order to get the full-featured set of these components Hammer.js must be loaded into the application. And the easiest way to achieve this is by installing the package via npm. So, back at the command prompt, let's install Hammer.js by typing npm install --save hammerjs. Now, after installing it we'll need to import it in our app's entry point. So let's come back to the code, open up main.ts, which can be found at the root level along with the index.html, and let's just import hammerjs, and that's it. Now the sixth, and final step, is to add material icons. We want to use mat icon components with official Material Design icons. And to do that we'll need to load the icon font and index.html with a link ref. So, let's switch back to code, open up index.html, and simply link in fonts.googleapis.com/icon?family=Material+Icons. And having done that, we can come back to our app.component.html. And, in the button that says Click me! let's go ahead and add an icon there as well by typing mat-icon, and then we want the face icon. For more information on using material icons check out the Material Icons Guide, which can be found at google.github.io/material-design-icons. But before we can serve our application again let's switch back to the code and open up our material.module, you're going to need to go ahead and add the MatIconModule, both imported and exported. Let's save this guy up, switch back to the command prompt, and serve our application again. And, yes indeed, we got an icon on our button, and if we open up the developer tools we can see that no errors are logged in the console and we still have our beautiful animations when we press the button.

  11. Creating a Material Master Module So now we only have two basic modules, or three with the icons modules as well, so let's go ahead and load all the material modules into our shared material module, so let's switch back to the code and open up the material.module, and you can find all the available modules if you browse the material project's GitHub page, or you can just trust me when I say that the following list is all the modules that are available in the material framework. And this file is available in my GitHub repo or you can find it in the exercise files section here at Pluralsight. Once we have imported and exported all the modules, now we got the dependency to the forms module. So, to be able to import this material.module now, we're going to need to go ahead and jump into our app.module.ts and import the formsModule. And, since I'm using VS Code I can just press Ctrl+. and import formsModule from Angular forms. Now I'm hoping we're good to go.

  12. From CSS to SCSS Before I'm ready to commit this code to GitHub I want to do one more thing. Currently we're using CSS at the default style extension. I'd really like to use SCSS instead. So to change the default extension to SCSS we need to open up the angular-cli.json and come down to the defaults styleExt and put down scss instead of css. And let's also rename our styles file from css to scss, and let's also not forget to rename the actual file. Also, rename the app.component.css to scss, and make sure to import the SCSS file instead. This won't do any difference for us now, but most front-end developers prefer something that compiles to CSS, and from now on when we generate any component, since we changed the default extension to SCSS it will generate a SCSS file for us and include it in our component annotation for our component. Let's also go ahead and delete the app.component.spec.ts file since we won't be writing any tests in this course. And doing this, if you're serving the application you're going to start getting a lot of errors in the console, so you're going to need to go ahead and kill the serving of the application and restart ng serve. And let's cross our fingers, and yep, everything works, and no errors in the console. Now, let's wrap up this module.

  13. Summary In this module we've installed all the necessary tooling that we're going to need throughout this course to develop our application. That included installing a code editor. In my case that was Visual Studio Code. We've installed Node.js on our machine, and we've also seen the Angular CLI in action, which helped us to scaffold the skeleton for our application. And finally, we set up the correct TypeScript version that we're going to need to be able to use Angular 5 together with Angular Material 5. And we saw that it was as easy as a command for an Angular CLI to scaffold our application. And we got started with Angular Material. In the next module we'll take a look at the library called flex layout, which will help us to create the base layout for our application.

  14. Layout Component Our Goal Hi, my name is Ajden Towfeek, and this is Angular Material. In this module we will create the layout for our contact manager app. We will use Angular's flex layout module that provides sugar to enable developers to more easily create modern responsive layouts, on top of CSS-free flexbox. By the end of this module we will have built the following layout for our application. Using layout components such as Toolbar and Sidenav we'll also associate breakpoints with mediaQuery definitions to adapt our layout, both for desktop and mobile devices. Awesome, so let's get on with it.

  15. Flexbox Basics We won't go into detail about what CSS flexbox is, that would be way too time consuming for this course, we want to be able to focus on Angular Material. If you want to know more about CSS flexbox there's an entire course on the matter here on Pluralsight, feel free to check that one out. Having that said, it's still good to know about the core concepts and the terminology since we'll be using it. A flex container is the box generated by an element with a computed display of flex or inline flex. Inflow children of a flex container are called flex items and are laid out using the flex layout model. The main access of a flex container is the primary access along which flex items are laid out. The flex items are placed within the container starting on the main start side and going towards the main end side. And width or height of a flex container or flex item, whichever is in the main dimension, is the box's main size. It's main size property is thus either its width or height property, whichever is in the main dimension. The axis perpendicular to the main axis is called the cross axis. It extends the cross dimension. Flex lines are filled with items and placed into the container starting on the cross side of the flex container and going towards the cross end side. The width or height of a flex container or flex item, whichever is in the cross dimension, is that box's cross size. Its cross size property is thus either its width or height property, whichever is in the cross dimension. Angular flex layout provides a layout API using flexbox CSS and mediaQuery. This module provides Angular developers from version 4.1 and higher with component layout features using a custom layout API. So, let's add it to our application and start with a very simple example before creating our contact manager layout.

  16. Application Routes Before we code let's take a minute and clarify how I want to segment the application. We're going to start this module by adding rooting to our application, and that's because I see two main modules here that I want to load separately. First a demo module that will contain what we've done so far and soon a simple flexbox demo. This module will have its rooting separating from our main application's rooting. And then I want to put our contact manager into a separate module with its own rooting and child root elements. So there will be some Angular plumbing here to get the rooting up and running, but just bear with me and I'll be explaining each step as we go along. So we can see our demo module as a playground where we can try different concepts out, and then keep the code instead of throwing it away. So, let's refactor our code to achieve this.

  17. Creating a Demo Module So, what we have for the moment is the full application that simply serves whatever is in the app component file. And if we take a look in the code we can see that we have no rooting at all here, we just have an app.component.html that has that button and that checkbox. So now, I would very much like to be able to separate these simple checkbox and button examples from our flexbox sample, and we're going to put that into a separate module. So, let's come back to the command prompt and generate a new module called the demo module. So we're going to kill the serving of the application, clear the screen, and once again I want to use the Angular CLI to scaffold our module. So we do that by typing ng g, for generate, and m for module, and now we want to define where to put that module. And we want that into a folder called demo, and I want to call it the demo module. And, once again, I'm not quite sure what this will generate for us, so I'm going to go ahead and do a dry-run. And, lucky for me, I actually did a dry-run because I don't want to put the demo module into two folders called demo, so we're going to want to pass in the flat parameter and that looks like the path that I want to use. We already know that we want to separate our buttons from our flexbox demo, and the way we're going to do that is with routing within our demo module. So if we go ahead and pass in routing as a param as well, we can see that two module will be generated for us. One module containing the routing, and one for the actual module. So let's go ahead and run this. And switch back to the code, we can see that we have a new folder called demo containing our two modules, one with a routing and one for the actual module itself. And we're going to want to move the code from our app.component.html into a component in our demo module. So let's go ahead and generate that component as well. So instead of generating a module now we want to generate a component. And we want it to go into the demo module and let's call this the buttons component. And I want to do a dry-run here as well. Our simple button and checkbox demo really don't need to have its own HTML file or its own style file, so we can go ahead and, along with the no-spec parameter because we won't be writing any tests either, we can define the style as inline and the template as well. And now it only generates one file for us, and this is what we want. So, let's go ahead and remove the dry-run, and switch back to the code, we can see that we have a new component called buttons, with a simple file. So let's open up our app.component.html and just take everything in here and put it in our end line template. Now, if we were to visit the application we wouldn't see anything because we removed all our code from our app.component.html, and we don't have a router outlet, and we aren't even loading our demo module, so we're going to need to do all those things to be able to get back to where we were earlier, but with routing instead.

  18. Setting up the Routes So, let's start by defining a router outlet in our main application. So let's open up app.component.html, and just add a router outlet element, and then come to the app.module and define some routes. Let's import Routes and the RouterModule into our app.module. And right off the BrowserAnimationsModule go ahead and import the RouterModule. But, we still haven't defined any routes, so let's go ahead and do that. Instead of declaring the routes in a separate routing module I'm going to go ahead and declare them in our app.module, that's just my style of coding, as we can see the Angular CLI went ahead and put the routing into a separate module for us, for our demo module. So let's define our routes. We shall be an area of routes, and they're going to pass these routes into our import statement for the RouterModule with forRoot because this is a root component, and then pass in our routes. And now there are a couple of ways of doing this, I'm going to do lazy loading for our demo module. So the path for our demo application will be demo, and then we're going to load children. And now we're going to pass in the path to our demo module, along with the module name. And the syntax is as follows. So, the demo module is located within a folder called demo, our file name for the module is demo.module, and then we need to provide the module name separated with a hashtag, like this. And we're also going to add a catchall route that will redirect to the demo module. Alright, so now we're going to try to load our demo module into the router outlet in our app.component.html, but we're also going to need to define the routes for our demo module. So let's open up our demo.routing.module and define a route to our button's component. And the path here will be buttons, and then we want to specify the component that will handle this route, which will be the ButtonsComponent that we just generated with the template and the styling inline. Let's go ahead and import that component. And currently this won't be able to run because we're going to need to import a couple of things into our DemoModule. This module still doesn't know anything about Angular Material. So let's open up app.module, and now we can safely remove the MaterialModule and the FormsModule, which is a dependency to the MaterialModule, from the imports in our main application since we are loading the DemoModule lazy. I'm going to import these into a DemoModule instead, but now we're going to need to go up one folder to find the shared/material.module, and then import these guys. And then in the demo-routing.module we have defined our route for the buttons path, but we also need a default catchall route in our DemoModule, so let's go ahead and add that, then we want to redirect to the buttons sample. Alright, so let's save this up and come back to the command prompt and serve our application. And our routing works. We can see that even though we browsed the route of the application, we'll get redirected to the demo module, and the demo module's default route is the buttons component. So we are still able to browse our buttons demo. Now we want to add a new component here with its own separate route for our flexbox demo. So, let's come back to the command prompt and generate a new component into our demo module, and we're going to call it flexbox. And once again, let's do a dry-run first, and we know that we won't be needing the spec file, and this looks about right. So let's go ahead and run this command and switch back to the code. So we got a new component in our demo folder, but we won't get the route by default, so let's go ahead and add a new route to our component, FlexboxComponent, and the path to that component will be flexbox. So, if you serve the application again, we'll get routed to the buttons demo by default, but we'll also be able to browse flexbox, which for now only says flexbox works! Cool, so we have successfully set up routing in our application, now let's take a look at that flexbox demo.

  19. Flexbox Demo Let's start by installing Angular flex-layout using npm. And currently, the flex-layout has a peer dependency to Angular Core 4.4, but we are running at Angular 5, but you can safely go ahead and ignore this warning because it will work anyways. So, let's switch back to VS Code and our demo.module and go ahead and import Angular flex layout. So we're going to import the module FlexLayoutModule from @angular/flex-layout and then go ahead and import it, right after the MaterialModule. And this is really all we need to do to get up and running with flexbox. Now, let's start with a very simple example solving an almost-daily problem, perfect centering. It couldn't be any simpler when using flexbox. So let's open up our flexbox.component.html, let's define a div, which will be our flexbox container. This div will have a couple of flexbox items, and we're going to have a bunch of these. So let's copy this guy up and change the content to enumerate each box. Now, let's open up our SCSS file and define the CSS classes. Now, let's first create our flex-layout context for our container. So flex-container display: flex. For our flex items we want them to take up some space, so let's set the width to 200 px, and the height to 150, and let's give them a nice background color, tomato, and let's have the font to be white. Give the font a bold weight, and increase the font size a bit, and let's also center the text. And this should be flex-item and not flex-items, and along with the centered text let's also center the text vertically by defining the line-height to the same height as the actual flex-item. Alright, so let's take a look at how this looks in the browser. So, currently, we just see the boxes laid out, and if they can't fit on the screen they just get resized. And this isn't quite the behavior I'm looking for, so let's see what we can do about this. So let's go side by side via the VS Code and the browser so we can see the updates live. Let's define the flow direction and allow the items to wrap. We can do this by, on the flex-container, defining flex-flow and then putting down row and wrap. Now we can see that the items are getting wrapped. This is the same thing as defining flex-direction: row and flex-wrap to wrap. So this really doesn't do any difference, just different ways of defining the same thing. We can also define how to distribute the remaining space, and we do that by defining justify-content, and here you can say space-around. And if we go bigger we can see that the boxes are evenly spaced, even though when they are on separate rows we can see that we don't have any margin on the top, so let's add that. Now we have six nicely-distributed items on the horizontal axis that when we resize the browser everything is fine, without media queries. But it's just as easy to change flexbox attributes defined with media queries. Let's for instance change the justify contents based around to flex start if the screen is smaller than 800 px. So if the screen is smaller than 800 px we want the flex-container to justify its contents with flex-start. And now if you resize we can see that at 800 px we hit the breakpoint and we change the way we justify the flex container's content. And there are many ways to play around with this. So far we've done everything from our SCSS file, but we could as well just opened up our flex.component.html and say that for smaller screens we want to layout in columns instead of rows. And now, if we resize the screen we can see that when the extra-small screen breakpoint was hit we are laying out our items in columns instead or rows. There are really many things we can do with CSS flexbox or Angular flex layout, we could easily spend several hours playing around with this, but instead I'm going to leave that up to you as an exercise. I really recommend you to go ahead and check out Thomas Burleson's Angular Flex layout demo, which you can find at tburleson-layout-demos.firebaseapp and then docs. Here you can go ahead and play with the different attributes that you can put into your markup or into your stylesheets and see how the boxes align depending on which attributes you choose. And this is really good because you can't remember them all. So here you can go ahead and play around and see which attributes really are the best fit to solve your problem. Now, let's get started with our contact manager app layout.

  20. Scaffolding the App Our contact manager will be laid out as following. We'll have a main wrapper for our entire module and the main component we're going to use is the Sidenav component, which will host our contacts. And this component will be responsive so it'll be visible on bigger screens and hidden and toggleable on smaller screen devices. We'll also have a toolbar that will always be visible to which we will add some menu items in the next module, and we'll have a main content area, which will display whichever contact is selected. Alright, so let's start by defining our contact manager module and load it into our application. Let's start by scaffolding a new module named contactmanager and let's foresee what this will generate for us, and that seems about right. So let's go ahead and run that command. Now in that new module we want a new route component that will compose our application. So let's go ahead and generate the new component in the contactmanager module and let's call it contactmanager-app, and once again, do a dry-run, and we won't be needing all these files, and we also we want to put it at the route level along with the module definition. So, let's pass in flat, and we don't want a spec file, also let's define the style inline, along with inline template. Right, and that was exactly what I was looking for, so let's go ahead and remove the dry-run and generate our new file. Now, this component will act as a host for our other components, but from the last slide it was clear that we want a toolbar, a sidenav, and something to host our main content. So, let's go ahead and generate all those components at the same time. So ng g component, and we want to put this into our contactmanager, and we're also going to create a couple of services and models further down the road, so we want to group all our components into the components folder. So let's start by creating our toolbar, and as always do a dry-run first. So, let's keep a separate template file and a separate style file for the toolbar, but remove the spec file, and go ahead and generate this. We're also going to generate a component called main-content, and our sidenav. Now let's switch back to VS Code and wire up our new contact manager module. So we can see that a new folder was created for us, and even though we will be using routing I didn't pass in the routing param because if we take a look at what happened for the demo module, we got a separate module containing our routes. I really like to keep the routes together with our module file, but that's really just my style of coding, feel free to do as you please. So first, let's start by hooking up our contact manager in our app.module. And just for the sake of simplicity, let's go ahead and lazy load our contact manager app as well by copy/pasting the demo route, and instead of demo let's just put down contactmanager. So now we should be able to load our contact manager, but also, let's default redirectTo through a contactmanager instead of the DemoModule. Now, just as in the DemoModule we're going to need to go ahead and import Angular Material and flex layout modules into our contactmanager.module. So let's open up our demo.module and copy/paste these modules into our contactmanager.module. And then also importing them. Now let's also define the routes, and let's open up app.module for that and just copy/paste this, which will modify it in a second. Let's make sure to import the Routes from a router module, along with the RouterModule, and I like to keep the Angular-specific imports grouped together, and then down here, go ahead and once again import the routes forChild and then pass in our routes. Now, let's take a minute and think about how we want to define these routes. According to this slide, our contact manager will have its own router-outlet, so we're going to need to define the routes in this module a bit differently than we did in our DemoModule, more specifically we're going to need to define a couple of children to our main contact manager application route. So, let's go ahead and do that. So at the route level we're going to want to load our ContactmanagerAppComponent, and let's get rid of this demo and change the wildcard to redirect to our route component, but then our route component will have its own router-outlet. And currently we have scaffolded the following components. So let's go ahead and define children for app component and the default path, which will still be the empty string, should load the component MainContentComponent. So let's go ahead and declare the elements in the markup files. So at the route level we're going to want to have the sidenav. Let's go ahead and open up the sidenav component file, and we can see that the selector is app-sidenav. So let's go ahead and put that in the route component instead, and the sidenav will be the host for sidenav content, along with the toolbar. So let's open up sidenav and wire up our toolbar along with our router-outlet that hopefully will display our main content for now. This isn't really the final product, but let's just see if everything is wired up correctly before we go on with creating our real sidenav host. So at the command prompt let's serve our application again. And now, instead of being routed to the demo module we get routed to our contact manager, and we can see that the route components within the contact manager module expanded the sidenav component for us, which contains the toolbar component, along with the router-outlet, and now we only have one default route, which is the main content, which also seems to work, which is awesome. Now we are ready to create a layout using the Angular Material components.

  21. The Sidenav Component The sidenav component is typically used for navigation, but it can really contain any content. The mat-sidenav is a panel that can be placed next to or above some primary content. The sidenav can render in three different ways depending on the mode property. Over means that the sidenav floats over the primary content, which is covered by a backdrop. Push means that the sidenav pushes the primary content out of its way, also covering it with a backdrop. We'll be using side on large-screen devices and over on small-screen devices. Using the side mode on mobile devices can affect the performance and is also not recommended by the Material Design specification. The easiest way to get up and running is to navigate to the Angular Material website, and browsing the Components, and really start to just copy/paste in the components into your own application and then just start modifying the CSS until we have the look and feel that we'd like for our application. So let's come down to Sidenav, and we can see that they say that the sidenav is typically used for navigation, so that's exactly what you want to use it for, and we want to place it next to our primary content, so it looks like this is a perfect fit for us. And if we take a look at the basic sidenav sample, this is an excellent starting point for us. So let's go ahead and view the source, and just get the markup, and drop it into our sidenav component. And we can see that they are clearly using some CSS classes so let's go ahead and get those as well, even though we will be renaming them, and let's just leave this as is for now and start modifying it once we've seen that everything runs in the browser. So let's open up the markup file and we want the toolbar inside our main sidenav content, along with router-outlet. And if we switch back to our app now we can see that this clearly isn't our intended layout, but let's try out to open the sidenav, and it works. So, let's try to modify this sample to fit our requirements better. First of all, let's just change the name of these classes to app-sidenav-container, and app-sidenav for instance, and app-sidenav-content, and let's come to our SCSS file and do the same renaming, sidenav-container, app-sidenav-content, and app-sidenav. And we want the sidenav to be 240 px, and for a sidenav container we want to enable flex, we want to use the entire screen. So width 100%, height 100%, but also min-width along with min-height, and let's also remove that border. Alright, so let's take a look at how this looks in our browser. And immediately I can see that we have a couple of problems here. So first of all, it looks like we have some kind of margin here and also we aren't really filling out the space, even though we have explicitly set the height to 100%. So, let's go ahead and fix those two things. So for the container to take up the height of 100% we're going to need to set the position to fixed, and to get rid of that margin let's open up our styles.scss, and set the margin to 0 on the body element. Now let's switch back to our browser and see what we've got. Alright, so it looks like we are filling up the space and we are able to toggle the sidenav, which is quite awesome, so we are really getting there. Now, let's replace the content of the sidenav with something other than the Jolly good! text.

  22. Styling the Sidenav So let's switch back to the documentation and take a look at how we can create the toolbar instead. So let's just take this simple code here and add that to our sidenav. So instead of Jolly good let's add the toolbar and say that this is our Contacts. And also, we don't want that gray color, we want this to have the primary color of our theme. And let's also mock our contacts for now with simply displaying a list of items. So once again, let's come back to our documentation and try to find something that will display our contacts in, let's take the List component for now. And this is a basic list with no styling or whatsoever, let's just take this for now and we'll modify that later. Alright, so let's take a look at what we have so far. Let's toggle the sidenav, and we can see that it really starts to look like something already, and we've just copy/pasted some code from the official documentation site. And this is a really neat way of working in my opinion, we can get up and running with a basic layout, which we can style later on, or even hand off to some designer guy and let him style the application for us. Alright, so let's see what we can do about that button that toggles the sidenav. Let's create the toolbar and put the button up there instead. So let's copy/paste the toolbar code from a sidenav component and put it into our toolbar markup. Instead of saying toolbar works! let's have a toolbar here as well, but let's give it a title Contact Manager. Now let's see what this looks like in the browser. Right, so now we have our toolbar, but it looks like it's centered around the middle, which isn't really what we're looking for, we want the toolbar at the top, so let's see what we can do about that. So let's switch over to our sidebar SCSS file, and we can see the code that causes this effect, it's the align-items: center and then justify-content: center. We are telling the content to flex at the first row, so let's go ahead and just change the flex-direction from row to column instead, and hopefully this does the trick. Alright, so we have our main content that works, along with the sidenav that can be toggled with this button.

  23. Configuring the Sidenav I'd really want my application to start with the sidenav opened if we are using a large-screen device, like I am on my laptop right now. So let's take a look at what the API says in the docs about the sidenav and which properties to use. So if you open up the Sidenav documentation and come over to the API tab and scroll down we can see which properties are available. And this goes for all the components in the docs. If we scroll down we can now be interested in two separate properties to bind to here. We're going to want to change the mode from over to side depending on if we are on a big screen or a small-screen device, and also set the opened property to true or false. So, let's switch back to the code and open up our sidenav.component. Let's start with setting the opened and the mode property to some values. And we'll start by setting these to some static values, but then we want to use media queries to change the mode depending on the screen size. But let's start by setting opened to true and mode to side. Let's see what this looks like in our browser. Alright, so now, by default, the sidenav is open, but we can see that we lost the shadow between the sidenav and the main content. So let's add some elevation there. And we do that by adding a CSS class, mat-elevation-z10. And the value after z indicates how much elevation we should have. If we put the screen side by and side and go ahead and change the z value to 1, we can see that the elevation decreased, which 15 casts a whole lot more shadow. So let's go with 10 for now.

  24. Adding Responsiveness So now, instead of setting the properties opened and mode to static values, let's try to bind to them instead. So in Angular, we bind with brackets, and we want to bind to a method on our component, which will tell us if the screen is small or not. So if the screen isn't small, so if we were on a big device, then we want the sidenav to be opened. And if the screen is small then we want it to be closed, but then we'll be able to toggle the sidenav instead. And, let's bind to mode as well. And remember that we could take three values here, over, side, or push. So, if the screen is small then we want it to be over. On large screens we want it on the side. And to be able to try this out we're going to go ahead and change this button down here to instead from just opening it we want to toggle it instead. We're going to move this toggle to our toolbar, but first things first, let's implement isScreenSmall on our component. The way to approach media queries in JavaScript, or TypeScript in our case, is through matchMedia, which is a low-level service to publish observables with window.matchMedia. Basically you just use the same approach as with CSS. Let's try to use this in our component code. So we want to bind to a method called isScreenSmall on our component. So let's open up sidenav.component.ts, and start by defining what the small-width breakpoint should be. So let's define a const at the top and name it SMALL_WIDTH_BREAKPOINT and set it to 720 px. And we want a query that will match on this breakpoint. So in our SidenavComponent code let's start by declaring a mediaMatcher and the type for the matcher will be a MediaQueryList because that is what matchMedia will give us. And the syntax we're going to pass in here is very similar to CSS media queries. So we want to listen for max-width and then our SMALL_WIDTH_BREAKPOINT, which is 720 px. Now we can declare our isScreenSmall method, which will give us a Boolean, and this shall return if the mediaMatcher has any matches. Now let's see how this works in the browser. Now we start off on a big screen, and the sidenav is opened, which is great, and we should be able to toggle the sidenav using this button. But if we bring out the developer tools and resize, we can see that the MediaQueryList isn't updated. But if we refresh the page, it's updated since it's not showing, and if we open it, the mode is now over instead of side, which causes the backdrop to be displayed over the main content. Alright, so we are almost there. We just need to refresh between each screen resize. Let's see what we can do about that. So we have defined this query that runs once, but we haven't really added a listener, so let's go ahead and do that in the constructor. So this mediaMatcher, add the listener, and we can see that the param here is the actual listener itself. So let's make sure to set our mediaMatcher to this param. But, before even running this code, I will argue that proper changes within the listener will not propagate. Why is that? So let's take a minute and reason about that. The reason that the MediaQueryList isn't updated is due to that NgZone does not wrap the matchMedia API, so it doesn't know that the change detection scan is needed. To make this work we will need to run change detection scan manually; there are several ways to do it. One is to inject the ApplicationRef and call ApplicationRef.tick. The second way is to inject ChangeDetectionRef and run the scan directly. And the third way is to simply run the listener inside an Angular zone. Option one and two will work just fine, but they require an action. Option three is more natural and does not require an action, so let's implement that one. So, to be able to run the listener within an Angular zone we simply resolve NgZone into a constructor and import it from Angular Core, now we'll just wrap this within zone.run, and hopefully this will trigger change detection, let's try it out. Alright, so in the browser we have the sidenav open by default, let's try to change the screen size to go below the breakpoint. And the sidenav closes. And if we open it up now we can see that it opens over, which causes the backdrop over the main content. And if we resize it again, we can see that it works. Let's change the view port to a phone device. And we can toggle the sidenav, and if we change back to desktop mode, the sidenav acts as expected. So that's great. Now, let's get rid of this button here and move it up to the app toolbar.

  25. Creating a Toggle Button So, let's open up our sidenav markup and instead of having this button here, let's move this toggle up to our toolbar. And we don't have a click event there, instead we're going to expose a toggleSidenav event that will fire whenever the toggle button is pressed. So let's go ahead and get rid of this button. Now, let's switch over to our toolbar markup and add a new button, with a menu icon. Now whenever this button is pressed we want to emit an event, the toggleSidenav event. So let's add a listener to the click event and emit the sidenav event that we still haven't declared. So let's go ahead and open up the toolbar TypeScript file and declare our event. So we'll output a toggleSidenav property, which will be a new EventEmitter. We're going to need to import EventEmitter from Angular Core along with the Output attribute, which needs to be declared as a function call. So whenever this button from the toolbar is pressed we're going to emit the toggle sidenav event, which we'll listen to in our sidenav.component to toggle the sidenav. So let's see what this looks like in the browser. So we can see the button up here, and we're able to toggle it, even though we are on the big screen. So I'm not sure I want this behavior, I want the sidenav always visible when we're on the desktop with more than 720 px, and I just want it visible when we are on a smaller device. So let's do that with styling. So, let's open up our toolbar.component and add a CSS class to it, sidenav-toggle. now let's declare this class in our toolbar.component.scss file. By default we don't want to display it at all, and then with a mediaQuery we want to enable it as a flex container. So let's see if this does the trick. Now we're on a small device and we can see the icon, and we're able to toggle the sidenav. Let's resize the screen, and we can see it go away. And this was exactly what we were going for. Let's just add some more styling to make the button look a little bit nicer. So first of all, let's define an iconWidth, which will be the same width and height as the toolbar. And on the sidenav-toggle class let's set padding and margin to 0 and 8 px, but also the min-width to the iconWidth. And when we actually display the button within this mediaQuery, let's go ahead and align it to center, center as well. And let's also define a class for the mat-icon within the sidenav-toggle, which increases the font size and also sets the height, and width, and the line height to the actual height of the toolbar. So let's format this and come back to application, and we can see that the button got a little bit bigger and it fits perfectly to the toolbar. And still, when we resize it disappears and appears. And, for mobile devices, they are always there whenever the sidenav is hidden. So we can see that the main content works, but it's not that appealing. So let's throw in a card there. To get the markup for that let's head over to the material Angular doc site and get the code for a card. At their site the first thing that we see is a basic sample. So let's go ahead and just view the code and get that. Back in our code let's head over to main-content.html and throw in this sample card instead, and just put in a header that says Main content. Now we also wanted some margins, and we probably want that for all the the components that's going to be viewed inside the router-outlet. So let's open up sidenav and wrap this router-outlet within a div with a wrapper class. Now let's declare that class and add some margins to it. So our wrapper class should have a margin of 50 px. Alright, so this application is really starting to look good. So let's wrap up this module and summarize what we've used so far.

  26. Summary Let's summarize what we've used in this module. Angular flex layout provides a sophisticated layout API using flexbox CSS and mediaQuery. This module is available for Angular version 4.1 and higher. The sidenav component is typically used for navigation, but it can really contain any content. The sidenav can render in three different ways depending on the mode property. Over floats the sidenav over the primary content, which is covered by a backdrop. Push pushes the primary content out of its way, also covered with a backdrop. And side causes the sidenav to appear side by side with the primary content without the backdrop. Mat toolbar is a container for headers, titles, or actions. A common pattern is to position a title on the left with some actions on the right. This can be easily accomplished with flex attributes, which we'll see in the following modules. So far, all our toolbar contains is a simple title. Setting responsive breakpoints is usually attended to via CSS media queries, however, there's a JavaScript alternative as well. We saw that the way to approach media queries in JavaScript is through window match media, which is a low-level service to publish observables with window match media. Basically, you just do the same approach as with CSS.

  27. Displaying Real Data Our Goal Hi, my name is Ajden Towfeek, and this is Angular Material. In this module we will load up our application with some real data and display its contents. By the end of this module you will have built the following app and you will have set up routing so we can load whichever contact we want by selecting them in the sidenav. And, it will look good on a mobile device as well. Now, let's see how we got this far in almost no time at all.

  28. Introducing the Data Service Let's load in some data into our application. The part of our application responsible for that will be our UserService. Data services such as this one usually have basic create, read, update, and delete operations. Our service will be somewhat more slimmed down to only reading and creating data, just for the sake of simplicity. In our data service we have a few moving parts. First we have a private data store. This is where we store our list of users in memory. We can return this list immediately for faster rendering or when we are offline. For now, it simply just holds onto our list of users. Since services in Angular are singletons we can use them to hold our data model or state we want to share. Next is our behavior subject. Our behavior subject can receive and emit new users lists. We don't want subscribers of a service to be able to push new values to our subject without going through our CRUD methods. To prevent data from being altered outside the service we expose the behavior subject through a public property and cast it to an observable using that the as observable operator. This will allow components to receive updates, but not push new values. Our data structure will be composed of two simple entities, the User entity and the Note entity, and then contain properties that are common to simple contact manager applications, such as the one we are building. You could go ahead and new up these objects directly in the user data service, but for a more real-world scenario approach I've published an API that exposes a couple of users at the following endpoint, angular-material-api at azurewebsites.net/users. This will allow us to make real HTTP calls and handle the data, just like you would do in a real-world application. Feel free to use your favorite browser and just browse the endpoint and see what the data looks like. You could also just go ahead and take all this and copy/paste it directly into your service to avoid making HTTP calls in case you're not on an internet connection. But now, let's implement our user service in our code.

  29. Feching Data Back in Visual Studio Code we can see that under contactmanager we have a folder for our components, but we don't have a folder or a class for our service, so let's switch back to the command prompt and scaffold a service using the Angular CLI. So we want to generate a service into contactmanager and then into a folder called services, and we want our service to be called user service. Now as always, let's go ahead and do a dry-run and see what this will generate for us. Alright, so it's almost what we wanted, we just want to get rid of the spec file, and we got what we want. So let's switch back to the code, and let's not forget to also provide this service to our module, since the Angular CLI doesn't do that for us for services. So under services, we got our new service, but let's go ahead and provide it to our module as well. Now, since I'm using VS Code I can just hit Ctrl+. and import the service, which imported the UserService for us at line 13. Now we also want to scaffold the classes that will represent our entities in our Angular code. So once again, let's switch back to the CLI and this time generate a class instead, and we want that to go into contactmanager\models, and then let's begin with the user class. And this won't try to generate any spec files, or CSS files, or template flies, it will just generate a file called user.ts into a folder models under contactmanager. Let's also go ahead and create the note class. Now let's switch back to VS Code and open up the user class and just add the properties, we know that we'll get back from the server to it. And the user entity will also have a collection of notes, which we're going to need to import from our note class. Now let's open up Note and add the properties to it that we know that we'll get back from the server. Alright, so we have our data structure modeled out for us, so let's go ahead and try to fetch the data from the user service. So let's begin with the private data store that will contain our users in memory for us. And remember, we don't want to expose this internal store. And we're going to need to import the user from models, and since we're going to do an HTTP call to get our users let's go ahead and resolve an HttpClient into our constructor and import it from @angular/common/http. Along with that let's also go ahead and initialize our data store. And for us to be able to resolve an HttpClient we're going to need to import a new module into our contactmanager.module. So let's open up the contactmanager.module and come down to the imports and go ahead and import the HttpClientModule that we'll get from @angular/common/http. So let's switch back to our service and continue implementing. Now we're going to want a public loadAll method that our initializing component should be able to call to load up the initial user data. So let's define that, let's also define the URL to the endpoint that I've hosted at Azure websites, and let's get a user array from this URL, and subscribe to a response, and also register an error handler. If something goes wrong let's just go ahead and log that to the console, but if we receive our data let's go ahead and add it to our store. And let's format this up. Now that looks a lot better. So hopefully now we're able to fetch data, but remember, we don't want to expose our internal store. So, let's go ahead and declare our behavior subject that components will be able to subscribe to. So, at the top, let's declare our users as a BehaviorSubject. And once again, this is our internal structure that we don't want external components to be able to manipulate. We're going to call asObservable on this subject, which will be exposed to our components. So now that we have our BehaviorSubject, let's go ahead and instantiate that along with our internal data store in the constructor, but let's also expose a get property that will allow our components to subscribe to this BehaviorSubject. And for that we're going to need to import from RxJS Observable. And now that components are able to subscribe to our BehaviorSubject, let's also go ahead and actually call next on our BehaviorSubject to publish data to all our subscribing components. So, whenever we receive data back from our loadAll method we want to go ahead and call next on our BehaviorSubject to let our listener components know that data is available. And here, we don't want to push out our internal data store, since that would allow components to manipulate our data, so I want to create a new object and then copy all the properties from our data store onto this new object, and then just publish our users. And we can achieve that by using Object.assign, and this will take two params. The first one is the target that we want to copy to. And that's going to be a new object. And then we want the source that we want to copy from. That's going to be our dataStore. But then we don't want to publish the entire store, let's just get the users. Alright, so I'm ready to try this out. So, let's find a suitable component that's going to resolve our UserService and load up our users. And I think a good place would be the sidenav, since the sidenav will contain a list of our users. So let's open up sidenav.component.ts, and into a constructor, along with our zone, go ahead and declare our UserService as a private member of our component, and also import the service. Now we want our markup code to be able to bind to an Observable. So let's declare our Observable in our sidenav.component, and once again import RxJS Observable along with our User model. And onInit, we're going to want to initialize our users observable to the one that we're exposing through our userService.users. So this property calls asObservable on our BehaviorSubject. And until now nobody has loaded that collection so let's go ahead and trigger loadAll. Alright, so I'm almost ready to try this out in the browser, although we wouldn't see anything now, so let's go ahead and subscribe to our users observable, and just console.log data whenever we get something from our UserService. Alright, so let's switch to the console and host our application. Now, our application loaded fine, so everything's good, but let's open up the console and see what we received. So we can see that we received data twice. The first one is from when we initialized our BehaviorSubject we populated it with an empty array. But then we called loadAll from our sidenav.component and we received four items. And if we expand the items, it looks like the data came down from the server to our application correctly. Awesome. So let's see if we can display these users in our sidenav.component.

  30. Navigation Lists So, let's head over to the material.angular.io site and look at the docs at which alternatives we have to list our users. So currently we are using this Basic list, but let's scroll down and see what else there is. And this looks interesting. So, Navigation lists, that's exactly what we're going to use our sidenav for. We want to navigate to our contact when everyone is clicked. And here we can see we have a simple navigation list, but we're going to probably want to display their avatar along with their name. So, let's take a look at this more complex list that uses a link along with a button with an icon. So we're not going to have a show info button, but this is close enough to what I'm looking for. So let's go ahead and get this code and try to use it in our code. So, let's open up sidenav.component.html, and replace this list with the one we just copied from the docs. Now, we don't have links, but we did declare an Observable of users. So, let's iterate over our users and also this will be loaded asynchronously, because it's an observable that we subscribe to, so let's go ahead and use the async pipe that is needed whenever you are binding to an Observable. Now, we will want to navigate, but let's skip that part for now, and instead of just displaying a link here, we're going to want to display the username, and let's delete this button, and take a look at what we've got in the browser now. Awesome. So we are displaying our contact's name. But what about that avatar?

  31. Loading SVG Avatars MatIconRegistry is an injectable service that allows you to associate icon names with SVG URLs and define aliases for CSS font classes. And we usually want to register and load up our icons once. And an excellent place to do so is in the app.component.ts. And in order to prevent cross-site scripting vulnerabilities, any SVG URLs passed to the MatIconRegistry must be marked as a trusted resource URL by using Angular's DomSanitizer service. So, let's go ahead and add the assets and try to load them up into our application. Now, first of all, let's go ahead and copy in our asset's SVG file. And you can get this file from the GitHub repo or from the exercise files right here at Pluralsight. I'm going to go ahead and put them right into this assets folder. Now let's go ahead and load up our icon registry with this SVG icon set. And, remember, we just wanted to do this once, and we want it to be available for all our components in our contactmanager.module, so a great place to do it is in the contactmanager-app.component. So let's resolve the MatIconRegistry, which we'll get from Angular Material. Now we can go ahead and add our SVG icon set. Since our asset contains several icons, you could go ahead and just add one icon and associate that with a name, but in our case we're going to want to register the entire set. And we can see here that IntelliSense tells us that we want a safe resource URL. And to be able to provide that we're going to need the DomSanitizer. So let's go ahead and resolve that into our constructor as well, and import the DomSanitizer from the @angular/platform-browser barrel. Now the DomSanitizer has several methods. Now we're going to want to bypassSecurityTrustResourceUrl, and this will give us a safe resource URL that the addSvgIconSet method accepts. And here we simply just pass in the path to our avatar's SVG icon set. And that's hopefully it. So, let's switch back to our sidenav.component.html and along with a username let's also use a mat-icon, but now instead of defining an icon name from the material icon set we're going to want to set the svgIcon attribute to our user's avatar. So let's save this up and switch back to the browser and see what it looks like. Alright, pretty nice. So we have our contacts with their avatars along with a name. Now let's make these links clickable to be able to display each contact's info in the main area content.

  32. Routing to Users Now, instead of this href here, we're going to want to use the router. So, whenever somebody clicks a link we're going to want to navigate still within the contactmanager.module, but we're going to also want to pass in the user.id. Now for this to be able to work we're going to need to register the route in a module as well. So let's open up our contactmanager.module and let's copy/paste this route. And above it, since ordering among routes in Angular is important, and we want the route that accepts an ID. And we still want to use our MainContentComponent. And now, let's handle when we're getting navigated to in our MainContentComponent. So let's open up main-content.component.ts, and first of all let's declare our user and import this from our models. Now we're going to get an ID as a param when we're navigated to. So we're going to want to use something called activated route to be able to get the params from the route. So in our constructor let's resolve ActivatedRoute, which we'll import from @angular/router. And we're also going to want to resolve our UserService since we only get the ID, we want to be able to fetch the user given an ID. And let's also import the UserService and format this up so it fits to the screen. Now in ngOnInit we're going to want to subscribe to the params observable, and now we can get the param id by accessing params with a string literal id. Now we want a method on our UserService, userById that takes a number id and give us a user. And we want to set our user to whatever this service returns to us. So let's go ahead and implement userById on our UserService. And this implementation will be very straightforward, let's begin with expecting that somebody has already called loadAll for us and we know that the sidenav has done so, so now we can just simply expect that our dataStore contains our users, since one was hopefully clicked and now we can just find the one in the internal store that has the same id. Now, let's write some markup that displays some info about the selected user. So, let's open up our main component.html file, and first of all, let's display something if the user isn't loaded yet. So, let's just put down Please select a contact. Or even better, let's head over to the documentation and see if we can find something more interesting. And I'd like to display some kind of busy spinner, let's scroll down and see what we've got. Oh, so we have a Progress bar and a spinner. Let's take the spinner. And we can see that it has two modes, one that's determinate and one that's indeterminate. So let's just take this one, and display that instead. But, if we do have a user, let's display something more meaningful than just Main content. So once again, let's go back to the doc site and see what we can do with the mat-card.

  33. User Cards Under LAYOUT we can find Card, and let's switch over to EXAMPLES. And this looks pretty neat, so let's check out what they've used in the code. So we've got some sort of mat-card header, along with an image, and then some content, and then some actions. So I'd really like to use at least the header along with the content. So, let's just grab this part and throw it in here. Now, we don't want that image of that dog, but we probably want the mat-icon with the user's SVG icon loaded, which we can find on the avatar property on the user object. Awesome. So, let's also go ahead and display the user's name, and as the subtitle let's also put down their birthday so we don't miss out on congratulating our friend's birthdate. But we don't want to display the raw JSON here, so let's go ahead and use the date type to format this to the digit for the day of the month and then print out the entire name of the month. And down here, instead of this text let's go ahead and display the user bio. So, let's switch back to our browser and take a look at what this looks like. So, we can see that we have a couple of problems. First of all, when we load up the app we haven't selected somebody on the list yet. So, we're displaying the busy spinner even though we don't need to. But, let's try to click on somebody in the list, and we can see that the navigation works, which is awesome. We can see the user's avatar, along with their birthday, and their bio. And the route is changing to reflect the user id that we just selected. But what happens if we press F5 when we are on a user route? Then we have the same problem as when we visited the contact manager. So let's see what we can do about these two scenarios, the first one being when we're hitting the default endpoint and the second one when we have selected somebody and then press F5.

  34. Refactoring Routing Issues So, let's switch back to the code and open up sidenav.component, and we are already listening to when we receive some data and we are logging it to the console, but let's use this subscription to something else. Why not navigate to the first user if there are any on the list? And to be able to do that we're going to need to resolve the router into our constructor and import it from Angular router, and in the subscription let's check if we actually had any data, then we want to navigate to the contactmanager route and pass in the id. So, this should take care of when we visited the route of our application to display the first contact that is available on our list. Now, what happened when we refresh the browser when we were already displaying a contact? So let's open up our main component.ts file. So, for some reason, our userById didn't get a user when we refreshed the browser, and we were standing in our route with an id param on it. And that's because there was an array condition between our sidenav component that still hasn't loaded our users in our main-content.component that tried to fetch the user. But since our service already exposes our users as an observable, why not try to take advantage of that. Let's go ahead and subscribe to our users observable in our main-content, as well as our sidenav.component, and whenever we get any users we want to find the user by ID. And this should be users, not user. And we only want to do it if our users array has a length that isn't 0. Alright, so let's try this out. Now, in the browser we are displaying our first contact, and we can see that from the URL. And if we refresh now, we can see that we got our contact. And also, if we remove the param we are loading our contact. Let's see how it looks on a smaller device. So this looks good, let's try to select a new contact, and we can see that the contact is changing in the background, but the sidenav isn't closing, which isn't really the behavior that we'd like when we're on a small-screen device, we want to close the sidenav whenever somebody's clicked. So let's see what we can do about that. So let's open up sidenav.component.ts, and we've already resolved the router into our constructor, let's see if we can use that to subscribe to events and close the sidenav if the screen is small. So our router exposes events as an observable. So whenever we are routing we want to know about it. And if we are on a small-screen device then we want to close our sidenav. So, we need a reference to our sidenav that's in our template file, and that's easily done. Let's just use the ViewChild attribute and resolve the sidenav. And let's open up sidenav.component.html and make sure that we have a reference to our sidenav called sidenav, and we do. So now, back in the TypeScript file we can just go ahead and always close the sidenav when we are navigating, if we are on a small-screen device, because then we know that we want to move out of the way of the content. Also, I really like that spinner, but I think it's not showing enough, so let's open up our main.content.component, and set a timeout, and not fetch the user immediately. So this is only for test purposes, please don't do this in production code. And for this to have an effect, we're going to need to go ahead and set the user to null whenever we are navigating, just to trigger the spinner to show and then disappear again. Now, since we are already subscribing to the users in our main.content.component it really isn't necessary to do the same thing in our sidenav on ngOnInit. Here we can really handle all the cases if we visited the route of the application so we didn't pass in an ID, meaning if id isn't defined then let's display the first contact. And also, we're going to need to change the const to let since we won't be able to change it otherwise. Now, having this here, we can safely go back to the sidenav.component and remove this navigation here, because this really does the same thing. Now, it always feels good to remove code, don't you agree? So let's switch back to our browser, and now, open up the sidenav and navigate to a new user, we can see that beautiful spinner and then the contact showing. And the sidenav is moving out of the way to display the main content, which is exactly the behavior we were looking for.

  35. Introducing Tabs I just want to do one more thing before we wrap up this module. Currently we are displaying the user bio in the card content directly. We know that users will also have notes, and a great way to separate these would be to display each chunk of info in its own tab. So we want the bio in a tab and then we want to be able to toggle to the user notes in a separate tab. So let's switch over to the docs and just head over to Tabs. Let's just take this first one, get the markup for it, and back in our code, open up main-content.component.html, and instead of just displaying the user info, let's go ahead and put it in a tab as well, and put this out there. And for now we can go ahead and put down notes here, but we can comment it out. We'll be addressing that in a separate module. Now let's switch back to our browser, and we can see that our application is really starting to look good. So let's wrap up this module and see what's next.

  36. Summary Let's recap. So, we started off this module by defining our user service, the key takeaways being we keep our users in an internal store. We don't allow components to push new values to our internal structure, they need to go through our CRUD methods format. We used a behavior subject to allows components to subscribe to data changes through an observable to keep our data immutable to our consumers. We registered user avatars as an icon set using the MatIconRegistry, which is an injectable service that allows you to associate icon names with SVG URLs. And to protect ourselves from cross-site scripting vulnerabilities, we need to use the DomSanitizer when providing asset URLs to the registry. We also saw that the card component has several sections that we can use to display info in. We use the card header to display the contact's name along with their avatar. And the header has a title and a subtitle, we use the subtitle to display the contact's birthday. And we have the card main content, and the last section, the actions, we won't use in this course, but at least now you've seen that they are there. Cool, so let's head over to our next module and take a look at what CDK tables brings to the table.

  37. Using Data Tables Our Goal Hi, my name is Ajden Towfeek and this is Angular Material. In this module we'll display data using the mat table component. By the end of this module you'll have the following data table implemented in the notes tab or our contact manager application, with features such as pagination, filtering, and also sorting.

  38. MatTable Features The mat-table itself only deals with rendering of table structure, such as rows and cells. The Material team has made it easy for us to add three key features, and they are pagination using the mat-paginator. The mat-paginator adds a pagination UI that can be used in conjunction with the mat-table. The paginator emits events that can be used to trigger an update via the table's data source. Sorting. We can use the matSort directive and the mat-sort-header to add a sorting UI to the table's column headers. The sort headers emit events that can be used to trigger an update via the table's data source. And filtering. While Angular Material does not offer a specific component for filtering tabular data, the table's data source can still be updated based on any custom filter. Now, let's try to implement this in our application.

  39. Generating our Notes Component Let's begin by generating a new component that's going to hold our notes in a grid. So Angular generates a component into the contactmanager module and components, and let's call it notes. And, let's also not generate a spec file, and as always do a dry-run, and that seems about right. So we want an HTML file, a TypeScript file, a SCSS file, and we want to declare it in the contactmanager module. So let's go ahead and run this command. Now, back in Visual Studio Code let's open up our main-content.component markup file, and remove this commenting of the Notes tab. And here we're going to want to resolve our Notes component. So app-notes. And we're going to want pass in the user.notes to a property called notes. So let's go ahead and declare that on a notes.component. We're going to need to import Input from @angular/core and Note from our models. Now, let's just make sure that this component renders correctly by opening the markup file and just output and a pre tag the notes as json. So now we have two tabs, Bio and Notes. And if we browse Notes we can see that we are rendering the JSON in a pre-element. Now let's try to put this into data table.

  40. Implementing the MatTable And once again, my preferred way of doing this is to browse docs and then start copy/pasting some code to get up and running and then start customizing it. So on the doc site let's go to Components, and scroll down to DATA TABLE. Let's take this first one and we're going to want to start off with something basic, so why not just pick this first sample here that displays a basic table. If we view the source here we can see that it contains of some basic markup, we've got the mat-table, and then containers that define our columns, along with the header row definition and the rows. But if we take a look in the TypeScript file, we can see that they are declaring the displayed columns pretty straightforward, but then they have an example data source that they declared right down here in the file. And this isn't really what I was looking for. But if we were to open this and StackBlitz instead, we can see that the sample is loading, but if we take a look at the markup now instead, or the TypeScript file, we can see that in this sample they haven't declared the sample data source inline. Instead they are using a MatTableDataSource. So, let's try to do that instead because it looks a lot simpler. So let's start by getting all the markup from the HTML file, and put it into our file. And our data isn't really structured this way, but we're going to address that in a second. First, let's make sure that we also get the CSS, put it into our notes.component.scss file, and the TypeScript file. And here we don't want to take everything, we're just going to get the displayedColumns to begin with, and let's open up notes.component.ts, and let's go ahead and import the MatTableDataSource. But, we are fetching our data from an API so we can't go ahead and initialize this in the same way as the sample. So let's just define dataSource here as a MatTableDataSource, and go ahead and take this piece of code and initialize the dataSource on ngOnInit instead. But once again, we don't have an element and we don't have element data. So our type here is going to be Note and not Element. And the same goes for the initialization down here. But we're going to feed our dataSource with the notes that we are passing in through our input parameter. Now, regarding the display columns, let's keep the position column, but instead of name, weight, and symbol, we had title and a date. So let's get rid of this last column. So, this is it for the component TypeScript file, now let's head over to the component.html file and see what we'll need to do there. Let's remove the file EXPLORER so all the markup fits on the screen, and we can see that the comment on the top says quite a lot. So, these columns can be defined in any order that actual rendered columns are set as a property on a row definition. So if you scroll down to the bottom, we can see that we have a matRowDef and a matHeaderRowDef. And the header row definition is simply the displayed columns that we just changed in the TypeScript component file. And the row definition simply iterates over the rows according to the displayed columns. So now that we know that, let's go ahead and remove this comment just to save a little bit of real estate. And for our number column, we're going to call this note instead of element since it's notes, and we have an id property on our notes, which we're going to use instead of the position property. Now, let's replace Name with Title, and once again change the variable name from element to note. And let's get rid of these comments as well. And we're just going to need one more column, and instead of weight we're going to display the date. And once again rename the variable to note, and go ahead and render the note.date. And we don't just want to output the raw date, so we're going to use the date pipe to format this by year, month, and day. Now we can go ahead and remove this last column. And before we switch over to the browser let's just fix this typo here because we don't have a name property on out note, it's called title. Alright, so that was hopefully it. Let's head over to the browser and see if we managed to display our data table. Alright, so let's switch to the Notes tab, and yay, awesome, so we're up and running with the data table and we are able to display our user notes in almost no time at all, awesome. But, what if one user has a lot of notes? Is it just as easy to add the pagination? Let's find out.

  41. Adding Pagination So, once again, let's head over to the doc site and let's keep scrolling past this basic table sample and see what else they've got. So down here we can see that they are starting to address the features, and the first one is pagination. What a coincidence. And this looks pretty good. So, how easy is it to adapt this? Let's start by taking a look at the source. And the markup basically looks the same except for this mat-paginator markup. What about the Component file? And we can see once again that they've gone ahead and defined their own sample database along with their own sample data source. Let's take a look at how this looks in StackBlitz. Let's open up the TypeScript file, and once again we can see that instead of defining everything inline this sample is leveraging the MatTableDataSource and just setting the paginator AfterViewInit. And this looks important, so we need to set the paginator AfterViewInit since this component will be able to query its view for the initialized paginator. Okay, so let's start adapting this code. And once again, I'm going to start by just taking the markup as is from this sample and copy/pasting it into our component, and this guy goes below the mat-table. And since we don't have that many notes let's go ahead and decrease this page size to 2 initially, just to see if we get any pagination at all. And now, let's get the code for the component. So, first of all, we're going to get a reference to the paginator using the ViewChild attribute. So let's take all of this and open up our notes.component.ts, and just dump it in there, and start importing the necessary statements. So let's add ViewChild from Angular Core, and the MatPaginator from Angular Material. And let's give ourselves a little bit more space by deleting this comment. So, can this really be it? Do we get pagination this easily? Let's switch back to our browser and find out. So let's open up our app, and hit the Notes tab, and it sure looks like we have a paginator, we can navigate to the next page, back and forth. Let's change how many items we're displaying. It actually seems like it's working. How awesome is that? But, what about filtering? Should we try that out as well? Let's go for it.

  42. Adding Filtering So once again, let's head over to the docs and keep scrolling to see what else they've got. So we've got Sorting, but let's not do that yet. Let's begin with Filtering. Let's just play with it on the docs and this seems pretty neat. Let's take a look at the source. The markup pretty much looks the same, except for this mat-form-field at the top, which is the filter input. What about our TypeScript file? And here we can see things get quite messy, pretty much immediately. Let's hope it looks differently at the StackBlitz sample. So let's take a look into the TypeScript file, and once again, this looks a lot cleaner. So let's see if we can get this running. So once again, let's start with a markup and just take the markup from this sample and copy/paste it into our notes.component.html file. And I like being lazy, so why not also take this CSS that they've got defined for us? So we already have the sample container, and the mat-table definition, so let's go ahead and take these two class styles and dump them into out notes.component.scss file. Alright, and now let's just head over to the TypeScript file and take this applyFilter method and copy/paste it into our notes.component.ts file. And let's try to understand this function here. So, it takes in some sort of filter value, which is the text that we're putting into the UI, and then we are removing the white spaces and the comment tells us that a MatTableDataSource defaults to lowercase matches. So, we simply call to lowercase on the input and then set the filter on the dataSource. So there really isn't much to this. And let's just make sure by taking a look at the markup file again, we have a simple input field that for each keyup stroke we apply the filter with the value from our input textbox. Alright, so let's try this out. Let's switch back to the browser, and once again, come to Notes, and now we have a Filter function at the top. So let's try to filter out all the titles that contain something. And it really seems to work, with almost no effort at all. Alright, so what else is there? Let's try to implement sorting as well.

  43. Adding Header Sorting So let's switch back to the doc site, and we had Sorting above the Filtering guide. And here we can play along with the sample or we can sort on the different columns. And the text tells us that we should only use the matSort directive along with the mat-sort-header to add sorting. Alright, so let's take a look at that. We got the matSort directive there, along with the mat-sort-header directive down here. Other than that, it really looks the same. So, let's head over to the TypeScript file. And once again, things get pretty messy in here, but I don't think we need to worry about all the details in here. Although one detail I'm not seeing immediately is this ViewChild MatSort here that allows us to reference the sort directive. And then it's passed in on ngOnInit. Alright, but let's take a look at StackBlitz to see if this has become simpler as well. So let's open up our app, table-sorting-example TypeScript file, and just as I expected. So, it really looks like it shouldn't be any hassle at all, and instead of doing it on ng init as the sample on the doc set, it seems important to initialize the sort AfterViewInit instead. Let's go ahead and copy/paste the ViewChild reference into our notes.component file, and we're going to need to import MatSort from Angular Material, and then down here where we initialize the paginator let's also initialize sort. Now also, let's switch back so we don't forget to use the matSort directive along with the mat-sort-header. So first, let's add the matSort directive to our table. Let's open up our markup, add matSort, and now let's get the mat-sort-header and put it on our mat-header-cell. So we want to be able to sort each and every column, so let's just add this to all of our three columns, and save this up. Alright, so I think we are ready to go, let's try it out in the browser. Heading over to Notes, we can still filter, that's good, we can change items per page, but can we sort? We can sort on the index, and the Title, and ascending and descending Date, which is quite neat. So, we got a data table with pagination, filtering, and column sorting in almost no time at all. Great work Angular Material team.

  44. Summary In this module we implemented a beautiful-looking data table using mat-table. The key features, provided by the Angular Material team, are pagination, sorting, and filtering. And we saw how quickly we were up and running. We also saw that an excellent alternative to implementing our own data store is to use the MatTableDataSource and feed it with an observable. In our case that was our selected user's notes that we got from our user service. Also, it's essential that we initialize sort and pagination after the view is initialized for the component to be able to query its view for the initial sort and pagination. Now let's see if we can add some new contacts to our application in the next module.

  45. Dialogs and Popups Our Goal Hi, my name is Ajden Towfeek, and this is Angular Material. In this module we'll cover Dialogs and Popups. By the end of this module our application will look as follows, and we'll be able to enter new user data by pressing the Menu item in our toolbar and choose New Contact, which will show us a model dialog with an entry form for creating a new user. And we'll be able to select an avatar, and if we leave the Name field we'll get validation that a name is required. So, let's enter a name and we'll use the date picker to be able to choose a date, but let's just enter my birthdate, and some simple Bio, and Save our user. And we can see that we get navigated to our new user, and the snackbar popped up from the bottom. Now let's implement this.

  46. Adding a Toolbar Menu The MatDialog service can be used to open model dialogs with Material Design, styling, and animations. A dialog is opened by calling the open method with a component to be loaded and an optional config object. The open method will return an instance of mat dialogRef. The mat dialogRef provides a handle to the open dialog. It can be used to close the dialog and to receive notifications when the dialog has been closed, like in this code sample, if the dialogRef closes with the parameter Pizza! we'll receive Pizza! as the result when subscribing to afterClosed. Components created via MatDialog can inject MatDialogRef and use it to close a dialog in which they are contained. When closing, an optional result value can be provided. Once again, let's go with Pizza! Several directives are available to make it easier to structure our dialog content. The mat-dialog-title attribute allows us to set the dialog title applied to a heading element, such as h1 or h2. The mat-dialog-content defines the primary scrollable content of the dialog. The mat-dialog-actions is a container for action buttons at the bottom of the dialog. And finally, the mat-dialog-close attribute can optionally be added to a button, it makes the button close the dialog with an optional result from the bound value. Since the MatDialog is created on the fly the ahead-of-time compiler will not know how to create the proper component factory for our dialog component by default. You must include your dialog class in the list of entryComponents in your module definition, so that the ahead-of-time compiler knows how to create the component factory for it. Now let's go ahead and implement our dialog that will allow us to add new users.

  47. Dialog Basics Now, first of all, we need to decide where to put the Add New Contact button, and I think I'm going to go ahead and add the menu item in the upper-right corner. So, let's head over to the docs and see how we can add buttons or menus to our toolbar. So let's go down to Toolbar and switch to the EXAMPLES. And we can see we have a multi-row toolbar here, not quite what we have got, but more interesting is that we have some kind of title and then a spacer along with an icon. So let's see how they achieve that. So basically we have a span with a class named example-spacer. And we can see that they use flex just to flex out the space. So let's just get this styling, along with the markup, and in Visual Studio Code let's open up our toolbar.component.scss file, and define the spacer. Now let's switch back to the docs site and get the markup as well. Let's copy/paste that icon as well, even though we will replace that one with a button with an icon that will trigger our menu for us. So let's switch back to our code, open up our toolbar markup, and we're not going to use the verified_user icon, let's go with more_vert. Let's also remove this example-icon class here since we won't be using that. And take a look in the browser at what we've got. Alright, so we have the icon, but it's not a clickable menu item yet. So let's see if we can find something about that in the docs site as well. And at the same level as the toolbar we've got Menu here in the NAVIGATION section. And the first sample here displays a basic menu. And this will do just fine. If we scroll down we can see that we can have nested menus as well. And we can see how we can toggle these menus programmatically, but we won't be needing that for our application. So let's just go ahead and stick with this basic sample, view the source, and get the markup. Let's just also make sure that we don't miss anything in the TypeScript file, it doesn't look so, or in the styling file. Alright, so let's switch back to code, and copy/paste in the markup. And instead of just displaying the text Menu we're going to use our mat-icon more_vert dots. Alright, cool, so let's just remove one of the menu items, and change the text to New Contact. So let's see if this works first, before going any further. And we're able to display our menu, but when we click, nothing happens. Let's just go back to our markup and try to understand what we've just copy/pasted in. So basically, we have a button, and we're binding matMenuTriggerFor to something called menu, and menu is our matMenu down here, which we have given the reference menu. So this way we link this button with the mat-menu down below. So pretty straightforward stuff. Let's go ahead and implement our dialog.

  48. Creating our First Dialog Now, let's add a click listener and call a method, openAddContactDialog on our TypeScript file. So let's open up toolbar.component.ts, and define that method. And now that we've done that let's import the mat-dialog and try to open a dialog component. So in the constructor let's resolve a MatDialog and import it from the @angular/material barrel. So MatDialog can open our contact dialog, which we still haven't generated. We could go ahead and define it inline, but I think it's going to be rather big, so let's go ahead and switch to the console and generate a new component for it. So let's generate a component into our contactmanager module under components, and let's call it new-contact-dialog. And as always, no-spec and do a dry-run to make sure it gets to the right place, and that seems about right. So let's go ahead and generate our dialog, and switch back to code, and try to open our newly-created contact dialog component. But first we're going to need to import it into our toolbar component, let's also pass in a configuration object to define the width, to let's say, 450 px. Now, remember that we needed to register our dialog as an entry component, let's see what happens if we don't do it. So let's switch back to the browser and try to press New Contact. And something clearly went wrong, so let's take a look in the console. And, as I suspected, no component factory found for our dialog component. So let's go ahead and add it to the entryComponents, just like the error message tell us to do. So let's switch back to the code and let's open up our contactmanager.module, and scroll down, so we can see that the contact dialog component got declared, but we're going to need to declare it as an entry point as well, due to the AOT compiler, to be able to figure out which component factory to use. Alight, so let's see if this does the trick. So back in the browser let's try to add a new contact, and we got that the contact-dialog works, which is the default text in our component markup file. That's great. So let's go ahead and do something more useful.

  49. Scaffolding a Form Let's open up our toolbar component and declare our dialogRef. This will allow us to subscribe to when the dialog is closed. So dialogRef.afterClosed, let's subscribe to that, and just console.log the results. So let's start by creating some proper dialog content. So let's open up our new-contact-dialog.component.html file and delete the full contents. Now first we want to display a dialog title and we do that by using the mat-dialog-title attribute on our header element. Then let's define the dialog content, which will be the scrollable content, the main content of the dialog, if you will. That followed by the actions, which will contain two buttons for us. One Save button and a Cancel button. So let's declare our Save button first, as a mat-button, with a primary color of the theme, and add a click listener, and if we press save let's call on save, on the TypeScript file, and let's add a nice Save icon there as well. And let's just copy/paste this button, and create our Cancel button, which will dismiss our dialog. Alright, so let's first switch back to the docs and see if we can find some proper dialog content. We probably want some input elements, one for selecting the new user's avatar, and one for name, and one for the birthdate, and one for the bio, one for each property on our user object. So let's go and take a look. So, on the material.angular.io site let's go ahead and take a look at the Form Field section. Let's scroll down, and we can see that we have a simple form field, which could easily be our username, our user's bio, and then let's select an avatar. And we're also probably going to want to use a date picker, but first thing first, let's grab this markup and put it into our main dialog content. And we can see we have some classes here that we're going to need to get as well. So let's take a look under CSS, we can see that they've created an example-container class that will flex in the column direction, and set the width to 100%, which gives this nice look and feel that we want for our dialog as well. So that's just great. So let's open up our SCCS file, and just copy/paste that in there. Now, let's see what we've got in our application so far. So let's trigger the dialog again, New Contact, and we can see that we've got a nice-looking model dialog. Cool, so let's customize this so it fits our needs.

  50. Customizing the Form Now, let's begin with implementing a couple of methods on our dialog component TypeScript file before going any further with the template. So let's open up our TypeScript file and begin with defining our save method along with our dismiss method. And to be able to close dialog from these methods we're going to need to resolve a MatDialogRef that we can find in the angular/material barrel, and we're going to need to type our own component's class name here, and when we dismiss the dialog let's just go ahead and close it, and pass null, and up here we're going to want to pass the user that we just created. So let's go ahead and define a user, which will be of the type user. And let's import this, I'm going to need to put down this. And then on ngOnInit we're going to want to new up our user. And it's the properties of this user that we'll want to bind to and update from our template file. And there are many ways of doing so, I'm going to go ahead with a data-driven approach. If you want to learn more about this, feel free to watch the Angular Forms course, right here on Pluralsight, it's great. Now, let's get back to our template file, and change the placeholder of Input to Name, since it will be our user's name, and then let's bind to a username. And let's also say that this is required. And the text area will hold the user's bio, so let's go ahead and update the placeholder and also bind to user.bio. And let's use the mat select input field to allow us to select the user's avatar. So let's switch back to the docs and see if we can find a good fit. So, let's see what we've got under Select here, and the Basic select allows us to select foods, right, let's keep on scrolling and see if we can find something that allows us to customize the label. Alright, so down here we can see a sample of how we can display a custom trigger label inside our select, because we'll probably will want to display our avatars along with an avatar name, for instance. And to be able to customize a trigger we only need this part, we need to define the mat-select-trigger. So let's go ahead and put that into our mat-select component, and display the actual selected avatar for that user. So svgIcon, and then let's bind to the user avatar, which will be the avatar id in our svgIcon set. And let's also just put out the user.avatar, just for debugging purposes, to see that we're trying to bind correctly to the svgIcon attribute. Alright, so let's change this to avatar for the placeholder, and also let's bind to the user.avatar property. Now, as for the options, we're going to want to iterate over the available avatars. So let's switch to our component file. And just define the available avatars in an array. So let's do that at the top. So we have four avatars right now, so let's just define them right here. Now back in our template file, instead of just putting out one static value like this, let's go ahead and loop over our avatars. And we want to bind to the value of our select option to the avatar. Now instead of just displaying option here, let's get what we just wrote for the select trigger for each option to display the same label. So we want the avatar along with the id. And I'm thinking we probably will want to select the avatar first, so let's move this up to the top. And before we switch to the browser, I just spotted two mistakes here. We're going to want to bind to the variable where we're looping over here, which isn't user/avatar, it's going to be just avatar, and the same goes in here, but also, let's move this out of the mat-icon since we won't see it otherwise. The same goes for our select trigger. Now, let's switch to the browser and see what we've got. Let's trigger our dialog, and since we put down the required attribute we got that asterisk there. We don't see any error messages, let's see what we can do about that later. We can put down Bio if we want, and we can select an avatar for our user. Cool, so let's put something down, and see if it gets logged to the console. So we can see that the dialog was closed, and let's zoom in, and we can see that we got our user object passed back to our toolbar component. Alright, so let's see if we can add some validation message there to a required field, which is the Name, and also let's try to use the date picker to set the birthday of our contact.

  51. Adding Form Validation So, let's head over to the docs again, and under Form field, let's keep on scrolling. I think we'll find something about Error messages. Alright. So, it looks like we only need to add a mat-error element inside our form field. So let's check out this example. So we activated the email filed, and if we leave it we got an error message that says, You must enter a value. Cool. So all they need to do was define the mat-error element, and use a FormControl, which we'll define a TypeScript file, along with the validators we want to use. Alright, so let's get this code here, and I love being lazy, so let's just copy/paste it right into our TypeScript file. And we're going to need to import FormControl from @angular/forms along with Validators from @angular/forms. And we're not going to be validating an email, we just want the required validator for our name field. So let's rename email to name, and go ahead and remove the validation for Not a valid email part. So, if our name FormControl has the error required, we'll provide the error message, You must enter a value. Let's change that to, You must enter a name. Now, let's switch back to the docs site, and get that mat-error element as well. And switch back to our code, open up our markup file, and put in that mat-error element. And instead of email we named it name. And we still want to bind to a username property, but we're also going to need to add the form control binding to our formControl named name. And for this form-driven approach to work, we're going to need to come over to our contactmanager.module and along with the forms module let's import ReactiveFormsModule, and we'll get that from @angular/forms. Now, let's head over to our application and see if we got some validation messages. So once again, we'll add the New Contact, and now if we leave the Name field without entering a value we get the error message You must enter a name. Cool. Now let's take a look at that date picker.

  52. Using the DatePicker Once again, let's start out from the material.angular.io doc site, head over to Components, and see what we've got on the Datepicker. So we have an input and an icon. And when we press the icon we get this nice-looking dialog that allows us to select a date. And when the date is selected the input field is updated. So let's check out the markup for this. So the key parts here are that we'll need to define a mat-datepicker and give it an id picker. Then we can use this id to reference it, both from the input field and from the mat-datepicker toggle, which is this button right here. So let's get this markup and drop it into our markup file right beneath the name field. And let's put down Born as the placeholder, and just bind to the birthDay property on our user. Cool, so this should be it. Let's make sure it works in the browser. So once again, let's trigger the dialog from the menu, select an avatar, put down a name, just pick a date to make sure it's passed along to our toolbar component, and put down some Bio, and press Save. Let's open up the developer console and see that we got everything passed back to the toolbar component, and it seems so. Awesome. So let's try to save this user using a user service.

  53. Saving the User Now, let's open up our TypeScript file, and try to save this user. And for that we're going to use our UserService. Let's go ahead and resolve that into our constructor. We're going to need to import the UserService, and instead of just closing the dialog here I want to call it on a method on a UserService that will allow us to add a user. And if that was successful, because otherwise we want to keep the dialog open and say that we failed to save, but that is out of the scope for this course, but let's at least return a promise from a service that we'll be able to chain and then call back to. So then we'll get the user back and let's pass that user back to our component. Cool, so let's head over to our UserService and implement this method. Let's go ahead and create a new method, addUser, that takes a user and returns a Promise with a saved user, and let's return our Promise here. And for the sake of this demo we're just going to resolve with our user and never really reject this because we'll be able to do this every time, we won't even do an HTTP call. So first of all, we're going to want to simulate that we got a new id from a database, for instance, for our user. So let's just go ahead and set the id to the dataStore.users.length array, and then just add 1. So if you had 4 users earlier, now our new user will get the id 5, which seems simple enough for this demo implementation. Next we're going to want to push that user to our internal dataStore. And then, once again, make sure that our components that are subscribing to our behavior subject gets notified. So let's just copy/paste that code down here from the loadAll method, and do it here as well. And this will need to be a resolver for this to work. Alright, so now we actually save the user, so it should be displayed in our sidenav, let's make sure that happens. So, from the menu item, New Contact, add a name, a date, and a bio. Now, let's Save this user, and yes, it showed in the sidebar. Cool. But we probably wanted the newly-added user to be displayed or at least get the option to display him. And maybe even get notified somehow. Hmmm, let's use the snackbar for that. It will display a message for us and allow us to execute an action. Let's do that next.

  54. Snackbar Notifications So let's switch back to the Angular Material docs site, and go ahead and find Snackbar under POPUPS and MODALS. And if we scroll down a bit we can see that it's very easy to open a snackbar, we just use the service snackBar and call a method open. And we can either open a component or just display a text along with an action. So, let's just head up to the sample and see what we need to resolve into our constructor. So we just need a MatSnackBar, so let's go ahead and get that. And in our constructor, along with our dialog, let's also resolve the snackBar, and let's make it private. And switch back to the docs site and let's snatch this little method here that allows us to open a snackbar with a message and an action. Let's define that below our openAddContactDialog. Now let's try to open that snackBar. So, if we didn't get null passed back because we were able to dismiss the dialog as well without saving, then we want to call this.openSnackBar, and display the message Contact added, along with an action, let's call it Navigate. And then we want to actually navigate when the action is pressed. So if we head back to the docs, we can see that the open method returns a snackBarRef. So let's go ahead and define that as well. So our openSnackBar will return a MatSnackBarRef. And let's import that from Angular Material, and also make sure to return the snackBar. And we can see that TypeScript isn't satisfied. So let's take a look at what open returns for us. Open returns a MatSnackBarRef of the type SimpleSnackBar. So let's go ahead and put that down as well. Now we can safely go ahead and subscribe to when onAction was pressed. And here we want to navigate to our contact that was just added. And to be able to do that we're going to need to resolve the router into our constructor. So let's go ahead and do that and format this up just a little bit so it fits nicely to the screen, and resolve the router into a constructor. So let's import that from @angular/router, and now we can safely navigate to our contactmanager route and pass in our newly-created contacts id. And just to give ourselves the chance to actually press that button let's change the duration to 5 seconds. Alright, so let's switch back to our browser and see if this works. Let's add a New Contact, enter a name, and let's just leave everything out, and press Save. We can see our contact was added, and we're able to navigate to that contact. Cool, so does it work on a mobile device as well? So let's add a New Contact, select an avatar, put in a name, and press Save. And the snackbar displays, and we're able to navigate to our new contact. Awesome. So, let's wrap up this module.

  55. Summary The MatDialog service can be used to open model dialogs with Material Design, styling, and animation. The open method will return an instance of MatDialogRef, which is the handle to the opened dialog. And since the MatDialog is created on the fly, you'll need to declare the dialog as an entry component for the ahead-of-time compiler to be able to create the proper component factory to create the dialog. MatSnackBar is a service for displaying snackbar notifications. The open method will return an instance of MatSnackBarRef. For messages with an action the MatSnackBarRef exposes an observable onAction for when the action is triggered. Now we're almost finished with our application, let's round things up in one final module.

  56. Wrapping Up Understanding Themes Hi, my name is Ajden Towfeek, and this is Angular Material. In this module we'll wrap up the course and add some features to our application that were overlooked, such as theming and right-to-left and left-to-right support. Let's first define what a theme is. A theme is a set of colors that will be applied to Angular Material components. It's created by composing multiple palettes. In particular, a theme consists of a primary palette. These colors are most widely used across all screen and components. An accent palette. These colors are used for floating action buttons and interactive elements. A warn palette. Colors used to convey error states. A foreground palette. And these colors are used for text and icons. And finally, a background palette. These colors are used for element backgrounds. In Angular Material all theme styles are generated statically at build time so that your app doesn't have to spend cycles generating theme styles on startup. Angular Material comes prepacked with several prebuilt theme CSS files, and we only have to include a single CSS file for Angular Material in our app to apply one. And if we're using Angular CLI, as we do in this course, this is as simple as including one line in your styles.css file, or styles.scss file. We can include a theme file directly into our application from @angular/material/prebuilt-themes. Available prebuilt themes are deeppurple-amber, indigo-pink, pink-bluegrey, and purple-green. When we want more customization than a prebuilt theme offers, we can create our own theme file. A custom theme file does two things, it imports the mat-core sass mixin. This includes all common styles that are used by multiple components. This should only be included once in our application, and that's really important. Because if the mixin is included multiple times our application will end up with multiple copies of these common styles. And we typically included the ones in either styles.css or styles.scss. Secondly, a custom theme file defines a theme data structure as the composition of multiple palettes. This object can be created with either the mat-light-theme function or the mat-dark-theme function. And we'll see this in action in a little bit. A typical custom theme file could look as the following. First we include the common styles for Angular Material. And, be sure to do this only once. We then define the palettes for our theme using the Material Design palettes available in palette.scss. That's what we imported above. For each palette we can optionally specify a default lighter and darker hue. The warn palette is optional, it defaults to red. We then composed our theme object, a SCSS map containing all of the palettes. And finally, we include theme styles for core and each component used in our app.

  57. Creating Custom Themes Now, we're going to define our custom themes in our styles.scss file. So, let's begin with commenting out the import of this prebuilt indigo-pink theme. Now first we need it to include the common styles for Angular Material, and we need to make sure that we include this only once. Then we're going to define the palettes for our theme. And each palette we can optionally specify a default lighter and darker hue. The warn palette is optional, but it defaults to red. And finally, we compose our theme object as a SCSS map containing all of the palettes, using mat-light-theme. Now all we need to do is include the theme styles for core and each component used in our app. Cool, so here we have just defined the default theme that we've just commented out the indigo-pink one, so let's go ahead and create a dark theme as well. We used mat-light-theme for this default theme, so let's create something different. So if we want to create multiple themes for our application we can just include the Angular Material theme mixin multiple times, but we'll need to gate it by an additional CSS class. So let's create dark-theme. And in here we can define a new set of palettes, but this time when we compose our palettes we're going to use mat-dark-theme instead. And then, all that is left to do is to create the theme from the palettes. Cool. So how can we try this out? So, before implementing toggle functionality let's just come to the sidenav.component.html file and add the dark-theme class to the container. Now let's switch over to the browser and see what we've got. Alright, so we've got a dark theme instead, pretty cool. But, wouldn't it be nice if we could toggle the theme from the menu? Let's try to implement that.

  58. Toggling Themes Let's add a new button that will allow us to toggle theme. And since our toolbar is within out sidenav we're going to need to emit an event to the parent, which is the sidenav and let the sidenav toggle the class. So, in here we're just going to listen to the click event and emit an event. So, let's switch to the TypeScript file and along with the toggleSidenav event also define a toggleTheme event. Now we can navigate to sidenav.component.html, and on our toolbar where we listen for the sidenavToggle let's also listen for toggleTheme. And now, we need to implement toggleTheme. So let's head over to the sidenav TypeScript file and add a method, toggleTheme. And we're going to need to introduce a new variable. So let's declare isDarkTheme, and that's going to be a Boolean, and let's initialize it to false. And whenever we want to toggle the theme we just want to toggle the value of the isDarkTheme. Cool, so now we are ready to bind to this Boolean, so let's switch over to sidenav, and where we just put down dark-theme in the class definition let's do a CSS binding there instead. So let's add the class dark-theme if isDarkTheme is true. Alright, so let's head over to the browser and try this out. And from the menu in the toolbar let's emit the event that our sidenav listens to and then toggle the theme. So it works. Cool.

  59. RTL and LTR Support A rather undocumented features so far is right-to-left support, but it's just as easy as toggling a class for a dark theme. We can just go ahead and set the direction attribute to right-to-left, and if we switch over to the browser we can see that instead of left-to-right, which is the default, we got the layout from right-to-left, but what about toggling the direction, just as we were able to toggle the theme. Let's try to implement that. So let's do the same thing as we did for the theme. Head over to toolbar.component.ts. Create a new event that we'll be able to subscribe to, but let's call it toggleDir. And in our toolbar HTML file we can just copy/paste this previous button and change it to toggleDir in the same manner. Alright, so we are emitting the event from the toolbar, let's also listen to it from our sidenav.component.html. Now we can get this line here and just copy/paste it and change toggleSidenav to toggleDir instead. And now, we need to implement toggleDir in our sidenav.component.ts file. So let's open up that file, and define that below toggleTheme, and we're going to want to introduce a variable here as well. So let's introduce dir, which will be a string, and let's initialize it to left-to-right. Now it's not as straightforward for toggling a string literal as toggling a Boolean, so here we want to check if the direction was left-to-right, then we want to change it to right-to-left instead, otherwise toggle it back to left-to-right. Pretty straightforward. And now we're ready to switch back to the sidenav component, and instead of setting the direction statically we can bind to the attribute and the value direction on our TypeScript file. Alright so let's switch back to the browser and see what we've got. So, be default we are displaying everything from left-to-right. Let's try to toggle to right-to-left. So it toggled, but for some reason we got this area on the left that was the sidenav previously. So this currently seems like a bug in the framework. But let's see if we can somehow work around that. Perhaps, if we bring out the developer console and toggle the sidenav, it disappears, and it does. So, that looks like a reasonable workaround, let's see how it behaves on a mobile device. So we don't have the same issue here since we are not displaying the sidenav all the time. But as soon as we are on a big screen we need to toggle the sidenav whenever we toggle the direction. So let's head over to the code, and open up our sidenav.component.ts file. And whenever we toggle the direction let's also toggle the sidenav. And when we toggle the sidenav we want to toggle it back, because remember, on big screens, we always want to show the sidenav, so if we were displaying a sidenav and we toggle it so it disappears, we're going to want it to appear again. So then we can just chain a then callback, and whenever we are finished with the first toggle we want the sidenav to toggle again. Let's try this out. Right, so we are toggling the direction, and then the sidenav toggled for us to correct the whitespace that we had on the left side. So let's toggle back, and it seems like we've found a reasonable workaround for the current bug. Cool, so now we have left-to-right and right-to-left support, in almost no time at all.

  60. Final Words In this module we've learned that Angular Material comes with a couple of prebuilt themes, deeppurple-amber, indigo-pink, pink-bluegrey, and purple-green. And it's as simple as including a single CSS file to apply one of them. We can also create our own theme file, a custom theme file does two things. First it imports the mat-core SCSS mixin and then defines a theme data structure as the composition of multiple palettes. We also saw how to create multiple themes for our application by including the Angular Material theme mixin multiple times, where each inclusion needs to be gated by an additional CSS class. And a rather undocumented features so far is the right-to-left support. We learned how to bind to the direction attribute and toggle between right and left and left to right. I hope that you've enjoyed watching this course, and if you're still with me here at the end I bet you learned a whole lot and found it interesting. I also hope that I've showed you how to build any application, not just this specific contact manager. Navigating back and forth between the official docs and customizing official samples is a workflow I apply in my profession as a consultant on a daily basis, not just for Angular Material, really for whichever technology stack or framework I'm using at the time. Now, the best way to learn more is to build something on your own, so go do that now. And make sure to let me know what you think about this course in the comment section, and if you feel something is missing, I'll try to update this course as frequently as possible, as the Material team releases new components. For updates make sure to follow me on Twitter and YouTube. And, until next time, have a nice day and stay curious.