Creating a Packaged Self Initializing Angular Material Icons Assets Service | Task

Ole Ersoy
Mar - 14  -  3 min

Scenario

We have created a service that adds our SVG files to the Angular Material Icon registry.

In this minimal version we have a single Asset object keyed on an SVG object container.

export const SVG:KeyAsset = {
  FS_LOGO: {
      name: 'fs_logo',
      url: 'https://raw.githubusercontent.com/fireflysemantics/logo/master/l1.svg'
  }
}

We register this asset in the MatIconRegistry using the name and url properties.

import { Injectable } from '@angular/core';
import { DomSanitizer } from "@angular/platform-browser";
import { MatIconRegistry } from '@angular/material/icon';

export interface Asset {
  name: string;
  url: string;
}

export interface KeyAsset {
  [key: string]: Asset;
}

export const SVG:KeyAsset = {
  FS_LOGO: {
      name: 'fs_logo',
      url: 'https://raw.githubusercontent.com/fireflysemantics/logo/master/l1.svg'
  }
}

@Injectable({
  providedIn: 'root'
})
export class AssetService {

  constructor(
    private matIconRegistry: MatIconRegistry,
    private domSanitizer: DomSanitizer) {
    {
      Object.keys(SVG).forEach(k=>{
        this.matIconRegistry.addSvgIcon(
          SVG[k].name,
          this.domSanitizer.bypassSecurityTrustResourceUrl(SVG[k].url));  
      })
    }
  }
}

If we package this service in a library as is, it will not work.

The reason is we also have to rememember to add the HttpClientModule as the MaterialIconRegistry as the service depends on these modules to load and register the SVG files.

Therefore we want to create and package both the service and the module that will be imported in order to access the service.

We also want the service to be self initializing. We should only have to import and register the module in order for the service to dynamically load the SVG assets and make them ready for use by a MatIcon element.

Approach

We will be producing this NPM package.

We can add this to an Angular project using the CLI or Stackblitz and after registering the AssetsModule.

This is the github repository containing the source code.

This is a youtube that outlines all the steps in creating the project and publishing it.

This is the module that will be packaged along with the AssetService.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { AssetService } from './assets.service';
import { MatIconModule } from '@angular/material/icon';

@NgModule({
  declarations: [],
  providers: [AssetService],
  imports: [
    CommonModule,
    HttpClientModule,
    MatIconModule
  ],
  exports: []
})
export class AssetsModule { 
  constructor(private a:AssetService) {}
}

We've placed it along side the asset.service.ts service in our Angular library. The module is exported by public-api.ts in the Angular Package Format library. The module constructor injects the asset service, and this initializes the icon registry.

After the module is imported in our projects the mat-icon containing the FS_LOGO can be rendered like this:

<mat-icon [svgIcon]="SVG.FS_1_LOGO.name" style="width: 42px; height:42px; font-size: 42px"></mat-icon>

Demo

NPM Imported Module

This stackblitz depends on and imports the AssetsModule, thus demonstrating using the NPM Package:

Unpackaged Stackblitz Demo

This has the module and service locally within the Stackblitz: