banner



Is Angular Material Included In New Angular App

TL;DR: In this article, you will learn how to use Angular Material to create beautiful and modern Angular applications. You will start from scratch, installing Node.js and Angular CLI (if you don't have them yet), you will install and configure the dependencies needed to develop with Angular Material. You can find the final code developed throughout this article in this GitHub repository.

So, What Exactly is Angular Material?

Angular Material is a User Interface (UI) component library that developers can use in their Angular projects to speed up the development of elegant and consistent user interfaces. Angular Material offers you reusable and beautiful UI components like Cards, Inputs, Data Tables, Datepickers, and much more.

Each component is ready to go with default styling that follows the Material Design Specification. Nonetheless, you can easily customize the look and feel of Angular Material components. The list of available Angular Material components continues to grow with each iteration of the library.

Angular Material Tutorial

This article aims to teach you how to use Angular Material through a hands-on exercise. First, you will check the dependencies you need on your computer to develop with Angular Material. Then you will learn how to configure and use different components.

Setup the Environment for Angular

To work with Angular, you will need Node.js and Angular CLI (Command Line Interface) installed in your development environment. Node.js will provide the packages needed by the CLI to work and the development server so you can check your progress in real-time.

Angular CLI is the tool that helps you create a new Angular project and configure Angular components, services, and so on. You will need it because an Angular project is more than just HTML and script files. That is, An angular project uses TypeScript, which needs to be transpiled and optimized to run browsers. Without Angular CLI, you would need to set up and wire a lot of tools to work together, which would consume too much time.

If you don't have Node.js installed in your computer, proceed to the download page and follow the instructions there (or use a tool like N, a Node.js version manager to have multiple versions installed with ease). After installing Node.js, use NPM (which comes along with Node.js) to install Angular CLI:

                      npm            install            -g @angular/cli        

Note: Depending on your computer's setup, you might need to use sudo to use the -g (global) flag.

Create an Angular Project

Having both Node.js and Angular CLI correctly installed on your computer, you can use the following command to set up a new Angular project:

                      # create a new Angular project under angular-material-tutorial            ng new angular-material-tutorial            # move into the new project            cd            angular-material-tutorial        

The first command will generate a directory/file (under a new directory called angular-material-tutorial) structure with many files that are needed so you can create your Angular applications. To learn the details of this structure, please, check the Angular CLI documentation. The second command will move your terminal into the project root directory.

Install Angular Material

To install Angular Material as a dependency of your project, run the following command:

                      npm            install            @angular/material @angular/cdk        

For now, you won't make any changes to your project's source code. First, you will install a few more cool dependencies.

Angular Material Theme

After installing Angular Material, you will configure a theme that defines what colors will be used in your Angular Material components. To configure the basic theme, open the src/styles.css file, and paste the following code:

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

By the way, if you don't know what IDE (Integrated Development Environment) to use while developing with Angular, Visual Studio Code is a great (and free) alternative.

Angular Material Gesture

Some components like Slide Toggle, Slider, and Tooltip rely on a library called HammerJS to capture touch gestures. So, you will need to install HammerJS and load it into our application.

To do so, from the project root directory, run:

                      # from angular-material-tutorial            npm            install            hammerjs        

After installing it, add the following line at the top of the src/main.ts file:

                      import            'hammerjs'            ;                  

Material Icons

Another cool thing to add to your project is the Material Icons library. To have access to this huge library of icons, update the src/index.html file as follows:

                                    <!              doctype              html              >                                                      <html              lang                              =                "en"                            >                                                      <head              >                        <!-- ... other tags ... -->                                          <link              href                              =                "https://fonts.googleapis.com/icon?family=Material+Icons"                            rel                              =                "stylesheet"                            >                                                      </head              >                        <!-- ... body and app root ... -->                                          </html              >                              

What Will You Build with Angular Material

After setting up the Angular project structure and some dependencies, you will start developing apps. In this article, to learn Angular Material through practical exercises, you will develop a dashboard for a blog engine where users can insert new posts and delete existing ones. This won't be a full-fledged application with a backend persistence nor enhanced features. The idea here is to show how cool and easy it is to use Angular Material.

"I'm learning Angular Material through practical exercises!"

Tweet

Tweet This

Importing Material Components

The first thing you will do is to create a new file called material.module.ts in the . /src/app directory. Inside this file, you will add the following code:

                      import            {NgModule}            from            '@angular/core'            ;            @NgModule            (            {            imports:            [            ]            ,            exports:            [            ]            }            )            export            class            MaterialModule            {            }                  

The idea of creating a new Angular module (@NgModule) is to centralize what you will import from Angular Material in a single file. Before adding Angular Material components in this file, you will need to import and configure it in your main module (i.e., in the . /src/app/app.module.ts file) as follows:

                      // ... other import statements ...            import            {BrowserAnimationsModule}            from            '@angular/platform-browser/animations'            ;            import            {MaterialModule}            from            './material.module'            ;            @NgModule            (            {            // ... declarations property ...            imports:            [            BrowserModule,            BrowserAnimationsModule,            MaterialModule,            ]            ,            // ... providers and bootstrap properties ...            }            )            export            class            AppModule            {            }                  

Note: You are also adding BrowserAnimationsModule so your app can count on some cool animation features (like the shadow on the click of the buttons).

Angular Material Sidenav

After defining a centralized place to import Angular Material components, you can focus on adding a navigation bar to your app. For this, you will update the . /src/app/material.module.ts to look like this:

                      import            {NgModule}            from            '@angular/core'            ;            import            {            MatSidenavModule,            MatToolbarModule,            MatIconModule,            MatListModule,            }            from            '@angular/material'            ;            @NgModule            (            {            imports:            [            MatSidenavModule,            MatToolbarModule,            MatIconModule,            MatListModule,            ]            ,            exports:            [            MatSidenavModule,            MatToolbarModule,            MatIconModule,            MatListModule,            ]            }            )            export            class            MaterialModule            {            }                  

This change will make MatSidenavModule available in your application. So, now, you can update the app template ( . /src/app/app.component.html) to use this component:

                                                    <mat-sidenav-container              >                                                      <mat-sidenav              #sidenav              role                              =                "navigation"                            >                                                      <mat-nav-list              >                                                      <a              mat-list-item              >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Login                              </span              >                                                      </a              >                                                      <a              mat-list-item              >                                                      <mat-icon              class                              =                "icon"                            >            home                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Home                              </span              >                                                      </a              >                                                      <a              mat-list-item              >                                                      <mat-icon              class                              =                "icon"                            >            dashboard                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Dashboard                              </span              >                                                      </a              >                                                      <a              mat-list-item              type                              =                "button"                            >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            LogOut                              </span              >                                                      </a              >                                                      </mat-nav-list              >                                                      </mat-sidenav              >                                                      <mat-sidenav-content              >                                                      <mat-toolbar              color                              =                "primary"                            >                                                      <div              fxHide.gt-xs              >                                                      <button              mat-icon-button              >                                                      <mat-icon              >            menu                              </mat-icon              >                                                      </button              >                                                      </div              >                                                      <div              >                                                      <a              >                        Material Blog                                          </a              >                                                      </div              >                                                      <div              fxFlex              fxLayout              fxLayoutAlign                              =                "flex-end"                            fxHide.xs              >                                                      <ul              fxLayout              fxLayoutGap                              =                "20px"                            class                              =                "navigation-items"                            >                                                      <li              >                                                      <a              >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Login                              </span              >                                                      </a              >                                                      </li              >                                                      <li              >                                                      <a              >                                                      <mat-icon              class                              =                "icon"                            >            home                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Home                              </span              >                                                      </a              >                                                      </li              >                                                      <li              >                                                      <a              >                                                      <mat-icon              class                              =                "icon"                            >            dashboard                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Dashboard                              </span              >                                                      </a              >                                                      </li              >                                                      <li              >                                                      <a              >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            LogOut                              </span              >                                                      </a              >                                                      </li              >                                                      </ul              >                                                      </div              >                                                      </mat-toolbar              >                                                      <main              >                                                      </main              >                                                      </mat-sidenav-content              >                                                      </mat-sidenav-container              >                              

For now, you won't have anything nice to see in a browser yet, but you will get there soon.

Angular Material and Flexbox

To make your life easier when defining your Angular application's layout, you will take advantage of the Flex layout schema introduced recently on CSS. More specifically, you will use an Angular directive called fxFlex to handle the Flex layout.

To use it, install the Flex layout package with the following command:

                      npm            install            @angular/flex-layout@v5.0.0-beta.14 rxjs-compat        

Note: You are explicitly installing v5. 0.0 -beta. 14 of the @angular/flex-layout library because the newer version available is not working properly with Angular 6.

Note that after the major upgrade to Angular 6, you will need to install rxjs-compat alongside @angular/flex-layout. The command above already includes this library. So, it is just a matter of copying and pasting the command in your terminal (while being in the project root, of course).

Then, import and configure it into src/app.module.ts as shown here:

                      // ... other import statements ...            import            {FlexLayoutModule}            from            '@angular/flex-layout'            ;            @NgModule            (            {            // ... declarations property ...            imports:            [            // ... other modules ...            FlexLayoutModule,            ]            ,            // ... providers and bootstrap properties ...            }            )            export            class            AppModule            {            }                  

If you take a close look, you will see that you are already using this package's features in the navigation bar defined before. For example, you have added directives like fxLayout, fxLayoutAlign, and other fxFlex directives.

Before running your app for the first time, add the following CSS rules to app.component.css, so your navigation looks better:

                      mat-sidenav-container, mat-sidenav-content, mat-sidenav            {            height            :            100%;            }            mat-sidenav            {            width            :            250px;            }            a            {            text-decoration            :            none;            color            :            white;            }            a:hover, a:active            {            color            :            lightgray;            }            .navigation-items            {            list-style            :            none;            padding            :            0;            margin            :            0;            cursor            :            pointer;            }            .icon            {            display            :            inline-block;            height            :            30px;            margin            :            0 auto;            padding-right            :            5px;            text-align            :            center;            vertical-align            :            middle;            width            :            15%;            }            .label            {            display            :            inline-block;            line-height            :            30px;            margin            :            0;            width            :            85%;            }                  

Also, add the following rule to . /src/styles.css so you don't have any white margins on your app:

                                    @import              "~@angular/material/prebuilt-themes/indigo-pink.css"              ;                        body            {            margin            :            0;            }                  

With these rules in place, you can issue ng serve from your project root to check your application for the first time.

Navigation bar with Angular Material

More Angular Material Components

Now that you have your application up and running with your first Angular Material component, it's time to add more features. So, the first thing you will do is to define two new components (views) to your application, the WelcomeComponent and the DashboardComponent. To create these two new components, you can use the Angular CLI tool as follows:

          ng g c welcome --module app.module ng g c dashboard --module app.module        

It's important to define --module app.module because you have another module called material.module, making Angular CLI unable to identify the targeted module automatically.

After running these two commands, open the welcome.component.html and replace the code with this:

                                                    <div                              style                                  =                  "                                      text-align                    :center                  "                                            >                                                      <h1              >            Angular Content Management System                              </h1              >                                                      <p              >                        This is a platform for technical writers to manage their blog post contents related to angular.                                          <br              >                        Click on Login to get Started!!!                                          </p              >                                                      </div              >                              

Don't worry about the DashboardComponent for now. You will work on it soon.

Creating Routes

Now that you have multiple components, you will need to define some routes so your users can access them. To do so, you can create a file called app.routes.ts in the . /src/app directory and add the following code to it:

                      import            {NgModule}            from            '@angular/core'            ;            import            {RouterModule,            Routes}            from            '@angular/router'            ;            import            {WelcomeComponent}            from            './welcome/welcome.component'            ;            import            {DashboardComponent}            from            './dashboard/dashboard.component'            ;            const            routes:            Routes            =            [            {path:            ''            ,            component:            WelcomeComponent}            ,            {path:            'dashboard'            ,            component:            DashboardComponent}            ]            ;            @NgModule            (            {            imports:            [RouterModule.            forRoot            (routes)            ]            ,            exports:            [RouterModule]            }            )            export            class            AppRouters            {            }                  

In this file, you define two routes: one for the WelcomeComponent and one for the DashboardComponent. As such, when you head to http: / /localhost: 4200 , you will see the WelcomeComponent and when you head to http: / /localhost: 4200 /dashboard, you will see the DashboardComponent.

Besides defining this module, you will need to update the app.component.html file to add links to these new routes:

                                                    <mat-sidenav-container              >                                                      <mat-sidenav              #sidenav              role                              =                "navigation"                            >                                                      <mat-nav-list              >                                                      <a              mat-list-item              >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Login                              </span              >                                                      </a              >                                                      <a              mat-list-item              routerLink                              =                "/"                            >                                                      <mat-icon              class                              =                "icon"                            >            home                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Home                              </span              >                                                      </a              >                                                      <a              mat-list-item              routerLink                              =                "/dashboard"                            >                                                      <mat-icon              class                              =                "icon"                            >            dashboard                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Dashboard                              </span              >                                                      </a              >                                                      <a              mat-list-item              type                              =                "button"                            >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            LogOut                              </span              >                                                      </a              >                                                      </mat-nav-list              >                                                      </mat-sidenav              >                                                      <mat-sidenav-content              >                                                      <mat-toolbar              color                              =                "primary"                            >                                                      <div              fxHide.gt-xs              >                                                      <button              mat-icon-button              (click)                              =                "sidenav.toggle()"                            >                                                      <mat-icon              >            menu                              </mat-icon              >                                                      </button              >                                                      </div              >                                                      <div              >                                                      <a              routerLink                              =                "/"                            >                        Material Blog                                          </a              >                                                      </div              >                                                      <div              fxFlex              fxLayout              fxLayoutAlign                              =                "flex-end"                            fxHide.xs              >                                                      <ul              fxLayout              fxLayoutGap                              =                "20px"                            class                              =                "navigation-items"                            >                                                      <li              >                                                      <a              >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Login                              </span              >                                                      </a              >                                                      </li              >                                                      <li              >                                                      <a              routerLink                              =                "/"                            >                                                      <mat-icon              class                              =                "icon"                            >            home                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Home                              </span              >                                                      </a              >                                                      </li              >                                                      <li              >                                                      <a              routerLink                              =                "/dashboard"                            >                                                      <mat-icon              class                              =                "icon"                            >            dashboard                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Dashboard                              </span              >                                                      </a              >                                                      </li              >                                                      <li              >                                                      <a              >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            LogOut                              </span              >                                                      </a              >                                                      </li              >                                                      </ul              >                                                      </div              >                                                      </mat-toolbar              >                                                      <main              >                                                      <router-outlet              >                                                      </router-outlet              >                                                      </main              >                                                      </mat-sidenav-content              >                                                      </mat-sidenav-container              >                              

Lastly, you will need to update the app.module.ts file to use the new module:

                      // ... other import statements ...            import            {AppRouters}            from            './app.routes'            ;            @NgModule            (            {            // ... declarations property ...            imports:            [            // ... other imports ...            AppRouters,            ]            ,            // ... providers and bootstrap properties ...            }            )            export            class            AppModule            {            }                  

If you check your application now (through ng serve), you will see the contents defined in the HTML file of WelcomeComponent. If you click on the Dashboard link, you will see that it loads the "dashboard works!" message.

Managing Data - Part 1

As your dashboard component has nothing more than a simple message, it's time to focus on enhancing it. The idea of this dashboard is to let users add and remove blog posts. The first thing you will do is define an interface to represent instances of blog posts.

To do so, create a new file called Post.ts inside the . /src/app directory and add the following code to it:

                      export            interface            Post            {            title:            string            ;            category:            string            ;            date_posted:            Date;            position:            number            ;            body:            string            ;            }                  

Now, you can use this interface to build a data service to simulate a real application. To create this service, you can run the following command:

          ng g s data/data --module app.module        

Once finished, you can open the data.service.ts file created and replace its code with:

                      import            {Injectable}            from            '@angular/core'            ;            import            {Post}            from            '../Post'            ;            import            {Observable,            of            }            from            'rxjs'            ;            @Injectable            (            )            export            class            DataService            {            ELEMENT_DATA            :            Post[            ]            =            [            {position:            0            ,            title:            'Post One'            ,            category:            'Web Development'            ,            date_posted:            new            Date            (            )            ,            body:            'Body 1'            }            ,            {position:            1            ,            title:            'Post Two'            ,            category:            'Android Development'            ,            date_posted:            new            Date            (            )            ,            body:            'Body 2'            }            ,            {position:            2            ,            title:            'Post Three'            ,            category:            'IOS Development'            ,            date_posted:            new            Date            (            )            ,            body:            'Body 3'            }            ,            {position:            3            ,            title:            'Post Four'            ,            category:            'Android Development'            ,            date_posted:            new            Date            (            )            ,            body:            'Body 4'            }            ,            {position:            4            ,            title:            'Post Five'            ,            category:            'IOS Development'            ,            date_posted:            new            Date            (            )            ,            body:            'Body 5'            }            ,            {position:            5            ,            title:            'Post Six'            ,            category:            'Web Development'            ,            date_posted:            new            Date            (            )            ,            body:            'Body 6'            }            ,            ]            ;            categories            =            [            {value:            'Web-Development'            ,            viewValue:            'Web Development'            }            ,            {value:            'Android-Development'            ,            viewValue:            'Android Development'            }            ,            {value:            'IOS-Development'            ,            viewValue:            'IOS Development'            }            ]            ;            constructor            (            )            {            }            getData            (            )            :            Observable<Post[            ]            >            {            return            of            <Post[            ]            >            (            this            .            ELEMENT_DATA            )            ;            }            getCategories            (            )            {            return            this            .categories;            }            addPost            (data)            {            this            .            ELEMENT_DATA            .            push            (data)            ;            }            deletePost            (index)            {            this            .            ELEMENT_DATA            =            [            ...            this            .            ELEMENT_DATA            .            slice            (            0            ,            index)            ,            ...            this            .            ELEMENT_DATA            .            slice            (index            +            1            )            ]            ;            }            dataLength            (            )            {            return            this            .            ELEMENT_DATA            .length;            }            }                  

In your data service, you have two different arrays: one for storing categories of posts and the other one for storing blog posts.

You will also have to guarantee that the app.module.ts file includes your new DataService class in its providers property:

                      // ... other imports ...            import            {DataService}            from            './data/data.service'            ;            @NgModule            (            {            // ... declarations and imports ...            providers:            [DataService]            ,            // ... bootstrap ...            }            )            export            class            AppModule            {            }                  

Now, you can update your dashboard to make use of the data service to render some data. So, open the dashboard.component.ts file and replace its code with this:

                      import            {Component}            from            '@angular/core'            ;            import            {DataService}            from            '../data/data.service'            ;            import            {Post}            from            '../Post'            ;            import            {DataSource}            from            '@angular/cdk/table'            ;            import            {Observable}            from            'rxjs/Observable'            ;            @Component            (            {            selector:            'app-dashboard'            ,            templateUrl:            './dashboard.component.html'            ,            styleUrls:            [            './dashboard.component.css'            ]            }            )            export            class            DashboardComponent            {            constructor            (            private            dataService:            DataService)            {            }            displayedColumns            =            [            'date_posted'            ,            'title'            ,            'category'            ,            'delete'            ]            ;            dataSource            =            new            PostDataSource            (            this            .dataService)            ;            }            export            class            PostDataSource            extends            DataSource<              any              >                        {            constructor            (            private            dataService:            DataService)            {            super            (            )            ;            }            connect            (            )            :            Observable<Post[            ]            >            {            return            this            .dataService.            getData            (            )            ;            }            disconnect            (            )            {            }            }                  

Then, open the dashboard.component.html file and replace everything with:

                                                    <div              >                                                      <br              >                                                      <div              class                              =                "container"                            >                                                      <div              class                              =                "container"                            >                                                      <div              fxLayout                              =                "column"                            fxLayoutGap                              =                "20px"                            fxLayout.gt-md                              =                "row"                            fxLayoutAlign                              =                "space-around center"                            class                              =                "content"                            >                                                      <div              class                              =                "blocks"                            >                                                      <button              button                              =                "submit"                            mat-raised-button              color                              =                "primary"                            >                                                      <mat-icon              >            add                              </mat-icon              >                        Add Post                                          </button              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      <br              >                                                      <div              class                              =                "container"                            >                                                      <div              fxLayout                              =                "row"                            fxLayoutAlign                              =                "center center"                            class                              =                "content"                            >                                                      <mat-card              class                              =                "card"                            >                                                      <mat-card-title              fxLayout.gt-xs                              =                "row"                            fxLayout.xs                              =                "column"                            >                                                      <h3              >            Recent Posts                              </h3              >                                                      </mat-card-title              >                                                      <mat-card-content              >                                                      <div              class                              =                "example-container mat-elevation-z8"                            >                                                      <mat-table              #table              [dataSource]                              =                "dataSource"                            >                                                      <ng-container              matColumnDef                              =                "date_posted"                            >                                                      <mat-header-cell              *matHeaderCellDef              >                        Date Posted                                          </mat-header-cell              >                                                      <mat-cell              *matCellDef                              =                "let element"                            >                        {{element.date_posted  | date: 'd/M/y'}}                                          </mat-cell              >                                                      </ng-container              >                                                      <ng-container              matColumnDef                              =                "title"                            >                                                      <mat-header-cell              *matHeaderCellDef              >                        Title                                          </mat-header-cell              >                                                      <mat-cell              *matCellDef                              =                "let element"                            >                        {{element.title}}                                          </mat-cell              >                                                      </ng-container              >                                                      <ng-container              matColumnDef                              =                "category"                            >                                                      <mat-header-cell              *matHeaderCellDef              >                        Category                                          </mat-header-cell              >                                                      <mat-cell              *matCellDef                              =                "let element"                            >                        {{element.category}}                                          </mat-cell              >                                                      </ng-container              >                                                      <ng-container              matColumnDef                              =                "delete"                            >                                                      <mat-header-cell              *matHeaderCellDef              >                                                      </mat-header-cell              >                                                      <mat-cell              *matCellDef                              =                "let element"                            >                                                      <a              type                              =                "button"                            >                                                      <mat-icon              class                              =                "icon"                            >            delete                              </mat-icon              >                                                      </a              >                                                      </mat-cell              >                                                      </ng-container              >                                                      <mat-header-row              *matHeaderRowDef                              =                "displayedColumns"                            >                                                      </mat-header-row              >                                                      <mat-row              *matRowDef                              =                "let row; columns: displayedColumns;"                            >                                                      </mat-row              >                                                      </mat-table              >                                                      </div              >                                                      </mat-card-content              >                                                      </mat-card              >                                                      </div              >                                                      </div              >                                                      </div              >                                                      </div              >                              

Here, you are using some Angular Material Components like mat-card, mat-button, and mat-table to render the list of existing blog posts. Before proceeding, you will have to import these components into the material.module.ts file. So, open it and update as follows:

                      import            {NgModule}            from            '@angular/core'            ;            import            {            // ... other modules ...            MatCardModule,            MatButtonModule,            MatTableModule,            }            from            '@angular/material'            ;            @NgModule            (            {            imports:            [            // ... other modules ...            MatCardModule,            MatButtonModule,            MatTableModule,            ]            ,            exports:            [            // ... other modules ...            MatCardModule,            MatButtonModule,            MatTableModule,            ]            }            )            export            class            MaterialModule            {            }                  

Before checking your application running with these new components, open the dashboard.component.css file and add the following content:

                      .card            {            min-width            :            80%;            }            .example-container            {            display            :            flex;            flex-direction            :            column;            max-height            :            500px;            min-width            :            100%;            }            .mat-table            {            overflow            :            auto;            max-height            :            500px;            }            a            {            cursor            :            pointer;            }                  

Now, running your app (ng serve) and heading to http: / /localhost: 4200 /dashboard, you will see the following screen:

Angular Material dashboard

Securing Angular Material with Auth0

As you don't want unauthenticated users to create blog posts or remove existing ones, you will take advantage of Auth0 to easily secure your app.

So, before integrating Auth0 into your app, you will need to sign up for a free Auth0 account. After following the instructions there to create your account, you will need to create an Auth0 Application to represent your Angular app.

To do so, click on the New Application button on your dashboard page. Then, fill the form shown as follows:

  • Application Name: Angular Material Tutorial
  • Application Type: Single Page Web Apps

Once finished, Auth0 will show you a screen where you can see tabs like Quick Start, Settings, and Addons. Choose the Settings tab and add http: / / localhost:4200 / as an Allowed Callback URL. This is the URL that Auth0 is allowed to call after finishing the authentication process (this configuration exists to make the process more secure).

Now, create a new file called auth.service.ts in the . /src/app directory and add the following code to it:

                      import            {Injectable}            from            '@angular/core'            ;            import            {Router}            from            '@angular/router'            ;            import            *            as            auth0            from            'auth0-js'            ;            // why do you need defining window as any?            // check this: https://github.com/aws/aws-amplify/issues/678#issuecomment-389106098            (window            as            any            )            .global            =            window;            @Injectable            (            )            export            class            AuthService            {            auth0            =            new            auth0            .            WebAuth            (            {            clientID:            '<APPLICATION_CLIENT_ID>'            ,            domain:            '<YOUR_AUTH0_DOMAIN>'            ,            responseType:            'token'            ,            redirectUri:            'http://localhost:4200/'            ,            scope:            'openid'            }            )            ;            accessToken:            String;            expiresAt:            Number;            constructor            (            public            router:            Router)            {            }            public            login            (            )            :            void            {            this            .auth0.            authorize            (            )            ;            }            public            handleAuthentication            (            )            :            void            {            this            .auth0.            parseHash            (            (err,            authResult)            =>            {            if            (authResult            &&            authResult.accessToken)            {            window.location.hash            =            ''            ;            this            .accessToken            =            authResult.accessToken;            this            .expiresAt            =            (authResult.expiresIn            *            1000            )            +            new            Date            (            )            .            getTime            (            )            ;            this            .router.            navigate            (            [            '/dashboard'            ]            )            ;            }            else            if            (err)            {            this            .router.            navigate            (            [            '/'            ]            )            ;            console            .            log            (err)            ;            }            }            )            ;            }            public            logout            (            )            :            void            {            // Remove tokens and expiry time from localStorage            this            .accessToken            =            null            ;            this            .expiresAt            =            null            ;            // Go back to the home route            this            .router.            navigate            (            [            '/'            ]            )            ;            }            public            isAuthenticated            (            )            :            boolean            {            // Check whether the current time is past the            // Access Token's expiry time            return            new            Date            (            )            .            getTime            (            )            <            this            .expiresAt;            }            }                  

The code in this service, although lengthy, is quite simple. You are just defining an instance of auth0.WebAuth to interact with Auth0, and then you define a method called handleAuthentication that will fetch the tokens returned by Auth0. Also, there are other handy methods in this service like isAuthenticated, login, and logout. You will use all of them soon.

Important! You will need to replace < APPLICATION_CLIENT_ID > and < YOUR_AUTH0_DOMAIN > in the code with your Auth0 application's values. For example, the client id will look like lU4PgkBaogkZP13Mv1gSkHK6VIH6xIkq, and the domain will look like bk-tmp.auth0.com.

Also, before proceeding, you will have to install the auth0-js library and its types definition (@types/auth0-js):

                      npm            install            auth0-js            npm            i -D @types/auth0-js        

Now, you can update the app.component.html to integrate it with your new service:

                                                    <mat-sidenav-container              >                                                      <mat-sidenav              #sidenav              role                              =                "navigation"                            >                                                      <mat-nav-list              >                                                      <a              mat-list-item              *ngIf                              =                "!auth.isAuthenticated()"                            (click)                              =                "auth.login()"                            >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Login                              </span              >                                                      </a              >                                                      <a              mat-list-item              *ngIf                              =                "auth.isAuthenticated()"                            routerLink                              =                "/"                            >                                                      <mat-icon              class                              =                "icon"                            >            home                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Home                              </span              >                                                      </a              >                                                      <a              mat-list-item              routerLink                              =                "/dashboard"                            >                                                      <mat-icon              class                              =                "icon"                            >            dashboard                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Dashboard                              </span              >                                                      </a              >                                                      <a              mat-list-item              *ngIf                              =                "auth.isAuthenticated()"                            (click)                              =                "auth.logout()"                            type                              =                "button"                            >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            LogOut                              </span              >                                                      </a              >                                                      </mat-nav-list              >                                                      </mat-sidenav              >                                                      <mat-sidenav-content              >                                                      <mat-toolbar              color                              =                "primary"                            >                                                      <div              fxHide.gt-xs              >                                                      <button              mat-icon-button              (click)                              =                "sidenav.toggle()"                            >                                                      <mat-icon              >            menu                              </mat-icon              >                                                      </button              >                                                      </div              >                                                      <div              >                                                      <a              routerLink                              =                "/"                            >                        Material Blog                                          </a              >                                                      </div              >                                                      <div              fxFlex              fxLayout              fxLayoutAlign                              =                "flex-end"                            fxHide.xs              >                                                      <ul              fxLayout              fxLayoutGap                              =                "20px"                            class                              =                "navigation-items"                            >                                                      <li              >                                                      <a              *ngIf                              =                "!auth.isAuthenticated()"                            (click)                              =                "auth.login()"                            >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Login                              </span              >                                                      </a              >                                                      </li              >                                                      <li              >                                                      <a              *ngIf                              =                "auth.isAuthenticated()"                            routerLink                              =                "/"                            >                                                      <mat-icon              class                              =                "icon"                            >            home                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Home                              </span              >                                                      </a              >                                                      </li              >                                                      <li              >                                                      <a              routerLink                              =                "/dashboard"                            >                                                      <mat-icon              class                              =                "icon"                            >            dashboard                              </mat-icon              >                                                      <span              class                              =                "label"                            >            Dashboard                              </span              >                                                      </a              >                                                      </li              >                                                      <li              >                                                      <a              *ngIf                              =                "auth.isAuthenticated()"                            (click)                              =                "auth.logout()"                            type                              =                "button"                            >                                                      <mat-icon              class                              =                "icon"                            >            input                              </mat-icon              >                                                      <span              class                              =                "label"                            >            LogOut                              </span              >                                                      </a              >                                                      </li              >                                                      </ul              >                                                      </div              >                                                      </mat-toolbar              >                                                      <main              >                                                      <router-outlet              >                                                      </router-outlet              >                                                      </main              >                                                      </mat-sidenav-content              >                                                      </mat-sidenav-container              >                              

In the new version of this file, you use the methods defined in the service created before to show or hide the login and logout buttons.

You will need to import AuthService in the AppComponent class and make it fetch the token returned by Auth0. So, open the app.component.ts file and replace its contents with this:

                      import            {            Component            }            from            '@angular/core'            ;            import            {            AuthService            }            from            './auth.service'            ;            @Component            (            {            selector:            'app-root'            ,            templateUrl:            './app.component.html'            ,            styleUrls:            [            './app.component.css'            ]            }            )            export            class            AppComponent            {            constructor            (            public            auth:            AuthService)            {            auth.            handleAuthentication            (            )            ;            }            }                  

Lastly, you will need to update the app.module.ts file as follows:

                      // ... other import statements ...            import            {AuthService}            from            './auth.service'            ;            @NgModule            (            {            // ... declarations and imports properties ...            providers:            [DataService,            AuthService]            ,            // ... bootstrap property ...            }            )            export            class            AppModule            {            }                  

Running your application now, you will be able to log in through Auth0. After logging in, you will see that you are redirected to the dashboard and that the Logout button is shown.

Angular Material project secured with Auth0

Enabling Data Deletion

Now that your app is secured with Auth0, you will want to allow authenticated users to delete blog posts. To do so, you will inject AuthService in your DashboardComponent class and define a new method called deletePost as follows:

                      // ... import statements ...            import            {AuthService}            from            '../auth.service'            ;            // ... @Component ...            export            class            DashboardComponent            {            constructor            (            private            dataService:            DataService,            public            auth:            AuthService)            {            }            // ... displayedColumns and dataSource ...            deletePost            (id)            {            if            (            this            .auth.            isAuthenticated            (            )            )            {            this            .dataService.            deletePost            (id)            ;            this            .dataSource            =            new            PostDataSource            (            this            .dataService)            ;            }            else            {            alert            (            'Login in Before'            )            ;            }            }            }            // ... PostDataSource ...                  

Now, you just have to update the dashboard.component.html file to bind the click event of the delete button to the deletePost method:

                                                    <a              (click)                              =                "deletePost(element.position)"                            type                              =                "button"                            >                                                      <mat-icon              class                              =                "icon"                            >            delete                              </mat-icon              >                                                      </a              >                              

Enabling Data Input

In the last feature of your app, you will use the dialog component of the Angular Material library to allow users to insert new blog posts. As you want only authenticated users to access this feature and you want to let unauthenticated users that they must log in before adding blog posts, you add the *ngIf= "auth.isAuthenticated()" directive to wrap the Add Post button. So, open the dashboard.component.html file and add this directive to the div class = "blocks" element that wraps this button:

                                                    <div              class                              =                "blocks"                            *ngIf                              =                "auth.isAuthenticated()"                            >                                                      <button              button                              =                "submit"                            mat-raised-button              color                              =                "primary"                            >                                                      <mat-icon              >            add                              </mat-icon              >                        Add Post                                          </button              >                                                      </div              >                              

Now, right after this block, add the following one:

                                                    <div              class                              =                "blocks"                            >                                                      <a              button              mat-raised-button              color                              =                "primary"                            (click)                              =                "auth.login()"                            *ngIf                              =                "!auth.isAuthenticated()"                            >                                                      <mat-icon              >            input                              </mat-icon              >            Login to Add Post                                          </a              >                                                      </div              >                              

This will be enough to tell unauthenticated users to log in.

To enable users to create new blog posts, you will create a new component called PostDialogComponent. To do so, issue:

          ng g c post-dialog --module app.module        

Then, open the post-dialog.component.html file and put the following HTML code inside it:

                                                    <h1              mat-dialog-title              >            {{data}}                              </h1              >                                                      <div              mat-dialog-content              >                                                      <form              class                              =                "example-form"                            (ngSubmit)                              =                "onSubmit()"                            >                                                      <mat-form-field              >                                                      <input              matInput              placeholder                              =                "Post Title"                            type                              =                "text"                            required              [(ngModel)]                              =                "blogPost.title"                            name                              =                "name"                            >                                                      </mat-form-field              >                                                      <mat-form-field              >                                                      <textarea              matInput              placeholder                              =                "Post Body"                            required              [(ngModel)]                              =                "blogPost.body"                            name                              =                "body"                            >                                                      </textarea              >                                                      </mat-form-field              >                                                      <mat-form-field              >                                                      <mat-select              matInput              placeholder                              =                "Post Category"                            required              [(ngModel)]                              =                "blogPost.category"                            name                              =                "category"                            >                                                      <mat-option              *ngFor                              =                "let cat of categories"                            [value]                              =                "cat.value"                            >                        {{ cat.viewValue }}                                          </mat-option              >                                                      </mat-select              >                                                      </mat-form-field              >                                                      <button              mat-raised-button              type                              =                "submit"                            color                              =                "primary"                            >            Save                              </button              >                                                      </form              >                                                      </div              >                                                      <div              mat-dialog-actions              >                                                      <button              mat-raised-button              class                              =                "close"                            (click)                              =                "onNoClick()"                            color                              =                "warn"                            >            Cancel                              </button              >                                                      </div              >                              

You can see you are using mat-dialog, mat-input, and mat-select from the Angular Material library in the HTML file. So, as you can imagine, you will need to import them into your material.module.ts file:

                      import            {NgModule}            from            '@angular/core'            ;            import            {            // ... other modules ...            MatDialogModule,            MatInputModule,            MatSelectModule,            }            from            '@angular/material'            ;            @NgModule            (            {            imports:            [            // ... other modules ...            MatDialogModule,            MatInputModule,            MatSelectModule,            ]            ,            exports:            [            // ... other modules ...            MatDialogModule,            MatInputModule,            MatSelectModule,            ]            }            )            export            class            MaterialModule            {            }                  

Besides updating this module, you will need to import and configure the FormsModule from @angular/forms in the main module. So, open the app.module.ts file and update it as follows:

                      // ... other imports ...            import            {FormsModule}            from            '@angular/forms'            ;            @NgModule            (            {            // ... declarations property ...            imports:            [            // ... other modules ...            FormsModule,            ]            ,            // ... providers and bootstrap ...            }            )            export            class            AppModule            {            }                  

Also, to make your dialog look nice, you can insert the following rules in the post-dialog.component.css file:

                      .example-form            {            display            :            flex;            flex-direction            :            column;            }            .example-form > *            {            width            :            100%;            }            .close            {            width            :            100%;            }                  

Then, you can open the post-dialog.component.ts file and replace its code with the following;

                      import            {Component,            EventEmitter,            Inject}            from            '@angular/core'            ;            import            {            MAT_DIALOG_DATA            ,            MatDialogRef}            from            '@angular/material'            ;            import            {DataService}            from            '../data/data.service'            ;            @Component            (            {            selector:            'app-post-dialog'            ,            templateUrl:            './post-dialog.component.html'            ,            styleUrls:            [            './post-dialog.component.css'            ]            }            )            export            class            PostDialogComponent            {            blogPost            =            {            title:            ''            ,            body:            ''            ,            category:            ''            ,            position:            0            ,            date_posted:            new            Date            (            )            }            ;            public            event:            EventEmitter<            any            >            =            new            EventEmitter            (            )            ;            constructor            (            public            dialogRef:            MatDialogRef<PostDialogComponent>            ,            @Inject            (            MAT_DIALOG_DATA            )            public            data:            any            ,            public            dataService:            DataService            )            {            }            onNoClick            (            )            :            void            {            this            .dialogRef.            close            (            )            ;            }            onSubmit            (            )            :            void            {            this            .blogPost.position            =            this            .dataService.            dataLength            (            )            ;            this            .event.            emit            (            {data:            this            .blogPost}            )            ;            this            .dialogRef.            close            (            )            ;            }            categories            =            this            .dataService.            getCategories            (            )            ;            }                  

To make a button open up this dialog box, you need to tell it to do so by binding a click event to the button. So, open the dashboard.component.html and modify the button you created before to look like this:

                                                    <div              class                              =                "blocks"                            *ngIf                              =                "auth.isAuthenticated()"                            >                                                      <button              button                              =                "submit"                            mat-raised-button              color                              =                "primary"                            (click)                              =                "openDialog()"                            >                                                      <mat-icon              >            add                              </mat-icon              >                        Add Post                                          </button              >                                                      </div              >                              

Then, in the TypeScript file of the dashboard.component.ts, you will have update the code as:

                      // ... other import statements ...            import            {PostDialogComponent}            from            '../post-dialog/post-dialog.component'            ;            import            {MatDialog}            from            '@angular/material'            ;            // ... @Component ...            export            class            DashboardComponent            {            constructor            (            public            auth:            AuthService,            public            dialog:            MatDialog,            private            dataService:            DataService)            {            }            // ... displayedColumns, dataSource, and deletePost ...            openDialog            (            )            :            void            {            let            dialogRef            =            this            .dialog.            open            (PostDialogComponent,            {            width:            '600px'            ,            data:            'Add Post'            }            )            ;            dialogRef.componentInstance.event.            subscribe            (            (result)            =>            {            this            .dataService.            addPost            (result.data)            ;            this            .dataSource            =            new            PostDataSource            (            this            .dataService)            ;            }            )            ;            }            }            // ... PostDataSource ...                  

Lastly, open the . /src/app/app.module.ts file and add the following property to @NgModule:

          entryComponents:            [            PostDialogComponent            ]            ,                  

Now, to see the dialog in action, run ng serve, log in, and head to http: / /localhost: 4200 /dashboard. From there, hit the Add Post button, and you will see the following screen:

Angular Material components - showing the dialog component

That's it! You have just created your first app with Angular Material. Easy right?!

"Angular Material makes it easy to develop modern apps with great UI!"

Tweet

Tweet This

Conclusion

In this article, you had the chance to use Angular Material components to create a beautiful application without investing too much time thinking about styles. What is great is that besides being easy to use, Angular Material components leverage best practices and a common UI that most users already use. Awesome, right?

Is Angular Material Included In New Angular App

Source: https://auth0.com/blog/creating-beautiful-apps-with-angular-material/

Posted by: hubbardhithorable.blogspot.com

0 Response to "Is Angular Material Included In New Angular App"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel