How To Add Angular Material To An Angular Project

Blog Post #009

Duncan Faulkner – August 2020

Adding Angular Material to a new or existing Angular project is a simple process. In the terminal, change the directory to your project and type:

ng add @angular/material

The Angular CLI will now install Angular Material, Angular CDK and Angular Animations and add these as a dependency to the project.

In previous versions of Angular (before v9) hammerjs was required for touch and gesture support.

npm install hammerjs

In the main.ts file in the imports at the top, include the following:

import 'hammerjs' // add this import

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.log(err));

Starting with version 9 of Angular hammerjs is now optional, you no longer need to install this as a dependency, it is now part of @angular/platform-browser. To use it, add the HammerModule to the platform-browser import in the app.module.ts file and include it in the NgModule imports array.

import { HammerModule, BrowserModule } from '@angular/platform-browser';

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserAnimationsModule
    BrowserModule,
    HammerModule,
  ],
    bootstrap: [AppComponent]
})
export class AppModule {
}

You can also create a custom class to override specific features of HammerModule.

import { Injectable } from '@angular/core';
import { BrowserModule, 
         HammerModule, 
         HammerGestureConfig, 
         HAMMER_GESTURE_CONFIG} 
from '@angular/platform-browser';

@Injectable()
export class HammerConfig extends HammerGestureConfig {
    overrides = <any> { 
       'pinch': {enable: true}
  }
}

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserAnimationsModule
    BrowserModule,
    HammerModule,
  ],
    providers: 
    [{
      provide: HAMMER_GESTURE_CONFIG, 
      useClass: HammerConfiguration
   }],
   bootstrap: [AppComponent]
})
export class AppModule {
}

The other values that can be overridden are:
pan, pinch, press, rotate, swipe and tap.
Note: that pinch and rotate are disabled by default.

Thanks for reading enjoy…

Follow me on Twitter to get notified about my newest blog posts!🐥


How To Use Typescripts …SpreadOperator In Angular

Blog post #004

Duncan Faulkner – February 2020

Recently I’ve found myself looking at ways I can improve the reading of my code. Just little things, just to tweak this or that just to make the code a little more easier on the eye.

Recently I’ve started using the spread operator (…) as I find this looks a lot cleaner and makes code easier to read.

In this post I’m going to show you how to use the spread operator in your Angular module files.

Most of the module files I’ve written have all looked the same. Starting at the top of the file are the Imports, followed by the NgModule with some or all of the following: Imports, Exports, Declarations, Entry Components and Providers.

Depending on the number of imports into the module this can have a lot of repeated code. So these files are ideal for the spread operator, reducing the repeated code. Lets see and example.

import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatChipsModule } from '@angular/material/chips';

import { NgModule } from '@angular/core';

@NgModule({
  imports: [
    MatAutocompleteModule,
    MatButtonModule,
    MatButtonToggleModule,
    MatCardModule,
    MatCheckboxModule,
    MatChipsModule
  ],

  declarations: [],
  exports: [
    MatAutocompleteModule,
    MatButtonModule,
    MatButtonToggleModule,
    MatCardModule,
    MatCheckboxModule,
    MatChipsModule
  ],
  entryComponents: [],
  providers: [MatIconRegistry]
})
export class MaterialModule { }

The above example is from the Mat-Icon material module file and shows the same things repeated three times in this example. Lets refactor this code.

import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatChipsModule } from '@angular/material/chips';

import { NgModule } from '@angular/core';

const MODULES = [
  MatAutocompleteModule,
  MatButtonModule,
  MatButtonToggleModule,
  MatCardModule,
  MatCheckboxModule,
  MatChipsModule
];
@NgModule({
  imports: [
    ...MODULES
  ],
  declarations: [],
  exports: [
   ...MODULES
  ],
  entryComponents: [],
  providers: [MatIconRegistry]
})
export class MaterialModule { }

Now, unfortunately the Angular Material imports need to be individually imported for each feature separately, but it does reduce the code (a bit) and it does help with having just one copy to manage, lets have another example, that I have changed to use the spread operator (you should be able to visualise what this looked like before).

import { NgModule } from '@angular/core';
import { VendorModule } from './vendor.module';

import {
  AnalysisComponent,
  ChartComponent,
  IconComponent,
  PodComponent,
  SpinnerComponent,
  TermsComponent,
  ChangePasswordComponent
} from './components';

import {
  PortPipe,
  NumericPipe,
  AsteriskPipe,
  SplitIpPipe,
  RemoveUnderscorePipe,
  AddUnderscorePipe,
  FormatBytesPipe
} from './pipes';

import { NumberDirective } from './directives';

const COMPONENTS = [
  AnalysisComponent,
  ChartComponent,
  IconComponent,
  PodComponent,
  SpinnerComponent,
  TermsComponent,
  ChangePasswordComponent
];

const PIPES = [
  PortPipe,
  NumericPipe,
  AsteriskPipe,
  SplitIpPipe,
  RemoveUnderscorePipe,
  AddUnderscorePipe,
  FormatBytesPipe
];

const DIRECTIVES = [NumberDirective];

const MODULES = [VendorModule];

const ENTRYCOMPONENTS = [TermsComponent, ChangePasswordComponent];

@NgModule({
  imports: [...MODULES],
  declarations: [...COMPONENTS, ...PIPES, ...DIRECTIVES],
  exports: [...COMPONENTS, ...PIPES, ...DIRECTIVES, ...MODULES],
  entryComponents: [...ENTRYCOMPONENTS],
  providers: [...PIPES]
})
export class SharedModule {}

In the example above, imports for the component, pipes and directives are all grouped together. Constants are configured, and used in the NgModule section of the file . The important part of this file is the NgModule section and you can easily now read that section without all the clutter of all the various components, pipes and directives all over the place.

The spread operator include options for object destructing, rest params and array destructing (as shown above).

Thanks for reading!


Previous Posts…