Overview Of Angular Elements

Angular elements is most exiting feature of angular framework version 6.x, it has been in the talk since angular 6.x was released and why not? I mean you can use component which is built on angular on any web platform regardless it runs on angular or not. It is great feature one can say but it is still in early phase, we can’t use that angular element outside the angular project. (Angular team still working on it to make it available on any web platform.) But in this article I will show, how we can manage angular element outside the angular environment. I.e. we will be using it on any web platform.

Angular elements are the most exciting feature of Angular Framework version 6.x. It has been buzzed about since Angular 6.x was released and why not? After all, you can use the component which is built on Angular on any web platform regardless of it running on Angular or not. It is a great feature, but it is still in an early phase. We can’t use that Angular element outside of the Angular project. (The Angular team is still working on it to make it available on any web platform.) But in this article, I will show how we can manage an Angular element outside the Angular environment; i.e., we will be using it on any web platform.

So, let’s dive into the process to create an Angular element step by step.

Configuration & Setup

First, we will create a blank application using Angular CLI.

ng new angularElementDemoApp

After creating the application using CLI, add the following command.

ng add @angular/elements    (it will work with angular 6.x framework & rxjs 6.x  only)

Angular Elements

Or run the following command.

npm install @angular/elements  - -save

And for the browser compatibility, download some polyfill packages.

npm install @webcomponents/custom-elements - -save

Then, also, update polyfill.ts file as shown in the image below.

Angular Elements

 

Create the component

Now, create the component. There is nothing special about a component; i.e., we are not doing anything special about the component. It is just a simple component with two buttons, one for incrementing the counter and the other for decrementing the counter, and one heading to display the counter.

Generate the component using Angular-cli,

ng g c demo-counter

And, change the demo-counter.component.html with the following one.

  1. <button (click)="onIncrClick()" >+</button>  
  2. <h1>{{count}}</h1>  
  3. <button (click)="onDecrClick()" >-</button>  

It is just simple HTML with two buttons and one header, as said above. Also, change the demo-counter.component.ts file with the following code.

  1. export class DemocounterComponent implements OnInit {  
  2. count:number=0;  
  3.   constructor() { }  
  4.   
  5.   ngOnInit() {  
  6.   }  
  7.   onIncrClick(){  
  8.    this.count=this.count+1;  
  9.   }  
  10.   onDecrClick(){  
  11.     this.count=this.count-1;  
  12.   }  
  13. }  

It is a simple code like when the user presses the + button, it will be incrementing the counter by one and when the user presses the – button, it will decrement the counter by one. Nothing special about the component.

Now, I want to use this component outside the Angular application; i.e., on any web platform. To do so, first, we will register it as a custom element.

Setting Up app.module.ts,

As you can see, by default inside the app.module.ts, it will bootstrap to AppComponent, but in our case, we don’t want to do such a thing.

Angular Elements

So, in our case, we will remove the bootstrap array from @NgModule and add one method in AppModule class. The name of the method is ngDoBootstrap() which can be used to bootstrap manually.

And also, inside AppModule, we will create our customElement and register it. So finally, our updates app.module.ts will look like below.

  1. import { BrowserModule } from '@angular/platform-browser';  
  2. import { NgModule,Injector } from '@angular/core';  
  3. import { createCustomElement } from '@angular/elements';  
  4. import { DemocounterComponent } from './democounter/democounter.component';  
  5.   
  6. @NgModule({  
  7.   declarations: [  
  8.     DemocounterComponent  
  9.   ],  
  10.   imports: [  
  11.     BrowserModule  
  12.   ],  
  13.   entryComponents:[  
  14.     DemocounterComponent  
  15.   ],  
  16.   providers: [],  
  17.   bootstrap:[]  
  18. })  
  19. export class AppModule {  
  20.   public constructor(private injector:Injector){  
  21.   }  
  22.   ngDoBootstrap(){  
  23.     const el=createCustomElement(DemocounterComponent,{injector:this.injector});  
  24.     customElements.define('demo-counter',el);  
  25.   }  
  26.  }  

The most important take away of the above code is any component which is not called by its selector or through the router, must be declared inside entryComponents.

customElements.define() is a method of HTML5 and it has nothing to do with Angular. The first argument to define the method is the name you want to register for your component and the second argument is the component itself.

Now, as we want to use the above created component outside of the Angular application, we will do the following adjustment to our production build.

Generate Production Build with the following Adjustment

Generate build

ng build --prod --output-hashing none --build-optimizer false

Our production build inside the dist directory will look like the following.

Angular Elements

It will generate 3 different JS files - main.js,polyfills.js, and runtime.js file. So, to concat these three files into one signle file, we will add the following packages to our application.

npm install fs-extra concat - -save-dev

And then, create the file build-script.js as shown below on root level.

  1. const fs = require('fs-extra');  
  2. const concat = require('concat');  
  3. (async function build() {  
  4.     const files =[  
  5.          './dist/AngularElementDemo/runtime.js',  
  6.         './dist/AngularElementDemo/polyfills.js',  
  7.         './dist/AngularElementDemo/main.js'  
  8.     ]  
  9.     await fs.ensureDir('elements')  
  10.   
  11.     await concat(files, 'elements/demo-counter.js')  
  12.     console.info('Elements created successfully!')  
  13. })()  

The above code will generate the single JS file for the build; i.e., it will concat our three different JS files - polyfills, main, and runtime to one file with the name of demo-counter.js inside elements directory.

So now, to generate a single JS file from build-script.js file, we need to adjust package.json file as shown below.

Angular Elements

 

Then, run the following on cmd,

node build-script.js

Angular Elements

Angular Elements

 

So now, we are all done. To use our Angular component outside of the Angular application means on any web platform, so let us write the below-shown HTML code.

  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">  
  6.     <meta http-equiv="X-UA-Compatible" content="ie=edge">  
  7.     <title>Angular Element Demo</title>  
  8. </head>  
  9. <body>  
  10.   <demo-counter></demo-counter>  
  11.   <script src="../elements/demo-counter.js"></script>  
  12. </body>  
  13. </html>  

Create one HTML page and copy the element directory with demo-counter.js file where you created your HTML page.

In my case, my folder structure will look like below.

Angular Elements

 

Output

Angular Elements

 

 

Summary

Therefore, we can conclude that to work with Angular Elements, we need to perform the following steps:

  1. Install @angular/elements  and @webpackcomponents/custom-elements
  2. Create component
  3. Register component in entryComponent in app.module.ts
  4. Generate production build and generate single js file
  5. Use it on html

 I hope you find this post useful. Thanks for reading.  If you like this post, please share it.