We can now begin to develop our regular Angular component. First, we define our template with the ./src/app/hideaway-message/hideaway-message.component.html

file

(although

this could be done in the component main file).



1 2 3 4 5 6 7 8 9 10 11 < div class = "panel panel-default" > < div class = "panel-heading" > { { title } } < button ( click ) = "hideContent($event)" style = "float: right" > { { btnText } } < / button > < / div > < div class = "panel-body" * ngIf = "!hidden" > { { content } } < / div > < / div >

We also add our styling in our ./hideaway-message.component.css within the same folder as the template file:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 . panel { margin : 10px ; background - color : # fff ; border : 1px solid transparent ; border - radius : 4px ; - webkit - box - shadow : 0 1px 1px rgba ( 0 , 0 , 0 , . 05 ) ; box - shadow : 0 1px 1px rgba ( 0 , 0 , 0 , . 05 ) ; } . panel - default { border - color : # ddd ; } . panel - default > . panel - heading { color : # 333 ; background - color : # f5f5f5 ; border - color : # ddd ; } . panel - heading { padding : 10px 15px ; border - bottom : 1px solid transparent ; border - top - left - radius : 3px ; border - top - right - radius : 3px ; } . panel - body { padding : 15px ; }

We can now define our component in the hideaway-message.component.ts file like this:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import { Component , Input , ViewEncapsulation } from '@angular/core' ; @Component ( { selector : 'hideaway-message' , templateUrl : './hideaway-message.component.html' , styleUrls : [ './hideaway-message.component.css' , ] , encapsulation : ViewEncapsulation . Native } ) export class HideawayMessageComponent { constructor ( ) { } hidden = false ; btnText = 'Hide' hideContent ( e ) { e . preventDefault ( ) ; this . hidden = ! this . hidden ; this . btnText = this . btnText == 'Hide' ? 'Show' : 'Hide' ; } @Input ( ) content ; @Input ( ) title ; }

ViewEncapsulation helps compile the CSS down to JavaScript (i.e., using Shadow DOM ), so the component can be used without having to worry about the CSS referencing properly. We can now check to see if our component is working by putting it within the app-root tag in the index.html file:

1 2 3 4 5 6 7 <body> < app - root > < hideaway - message title = "Lorem ipsum dolor sit amet" content = "Lorem ipsum dolor sit amet, iusto appellantur vix te, nam affert feugait menandri eu. Magna simul ad est. Nostrum neglegentur ius at, at pertinax repudiare vel. Vim an adolescens quaerendum." > < / hideaway - message > < / app - root > < / body >

We now start our application so it can be in a browser (on the default Angular port http://localhost:4200/ ) using the command below in the command line: ng serve

Now that our component is fully functional, the next step is to convert it into an Angular element. We do this by editing the app.module.ts file to look like this:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import { BrowserModule } from '@angular/platform-browser' ; import { NgModule , Injector } from '@angular/core' ; import { createCustomElement } from '@angular/elements' ; import { HideawayMessageComponent } from './hideaway-message/hideaway-message.component' ; import { AppComponent } from './app.component' ; @NgModule ( { declarations : [ HideawayMessageComponent , AppComponent ] , imports : [ BrowserModule ] , entryComponents : [ HideawayMessageComponent ] } ) export class AppModule { constructor ( private injector : Injector ) { } ngDoBootstrap ( ) { const element = createCustomElement ( HideawayMessageComponent , { injector : this . injector } ) ; customElements . define ( 'hideaway-message' , element ) } }

In the code above, we have stopped Angular from automatically bootstrapping the application. We accomplished that by removing the bootstrap property in the decorator parameter object and overwriting the ngDoBootstrap method in the AppModule class. We also add the component, HidawayMassageComponent to the entryComponents array, to instruct Angular to create the component, even though it is not part of a template.

Then within ngDoBootstrap method, the HidawayMassageComponent is parsed using the function createCustomElement from the Angular element module to prepare it to be added to CustomElementRegistry (this process includes making the component extend the HTMLElement abstract class). After the component has been transformed into an element, we then add it to the list of elements available to the DOM using customElement object which is available globally in JavaScript. Now we can use the element in an HTML file within our project. For example, the index.html file could be rewritten as below:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <body> < div style = "width: 90%; margin: auto;" > < hideaway - message title = "Lorem ipsum dolor sit amet" content = "Lorem ipsum dolor sit amet, iusto appellantur vix te." > < / hideaway - message > < hideaway - message title = "Lorem ipsum dolor sit amet" content = "Lorem ipsum dolor sit amet, iusto appellantur vix te." > < / hideaway - message > < hideaway - message title = "Lorem ipsum dolor sit amet" content = "Lorem ipsum dolor sit amet, iusto appellantur vix te." > < / hideaway - message > < hideaway - message title = "Lorem ipsum dolor sit amet" content = "Lorem ipsum dolor sit amet, iusto appellantur vix te." > < / hideaway - message > < / div > < / body >

Building the Custom Element

Now that we can use the element in an HTML document within our project, the next step is to try to make sure that we can use the element by referencing a file with the element declaration and dependencies. For this, we need to pull in a module called concat , using npm:

npm install concat --save-dev

Next, we create a build script in the root of the project folder and name it accordingly. In the

build-script.js

file, we add the path to the production build files and a path to the output file after concatenation, and pass it to the concat function like below:

1 2 3 4 5 6 7 8 const concat = require ( 'concat' ) ; const files = [ './dist/AngularElements/runtime.js' , './dist/AngularElements/polyfills.js' , './dist/AngularElements/main.js' ] ; const outputFile = './dist/final-bundle.js' ; concat ( files , outputFile ) ;

This list of files is the product of the Angular build command, and these files are usually found in the dist directory in the project root directory – please r eplace AngularElements in the paths above with the name of your project. Please note that these paths are specific to Angular apps built with version 6.0 of the CLI or higher.



We need to add a script in the package.json file to firstly build our application in prod mode, without hashing the output file, and run our build-script. We add the code below to the scripts object:

1 "build-element" : "ng build --prod --output-hashing=none && node build-script.js"



Now we can run the command below to get our concatenated file: