Angular Material - Part One

Introduction

Here, we’ll learn about Angular Material which is a collection of components that give our applications modern look and feel. And more specifically we’ll learn how to
  • Work with various kinds of components such as FormControl, Icons, Dialog Boxes, Progress Spinners, Tooltips, and so on
  • Use Pre-Built Themes
  • Create Custom Themes
  • Use Angular Material’s Typography
  • Create Custom Typography for your applications

Let’s get started.

What is Angular Material?

Angular Material is a library of reusable and high-quality UI components that are built with Angular and TypeScript. These components are internationalized so users with different languages can use them. We have a clean and simple API. They are well-tested with unit and integration test. They are customizable. They are very fast with the very minimal performance overhead and they are almost well documented. So, let’s see a few examples of this component in action.

So, go to this link and open the Angular Material Components.

Angular Material

We can see we have various kinds of components. We have Form Controls, Navigation, Layout, Button & Indicators, Popup & Modals, and Data table components here. So, let’s see a few of these in action. So, click on Form Controls and you’ll see this page.

Angular Material

Now, click on Checkbox and click on the Examples tab of the checkbox. We can see checkboxes and radio buttons in action. So, these checkboxes have the same API as the native checkboxes we use in Angular. But you can see they’re looking pretty.

Angular Material

And if you click on any checkbox, they also have nice animations. And we can use them very nicely in our application by using Angular Material. Similarly, here, we have modals & popup elements in the different component with very nice animation. And if you explore the examples of different components here, you’ll be the huge fan of Angular Materials.

Now you might think we have dialog boxes, checkboxes, and all the stuff already in Bootstrap then why should we use the things of Angular Materials? As you know Bootstrap and Angular Material libraries built by different teams. Bootstrap was developed a few years ago with plain javascript and it has nothing to do with Angular. So, we can’t easily use all the JavaScript code that we have in Bootstrap in our Angular applications. We need to create custom directives or custom components and do some magic in order to use those components.

Angular Material, on the other hand, is built specifically for the Angular applications. So we don’t have to do anything magical. We can simply import the module and use Angular Material components just like how we use custom components. Also in terms of statics, Bootstrap have different design language. All the bootstrap components have a different look and feel whereas Angular Material is based on the Material design which is a visual language developed by Google in 2014. This is the same language that you see on Google Plus, in Android and many other applications. So, the answer to the above question is we can use bootstrap, we can use Angular Material, we can use both.
Angular Material

Angular Material is still new. It doesn’t have all the components that we have in Bootstrap. So if you want to build an application with complex UI, the chances are that some of the components you need are not the part of Angular Material but you’ll find them in Bootstrap. And as we know that we can’t use Bootstrap javascript easily in our Angular applications, we’ve to use 3rd party components that are based on Bootstrap. And that means our application is going to have a lot of dependencies to libraries built by others. And these libraries can break at any time. That’s why I personally prefer Angular Material because all the components are built with the same list of quality standards. We have the common API that is well tested and we can easily use them in our Angular applications.

Note
You might see many articles and tutorials working with md- prefix component selector. But now it is depreciated. So, don’t confuse. We’re using mat- prefix here.

Installing Angular Material

Step 1

So, let’s see how to install Angular Material. Here are the steps to install the Angular Material in your project. So, let’s see these steps in action.

  • PS C:\Users\Ami Jan> mkdir material-demo
  • PS C:\Users\Ami Jan> cd ./material-demo
  • PS C:\Users\Ami Jan\material-demo> ng new material-demo
  • PS C:\Users\Ami Jan\material-demo> cd ./material-demo

And now we need to install a couple of node packages

PS C:\Users\Ami Jan\material-demo\material-demo> npm i --save @angular/cdk @angular/material @angular/animations hammerjs

@angular/cdk stands for Component Development Kit which is one of the dependencies of Angular Material and it is basically a library that allows you to build awesome components for the web but without adopting the material design visual language. So if you wanna build a reusable data table that doesn’t necessarily have the material design visual language, we can build it with cdk in an agnostic way.

@angular/material this is the actual @angular/material package. These 2 are the essential packages that we need to install.

Now optionally we can install a couple more packages 1 is for adding animations and the other one is for the gesture. For gesture support, we need to install hammer.js. So, hammer.js is the powerful library that allows you to add gesture support to your pages. But again, it is an optional dependency but I would recommend you to add it to your application.

Step 2

After installing the packages successfully. Now it is the time to include the theme. Go to this path

node_modules/@angular/material/prebuilt-themes/

So here, we have a bunch of themes. But we’ll use indigo-pink.css. And you can use any other you prefer.

Let’s go to styles.css and here we need to import them just like we imported bootstrap before. We add the relative path of node_modules.

  1. @import "~@angular/material/prebuilt-themes/indigo-pink.css";  

Make sure to spell it properly, otherwise, it is not gonna work.

Step 3

Now, go to the app.module.ts. Here if we wanna add animations support, we need to import BrowserAnimationsModule.

  1. Import Statements:  
  2. import { BrowserModule } from '@angular/platform-browser';  
  3. import { BrowserAnimationsModule } from '@angular/platform-browser/animations';  
  4. imports: [  
  5.     BrowserModule,  
  6.     BrowserAnimationsModule  
  7. ]  

I’ve just provided the changes above. So, this is the implementation of the animations module in the browser. And if you don’t want have animations, instead of BrowserAnimationsModule, you need to import NoopAnimationsModule. So,

  1. import { BrowserModule } from '@angular/platform-browser';  
  2. import { BrowserAnimationsModule } from '@angular/platform-browser/animations';  
  3. import { NoopAnimationsModule } from '@angular/platform-browser/animations';  
  4. import { NgModule } from '@angular/core';  
  5. import { AppComponent } from './app.component';  
  6. @NgModule({  
  7.     declarations: [  
  8.         AppComponent  
  9.     ],  
  10.     imports: [  
  11.         BrowserModule,  
  12.         BrowserAnimationsModule  
  13.     ],  
  14.     providers: [],  
  15.     bootstrap: [AppComponent]  
  16. })  
  17. export class AppModule {}  

So now, we need to import one of these Modules (BrowserAnimationModule, NoopAnimationsModule) into our NgModule. And here, we have imported BrowserAnimationsModule in the imports array.

So, these are the 3 steps we need to follow in order to install the Angular Material. Now, to make sure we have installed Angular Material properly, let’s go ahead and add the checkbox into our component. So, let’s go to app.component.html and delete all the markup here and add the checkbox and give it a label.

  1. <mat-checkbox> Subscribe to NewsLetter </mat-checkbox>  

So in Angular Material, we have a custom component for rendering the elements and this md-checkbox is the selector of checkbox component of Angular Material. Now, run the application.

PS C:\Users\Ami Jan\material-demo\material-demo> ng serve

Now, let's get back in the browser and here, we get the blank screen. We know the meaning of the blank screen - we have some error in the console.

Angular Material

So, the error is ‘mat-checkbox’ is not a known element because we have used the custom component but we have not imported this component into our app.module.ts. So let’s go back to app.module.ts.

Every component in Angular Material is defined in a separate module, so we need to go on the top in app.module.ts and import this module and then adds it into the imports array of NgModule. But how do we know what module a component is defining? So let’s go back to this page. We can see the name of the module in which this checkbox component is defined in,

  1. import {MatCheckboxModule} from '@angular/material/checkbox';  

And now, add it in the app.module.ts.

  1. import { BrowserModule } from '@angular/platform-browser';  
  2. import { BrowserAnimationsModule } from '@angular/platform-browser/animations';  
  3. import { NoopAnimationsModule } from '@angular/platform-browser/animations';  
  4. import { MatCheckboxModule } from '@angular/material/checkbox';  
  5. import { NgModule } from '@angular/core';  
  6. import { AppComponent } from './app.component';  
  7. @NgModule({  
  8.     declarations: [  
  9.         AppComponent  
  10.     ],  
  11.     imports: [  
  12.         BrowserModule,  
  13.         BrowserAnimationsModule,  
  14.         MatCheckboxModule  
  15.     ],  
  16.     providers: [],  
  17.     bootstrap: [AppComponent]  
  18. })  
  19. export class AppModule {}  

And now, we have a beautiful modern checkbox with animation.

Angular Material

Check Boxes

Now, let’s continue with checkbox we have added. So this checkbox component in Angular Material implements a very similar API to the native checkbox we have in Html5. For example, in html5 in order to add checkbox we need to use input element with checkbox type and if we want to add a bunch of attributes

  1. <input type="checkbox" checked="checked" value="">  

So our custom checkbox in Angular Material also has these properties. So once again, if you open this link, you can find all the properties implemented in this component. I’ve attached the link of API/Directives, here you can see the name of the component and all its input and output properties, methods etc. There is not enough time to go through each of these properties but let’s discuss a few key properties that you’re going to use in a lot of real-world applications.

Back in app.component.html,

  1. <mat-checkbox> Subscribe to NewsLetter </mat-checkbox>  

Here we can set the value exactly the same way of a native checkbox

  1. <mat-checkbox value="2"> Subscribe to NewsLetter </mat-checkbox>  

Or we can use property binding.

  1. <mat-checkbox [value]="fieldOrPropertyInComponent"> Subscribe to NewsLetter </mat-checkbox>  

Similarly we have checked property here,

  1. <mat-checkbox [value]="" checked="checked"> Subscribe to NewsLetter </mat-checkbox>  

And if we want to make it dynamic then obviously we have an option of property binding syntax.

  1. <mat-checkbox [value]="" [checked]="isChecked"> Subscribe to NewsLetter </mat-checkbox>  

And in the component here we define the property,

  1. export class AppComponent {  
  2.     title = 'app';  
  3.     isChecked = true;  
  4. }  

Now if you open the browser. You’ll see checkbox is checked.

We also have change event that we can subscribe here.

  1. <mat-checkbox [checked]="isChecked" (change)="onChange($event)"> Subscribe to NewsLetter </mat-checkbox>  

Now implement this event in the component,

  1. export class AppComponent {  
  2.     title = 'app';  
  3.     isChecked = true;  
  4.     onChange($event) {  
  5.         console.log($event);  
  6.     }  
  7. }  

Here is the output we get on checkbox click,

Angular Material

And this is our $event object and it has 2 properties (source which references to our MatCheckbox class and checked)

Now let’s suppose we have a div on the view and we’re using checkbox to show and hide the details.

  1. <mat-checkbox #showDetails [checked]="isChecked" (change)="onChange($event)"> Show Details </mat-checkbox>  
  2. <div *ngIf="showDetails.checked"> Some Details.... </div>  

Now back in the browser. Now toggle the checkbox and watch the effects.

Radio Buttons

Another component that is very similar to the checkbox is the radio button. So back in the Angular Material website, under components page, select radio buttons. So, the quick tip is whenever you wanna work with component look at this overview tab here you’ll see a very simple example of using that component,

Angular Material

And if you click the view source, you’ll see the markup that you need to write to render this component. As we can see in the picture, we make the radio-group. Inside that radio-group, we place the radio controls to make only one selectable there. And of course, we may have many radio-groups on 1 web page.

  1. <mat-radio-group>  
  2.     <mat-radio-button value="1">Male</mat-radio-button>  
  3.     <mat-radio-button value="2" [checked]="isChecked">Female</mat-radio-button>  
  4. </mat-radio-group>  

And of course we can use property binding syntax here as well like we do before with checkbox component. And here Female is checked by default when you open the browser.

Don’t forget to import each component module in your app.module.ts

Whenever you use any Angular Material component, make sure you import the module first in app.module.ts. Under component API tab you’ll find the API reference import statement to enable working for that specific component which you wanna use.

If you look at the documentation for this radio button, here we have some input and output properties. Here, we also have a value input property. So we can set the value of the group and this will automatically check the radio button with that value. Let’s see in action.

  1. <mat-radio-group value="2">  
  2.     <mat-radio-button value="1">Male</mat-radio-button>  
  3.     <mat-radio-button value="2">Female</mat-radio-button>  
  4. </mat-radio-group>  

This will automatically check the female radio button in the browser.

You can see how these components are really very easy to use.

Drop-Down Lists

Now let’s see how to render the drop-down list, here is the link. I’ll not repeat the things which are the same in each component. Now, you know 70-80% about Angular Material. They are actually very easy to use.

Let’s go to the overview tab and look at an example.

Angular Material

Look how much they are really very simple to understand. This code is very similar to the native select an option element we have in HTML5. Now let’s come back to app.component.html and add a native html5 drop-down list and then convert it to an Angular Material drop-down list.

  1. <select>  
  2.     <option value=""></option>  
  3. </select>  

Now, let’s print the options based on the array list. So come back to the component.

  1. export class AppComponent {  
  2.     colors = [{  
  3.         id: 1,  
  4.         name: 'Red'  
  5.     }, {  
  6.         id: 2,  
  7.         name: 'Green'  
  8.     }, {  
  9.         id: 3,  
  10.         name: 'Blue'  
  11.     }];  
  12. }  

Now, back in the template and here we gonna apply ngFor directive to repeat these array options.

  1. <select>  
  2.     <option *ngFor="let color of colors" [value]="color.id">{{ color.name }}</option>  
  3. </select>  

So, this is our native html5 dropdown list. Now, if you see the result in the browser.

Angular Material

We got something weird. But we can do better. So, let’s convert it into the Angular Material dropdown list. So, first of all, verify the dropdown list component in app.module.ts.

  1. Import statements: import {  
  2.     MatRadioModule  
  3. } from '@angular/material/radio';  
  4. import {  
  5.     MatSelectModule  
  6. } from '@angular/material/select';  
  7. import {  
  8.     MatCheckboxModule  
  9. } from '@angular/material/checkbox';  
  10. imports: [  
  11.     BrowserModule,  
  12.     BrowserAnimationsModule,  
  13.     MatCheckboxModule,  
  14.     MatRadioModule,  
  15.     MatSelectModule  
  16. ]  

And now, all just prefix our HTML5 dropdown list template code with mat. Now, our new code is,

  1. <mat-select>  
  2.     <mat-option *ngFor="let color of colors" [value]="color.id">{{ color.name }}</mat-option>  
  3. </mat-select>  

Now, back in the browser, it will not be visible to you.

Angular Material

However, we don't have any error message in the console. So, don’t confuse to see the white screen. It is not actually white. It has a dropdown list with maximum width. Now, let’s pre-select one of the items here to make it more clear to you. And to pre-select we need to use ngModel directive.

  1. <mat-select [(ngModel)]="color">  
  2.     <mat-option *ngFor="let color of colors" [value]="color.id">{{ color.name }}</mat-option>  
  3. </mat-select>  

Now, let’s define the color property.

  1. export class AppComponent {  
  2.     colors = [{  
  3.         id: 1,  
  4.         name: 'Red'  
  5.     }, {  
  6.         id: 2,  
  7.         name: 'Green'  
  8.     }, {  
  9.         id: 3,  
  10.         name: 'Blue'  
  11.     }];  
  12.     color = 2;  
  13. }  

Now, let’s open the browser and see what we get.

Angular Material

We got an error because ngModel directive is defined in the forms module and because this is the brand new Angular project and we have not imported the forms module. So back to app.module.ts and add the FormsModule in imports array.

  1. imports: [  
  2.     BrowserModule,  
  3.     FormsModule,  
  4.     BrowserAnimationsModule,  
  5.     MatCheckboxModule,  
  6.     MatRadioModule,  
  7.     MatSelectModule  
  8. ]  

Now, back again in the browser,

Angular Material

Now, we have green selected by default.

So, to convert the native HTML 5 dropdown list to an Angular Material, all we have to do is to prefix the elements with mat-, very easy.

Inputs

Now, let’s see how to work with Angular Material input controls. Let's take a look at the markup.

Angular Material

So here, we have a form containing mat-form-field with plain html5 input elements. These input elements have a directive mdInput. You might be thinking why we need from here, because we may have a few other elements as well here with input fields, we can have error messages so we put all these inside forms. It is very near to our plain HTML code.

  1. <form>  
  2.     <mat-form-field>  
  3.         <input type="text" matInput placeholder="Username">  
  4.     </mat-form-field>  
  5. </form>  

Now back in the browser, make sure that you’ve added component module reference in app.module.ts.

And after all the verification and if we’re correctly working according to the guidance of angular material documentation, it will show us the results in the browser. And here we get an input with username placeholder successfully.

Angular Material

Now, let’s take this form to the next level.

  1. <form>  
  2.     <mat-form-field>  
  3.         <input type="text" matInput placeholder="Username">  
  4.         <mat-hint>Type a unique name.</mat-hint>  
  5.         <span matSuffix>@domain.com</span>  
  6.         <span matPrefix>admin.</span>  
  7.     </mat-form-field>  
  8. </form>  

And here is the result what is going on with this form code.

Angular Material

Now, let’s add the form validation on the form.

  1. <form>  
  2.     <mat-form-field>  
  3.         <input type="text" matInput placeholder="Username" required>  
  4.         <mat-hint>Type a unique name.</mat-hint>  
  5.         <span matSuffix>@domain.com</span>  
  6.         <span matPrefix>admin.</span>  
  7.         <mat-error> The username field is required. </mat-error>  
  8.     </mat-form-field>  
  9. </form>  

Previously in the article of Template driven forms, we used div to the couple of bootstrap classes for rendering an error. We used alert and alert-danger. But here, when using Angular Material, we use mat-error and by the way make sure not to use bootstrap classes here for example adding a class form-control to input field. We should not add these classes because it will mess up with the appearance of your Angular material components. So you should either use bootstrap or Angular Material when you’re building a form.

Here, we have 2 methods to add the validation error.

We need to add formControl to keep track of the validity of input fields. And here, we’re using Template Form Approach. So,

  1. <form>  
  2.     <mat-form-field>  
  3.         <input ngModel name="username" type="text" matInput placeholder="Username" required>  
  4.         <mat-hint>Type a unique name.</mat-hint>  
  5.         <span matSuffix>@domain.com</span>  
  6.         <span matPrefix>admin.</span>  
  7.         <mat-error> The username field is required. </mat-error>  
  8.     </mat-form-field>  
  9. </form>  

Now, with the help of this code, Angular creates the formControl object and associated with this input field. Run the application and leave it blank we’ll see red error message.

Now, we want to display mat-error if the field has an error. So,

  1. <form>  
  2.     <mat-form-field>  
  3.         <input ngModel #username="ngModel" name="username" type="text" matInput placeholder="Username" required>  
  4.         <mat-hint>Type a unique name.</mat-hint>  
  5.         <span matSuffix>@domain.com</span>  
  6.         <span matPrefix>admin.</span>  
  7.         <mat-error *ngIf="username.invalid && username.errors.required"> The username field is required. </mat-error>  
  8.     </mat-form-field>  
  9. </form>  

With this, we can have multiple errors of different kinds. Now, let’s see the markup result.

Angular Material

And now, the 2nd complex approach is using Reactive Forms.

  1. <form>  
  2.     <mat-form-field>  
  3.         <input [formControl]="username" type="text" matInput placeholder="Username" required>  
  4.         <mat-hint>Type a unique name.</mat-hint>  
  5.         <span matSuffix>@domain.com</span>  
  6.         <span matPrefix>admin.</span>  
  7.         <mat-error *ngIf="username.hasError('required')"> The username field is required. </mat-error>  
  8.     </mat-form-field>  
  9. </form>  

And now, our component code is like below.

  1. import {  
  2.     FormControl,  
  3.     Validators  
  4. } from '@angular/forms';  
  5. import {  
  6.     Component  
  7. } from '@angular/core';  
  8. @Component({  
  9.     selector: 'app-root',  
  10.     templateUrl: './app.component.html',  
  11.     styleUrls: ['./app.component.css']  
  12. })  
  13. export class AppComponent {  
  14.     username = new FormControl('', [  
  15.         Validators.required,  
  16.         Validators.email  
  17.     ]);  
  18. }  

But this code will only work if you have import the reactive forms module in app.module.ts.

  1. Import statement is: import {  
  2.     FormsModule,  
  3.     ReactiveFormsModule  
  4. } from '@angular/forms';  
  5. imports: [  
  6.     BrowserModule,  
  7.     FormsModule,  
  8.     ReactiveFormsModule,  
  9.     BrowserAnimationsModule,  
  10.     MatCheckboxModule,  
  11.     MatRadioModule,  
  12.     MatSelectModule,  
  13.     MatInputModule  
  14. ]  

Now let’s see the results in the browser. Both have the same results.­

Text Areas

So what we had learn about input fields also applies to text area elements. Let’s see an example with plain html5 textarea element.

  1. <textarea rows="2"></textarea>  

It will give us this output.

Angular Material

Now, to give this material design look and feel.

  1. <form>  
  2.     <mat-form-field>  
  3.         <textarea matInput rows="2"></textarea>  
  4.     </mat-form-field>  
  5. </form>  

And now this is what we get,

Angular Material

But when we put a lot of text inside, it contains the scroll instead of auto resize. So here we have also the solution to this problem.

Under the API tabs under the list of directives, we have interesting directive matTextareaAutosize. So, we can apply this directive to the textarea and this will automatically resize that textarea to fit its content.

  1. <form>  
  2.     <mat-form-field>  
  3.         <textarea matInput matTextareaAutosize rows="2"></textarea>  
  4.     </mat-form-field>  
  5. </form>  

Here is what we get,

Angular Material

Textarea is expanding to fit its content. In the old days we have to implement this using javascript/jquery. But now we can easily achieve this functionality using Angular Material component selectors.

Date Picker

Now that we know how input fields work in Angular Material. Let’s take a look at the Date Picker component. So here, in the Angular Material website, look at this date picker so here in app.module.ts, we’ll import MatDatepickerModule.

  1. Import Statement  
  2. import {  
  3.     MatDatepickerModule  
  4. } from '@angular/material/datepicker';  
  5. imports: [  
  6.     BrowserModule,  
  7.     FormsModule,  
  8.     ReactiveFormsModule,  
  9.     BrowserAnimationsModule,  
  10.     MatCheckboxModule,  
  11.     MatRadioModule,  
  12.     MatSelectModule,  
  13.     MatInputModule,  
  14.     MatDatepickerModule  
  15. ]  

Ok now back in the documentation let’s take a look at the overview tab let’s see on this example,

Angular Material

If we click on Choose a date icon right side of the control.

Angular Material

Look how beautiful this datepicker is. Now, let’s take a look at the markup of the datepicker. Open app.component.html, if we’re working with form then obviously this datepicker is just a single form control of that form. And we put the angular material components in the form element.

  1. <form>  
  2.     <input type="text" matInput>  
  3.     <mat-datepicker></mat-datepicker>  
  4. </form>  

Now, we need to connect this datepicker to this input field, we created above to the mat-datepicker. So first we need to assign a variable to the mat-datepicker.

  1. <mat-datepicker #birthdate></mat-datepicker>  

And then on the input element we apply.

  1. <form>  
  2.     <input type="text" matInput [matDatepicker]="birthdate">  
  3.     <mat-datepicker #birthdate></mat-datepicker>  
  4. </form>  

So in this way, we linked these 2 elements. Now, let’s test the application in the browser.

Angular Material

Here we get this error in the console. Now, what is the problem? We have already imported Datepicker component in app.module.ts, so as we can see in the error message, we need to import one more module to our app.module.ts for the support of MatDatepicker. Actually, our MatDatepicker is built on top of the native date objects in JavaScript and then the team behind Angular Material decided to add the support from moment.js to our Datepicker module. Now, we can any module import statement to resolve this issue. Now, let’s make it simple and import MatNativeDateModule. With the help of MatMomentDateModule, you’ll be able to choose moment.js dates.

  1. Import Statement  
  2. import {  
  3.     MatNativeDateModule  
  4. } from '@angular/material';  
  5. imports: [  
  6.     BrowserModule,  
  7.     FormsModule,  
  8.     ReactiveFormsModule,  
  9.     BrowserAnimationsModule,  
  10.     MatCheckboxModule,  
  11.     MatRadioModule,  
  12.     MatSelectModule,  
  13.     MatInputModule,  
  14.     MatDatepickerModule,  
  15.     MatNativeDateModule  
  16. ]  

And now it is working,

Angular Material

Let’s add an icon, like the icon of the calendar. So we’ll follow the documentation examples, we’ll add the toggle icon here.

  1. <form>  
  2.     <mat-form-field>  
  3.         <input type="text" matInput [matDatepicker]="birthdate">  
  4.         <mat-datepicker-toggle matSuffix [for]="birthdate"></mat-datepicker-toggle>  
  5.         <mat-datepicker #birthdate></mat-datepicker>  
  6.     </mat-form-field>  
  7. </form>  

And look, it is working.

Angular Material

This calendar popup has 2 modes (month and year) and by default it opens in the month mode and we can see all the days of the current month and we can click to Sep 2018 to switch to year mode where we see the years and all the months inside any year and if you click on current passing year, you’ll also notice the current month is selected. So let’s have an experience your own. We can navigate back and forward with the help of left and right arrow symbols.

Now let’s minimize our browser and simulate the environment for the mobile view.

Angular Material

This is not the good user experience because it is showing us half datepicker control. So let’s see how to solve this problem, back in app.component.html here on the mat-datepicker element we need to set touchUi attribute to true.

  1. <form>  
  2.     <mat-form-field>  
  3.         <input type="text" matInput [matDatepicker]="birthdate">  
  4.         <mat-datepicker-toggle matSuffix [for]="birthdate"></mat-datepicker-toggle>  
  5.         <mat-datepicker #birthdate touchUi="true"></mat-datepicker>  
  6.     </mat-form-field>  
  7. </form>  

Now back in the browser, and now it is the better result.

Angular Material

So make sure to always check the touchUi to true. Now, let’s see a few other functions of this datepicker. By default, we don’t have a date in the datepicker input fields and when we click on the datepicker, it popups with the current day selected. If we manually write the date in the input field and click on the datepicker, our manually written date will be selected in the popup.

Angular Material

Another thing we can do here is to set the range of valid dates, i.e., we may want to limit the user to select the date from Jan 2018 to the Oct 2018. So here in app.comonent.html, we can set the min and max properties to these input elements. So,

  1. export class AppComponent {  
  2.     minDate = new Date(2018, 1, 1);  
  3.     maxDate = new Date(2018, 10, 1);  
  4. }  

Add these fields in AppComponent, intellisense will automatically guide you what is the year, month, and date arguments here.

Now, come to the HTML template.

  1. <form>  
  2.     <mat-form-field>  
  3.         <input [min]="minDate" [max]="maxDate" type="text" matInput [matDatepicker]="birthdate">  
  4.         <mat-datepicker-toggle matSuffix [for]="birthdate"></mat-datepicker-toggle>  
  5.         <mat-datepicker #birthdate touchUi="true"></mat-datepicker>  
  6.     </mat-form-field>  
  7. </form>  

Now, let’s see what happens in the browser.

Angular Material

All the days after 1st of November is disabled but this is currently a bug in the datepicker component. Because we’ve set the maximum date as 1st October, but it is working with next month (November) with the same day. Hopefully, in the next release, it will be fixed. So this is the simple bug in how the datepicker calculates the min and max dates. Another thing that is not implemented in datepicker is displaying an error when the user adds invalid date manually, i.e.

Angular Material

Again this is an issue in Angular. And if you want to head over to the issues on GitHub. Here is the link to be updated.

Sometimes we need to display the calendar automatically. This is very easy to implement. So let’s go back to the documentation of datepicker, here, we can see datepicker has a couple of methods (open and close). So we’re going to call the open method to open calendar when the input field gets focus. So,

  1. <form>  
  2.     <mat-form-field>  
  3.         <input (focus)="birthdate.open()" [min]="minDate" [max]="maxDate" type="text" matInput [matDatepicker]="birthdate">  
  4.         <mat-datepicker-toggle matSuffix [for]="birthdate"></mat-datepicker-toggle>  
  5.         <mat-datepicker #birthdate touchUi="true"></mat-datepicker>  
  6.     </mat-form-field>  
  7. </form>  

And this is what we get in result,

Angular Material

Icons

In Angular Material, just like bootstrap, we have a number of modern beautiful icons. So, if you head over to material.io, we can see all these icons on this page. So let’s see how to use icons in our Angular applications. So first head over to angular material web look here we have step 6 to add material icons. In order to render icons we need to import material icons font from googleapis.com. So,

Step 1

Angular Material

So, just copy the link. And back in VS Code and go to styles.css, and here we need to add an import statement. So,

  1. @import "https://fonts.googleapis.com/icon?family=Material+Icons";  
  2. @import "~@angular/material/prebuilt-themes/indigo-pink.css";  

Step 2

Next, we need to go to the app.module.ts and import the icon module. So,

  1. Import statement  
  2. import {  
  3.     MatIconModule  
  4. } from '@angular/material/icon';  
  5. imports: [  
  6.     BrowserModule,  
  7.     FormsModule,  
  8.     ReactiveFormsModule,  
  9.     BrowserAnimationsModule,  
  10.     MatCheckboxModule,  
  11.     MatRadioModule,  
  12.     MatSelectModule,  
  13.     MatInputModule,  
  14.     MatDatepickerModule,  
  15.     MatNativeDateModule,  
  16.     MatIconModule  
  17. ]  

Step 3

Now come back to app.component.html

  1. <mat-icon></mat-icon>  

And here we add the name of our icon. So let’s select any icon from our material.io and use it in our code. And the label of this icon is alarm. So,

  1. <mat-icon>alarm</mat-icon>  

And it is showing us this result in the browser.

Angular Material

Now if you want to change the color of these icons. There are 2 ways.

  • 1 simple way is to use the CSS
  • 2nd way is to use the custom theme

For now, let’s how to use CSS to change the color of this icon. We’ll explore themes later in this article.

Step 4

So, let’s go to app.component.css, here we can apply the style to our mat-icon.

  1. /* To apply on all the icons: Generic */  
  2. mat - icon {  
  3.     color: red;  
  4. }  
  5. /* To make it specific, here is alarm is class of mat-icon element */  
  6. mat - icon.alarm {  
  7.     color: purple;  
  8. }  

So this is what we get,

Angular Material

So we can see our icon is now red. This is how we add an icon. It is really easier than working with glyphicons defined in bootstrap

Buttons

So, let’s see how to work with buttons. Just like always, let’s start with app.module.ts and here we import.

  1. import {MatButtonModule} from '@angular/material/button';  

Now, let’s go to app.component.html and here we’ll add a plain html5 button

  1. <button>Click Me!</button>  

So, this is what we get in the browser.

Angular Material

Which is really boring and ugly. Now let’s give this modern look and feel. In Angular Material, we have a number of directives that we can apply to our buttons to give them the material design look and feel. And here you’ll see all the button variants. Let’s see few of them,

  1. <button mat-button>Click Me!</button>  

Result

Angular Material

And if you hover this ‘Click Me!’ it will look like a button on hover. But by default, it doesn’t look like a button and I personally recommend you not to use this directive. Now let’s take a look at another directive.

  1. <button mat-raised-button>Raised</button>  

And here is the result,

Angular Material

This is much better. By default, the background color of this button is based on the background color of the theme. And the theme we have applied here has the background color white that’s why the background color of this button is also white but we can change this. We can simply apply the color attribute.

  1. <button color="" mat-raised-button>Raised</button>  

And here we have 3 options (primary, Accent, warn). If you have worked with bootstrap, you have seen the same concept there. In bootstrap, we have primary secondary danger and so on. So let’s use a primary color of the button.

  1. <button color="primary" mat-raised-button>Raised</button>  

And we get the result,

Angular Material

Now let’s copy paste a couple of times and check the colors.

  1. <button mat-button>Click Me!</button>  
  2. <button color="primary" mat-raised-button>Primary</button>  
  3. <button color="accent" mat-raised-button>Accent</button>  
  4. <button color="warn" mat-raised-button>Warn</button>  

And our result will be.

Angular Material

So, these are 3 beautiful buttons based on the current theme. Now, what if we don’t like these colors? What if instead of this blue-purple or primary button, we want to look the primary button as green. There are 2 ways to achieve this. One way is to use CSS which is not recommended. Because you want your entire application to have a common and consistent look and feel. If you have green use in your button, chances are that green should be used somewhere else as well. That’s why in Angular Material we have this concept called Theme where we define all the colors in our application. And that’s something we’re going to look later on. So, for now, don’t worry about to change the color of these buttons.

Now, let’s take a look some more types of button.

  1. <br />  
  2. <button mat-fab>  
  3.     <mat-icon>check</mat-icon>  
  4. </button>  

Here, fab stands for floatable action button. These are round buttons that have an icon inside so we don’t add the label here but instead we add an icon. Let’s see its results.

And if you’re watching this check button or the color might be purple or red. Then you should move to app.component.css and remove the styles which we have applies to mat-icon.

Angular Material

We can also change the color of this fab button.

  1. <button mat-fab color="primary">  
  2.     <mat-icon>check</mat-icon>  
  3. </button>  

And now the color is changed in the browser.

Angular Material

Chips

We have another useful component in Angular Material called Chips. We use chips for some kind of tags below an object or product and we can use them to implement some kind of filter.

Angular Material

For example, we wanna display the list of courses and we have 3 categories beginner, intermediate and advanced. The user can click each category to see the courses in that category. So let’s see how to implement something like that,

Step 1

Add the module in imports array and add the reference with an import statement.

  1. import {MatChipsModule} from '@angular/material/chips';  

Step 2

Now let’s go to app.component.html and I’ve already shared the example picture to generate the chips.

But let’s make a dynamic example of course levels. So, first of all, define the course categories in app.component.ts

  1. export class AppComponent {  
  2.     categories = [{  
  3.         name: 'Beginner'  
  4.     }, {  
  5.         name: 'Intermediate'  
  6.     }, {  
  7.         name: 'Advanced'  
  8.     }];  
  9. }  

Now define the chips in app.component.html and make it dynamic.

  1. <mat-chip-list>  
  2.     <mat-chip *ngFor="let category of categories" (click)="category.selected = !category.selected" [selected]="category.selected">{{ category.name }}</mat-chip>  
  3. </mat-chip-list>  

This code is very easy to understand. On category click event we’re just changing the state if this specific category is selected then it will become unselected and if it is not selected then it will be selected. And selected property binding is for maintaining the state of the item.

Angular Material

So I click on the Beginner, it becomes selected and if I click again it will become unselected. But now, we can select more than one categories. And we want to make them selectable only one item. So instead of using an expression now, we use the component function in the click event.

  1. <mat-chip-list>  
  2.     <mat-chip *ngFor="let category of categories" (click)="selectCategory(category)" [selected]="category.selected">{{ category.name }}</mat-chip>  
  3. </mat-chip-list>  

And now let’s define the method.

  1. export class AppComponent {  
  2.     categories = [{  
  3.         name: 'Beginner'  
  4.     }, {  
  5.         name: 'Intermediate'  
  6.     }, {  
  7.         name: 'Advanced'  
  8.     }];  
  9.     selectCategory(category) {  
  10.         // filter: Here we're fining the other categories which I don't select and  
  11.         // forEach: then iterate them and make them not selected.  
  12.         this.categories.filter(c => c !== category).forEach(c => c['selected'] = false);  
  13.         category.selected = !category.selected;  
  14.     }  
  15. }  

And now, only 1 item is selectable. And everything works beautifully.

Progress Spinners

Another useful component that you have seen in a lot of real-world applications is progress spinner.

Step 1

Import the statement in app.module.ts

  1. import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';  

And import the module in the import array.

Step 2

Now back in app.component.html

  1. <mat-progress-spinner></mat-progress-spinner>  

This element has 2 modes (determinate and indeterminate). We use determinate when we know how long this process is going to take i.e. if we’re implementing file upload we can keep track of the upload progress. So we can display the progress bar from zero to hundred percent. And here we’ll use,

  1. <mat-progress-spinner mode="determinate" value="20">  
  2. </mat-progress-spinner>  

So in this mode, we should also set value property 20. And here we get the result.

Angular Material

Now, let’s make it dynamic. And here we’ll simulate the scenario where we can keep track of the progress of an action. So let’s go to app.component.ts

  1. export class AppComponent {  
  2.     progress = 0;  
  3.     timer;  
  4.     constructor() {  
  5.         this.timer = setInterval(() => {  
  6.             this.progress++;  
  7.             if (this.progress === 100) {  
  8.                 clearInterval(this.timer);  
  9.             }  
  10.         }, 20);  
  11.     }  
  12. }  

Here, we’re using a constructor and in this constructor, we’re using native setInterval JavaScript function. The first argument of this function is a callback and in this function, we’re incrementing the value of a field in this class. And when this progress is 100, we are going to stop the timer by using clearInterval() and as the argument to clearInterval(), we pass the timer object. And as the 2nd argument to setInterval() we’re passing 20ms delay. So with the help of this code, every 20ms progress is going to increment until it reaches 100.

Step 3

Now, back in app.component.html. Instead of hard coding 20 here, I’m gonna bind the value property to the progress field in our component.

  1. <mat-progress-spinner mode="determinate" [value]="progress">  
  2. </mat-progress-spinner>  

Now, if you see this in action, you’ll see the beautiful progress bar in action in the browser.

Step 4

Now, this progress spinner also has another mode which is indeterminate. And that is when we don’t know the progress of an action. For example, when we call the API on the server, we don’t know how long it is going to take and get the response. So we wanna display this spinner until we get the response. In this mode, we don’t any need to set the value property.

  1. <mat-progress-spinner mode="indeterminate">  
  2. </mat-progress-spinner>  

And we’ll see continuously rounding spinner on loading the browser page.

Step 5

Now let’s simulate the call to the backend and let’s see how to display the spinner while waiting to the server for the response. So back in app.component.ts

So in order to call the server, we use our data service. So that data service is going to be a dependency to this constructor and in the ngOnInit() we call the data service to get the data.

  1. export class AppComponent {  
  2.     constructor() {}  
  3. }  

But in this demo, I don’t want to waste time to create the service using dependency injection and dealing with all kinds of details that don’t matter for this demo. So I wanna simulate a call to the server. So,

  1. Import Statement in Angular 6 Project: import {  
  2.     Component  
  3. } from '@angular/core';  
  4. import {  
  5.     Observable,  
  6.     timer  
  7. } from 'rxjs';  
  8. export class AppComponent {  
  9.     course;  
  10.     constructor() {  
  11.         // to get all the courses  
  12.         this.getCourses().subscribe(course => this.course = course);  
  13.     }  
  14.     getCourses() {  
  15.         return timer(2000);  
  16.     }  
  17. }  

Technically, getCourses() should not be here in the component to be a part of the services, like data service but we don’t want to waste the time of that service. And we know our data service returns Observable. So here, in our getCourses(), timer() is returning observable and then we have subscribed it in the constructor. timer() is a factory method which returns observable after every 2 seconds, it simulates the call to the server that is going to take 2s.

So here, in our constructor, when we call getCourses(), we’re gonna wait 2 seconds and then we’ll get the result but in our case, there will be no result because we’ve not any list of courses and it doesn’t really matter. So, let’s simplify.

  1. export class AppComponent {  
  2.     isLoading = false;  
  3.     constructor() {  
  4.         this.isLoading = true;  
  5.         this.getCourses().subscribe(x => this.isLoading = false);  
  6.     }  
  7.     getCourses() {  
  8.         return timer(2000);  
  9.     }  
  10. }  

Of course, in a more real-world scenario, here we also want to set the courses field in our component.

Step 6

Now, back in our app.component.html template, we want to display this spinner only when progress spinner is true.

  1. <mat-progress-spinner   
  2.   *ngIf="isLoading"  
  3.   mode="indeterminate">  
  4. </mat-progress-spinner>  

Now, see the result in the browser. We’ll see the progress spinner which will disappear after 2 seconds.


Similar Articles