Using Angular Elements with NgRx

Santosh Yadav
Apr 29, 2019 · 5 min read

In this blog, Let’s walk through how to build a fully functional counter that is backed by NgRx and distributed across multiple angular elements. This will allow us to deploy our counter for use across multiple frameworks.

Prerequisites

Basic knowledge of Angular and NgRx is expected for this blog.

Versions used:

  1. Angular: 7.2.x
  2. NgRx: 7.4.x

Angular Elements

Angular Elements are simply Angular Components packaged as custom elements so it can work with any framework or library as an HTML tag.

Angular offers createCustomElement() API with @angular/elements package to convert the component to custom elements. You can read more on Angular Elements on the Angular Docs.

Background

We got the idea of this blog while working on one of the tasks on NgRx you can read more about it on GitHub.

About the Project

We are going to build an Angular library which we will utilize in an Angular App and one static HTML page. To achieve this we need 2 applications within our project, one to showcase how it works with Angular App, and second to build/generate a .js file which can be utilized in our static HTML file.

Initial Project Setup

First, create a new Angular Project using Angular CLI.

ng new ngRxElementDemo --createApplication=false

Now it is time to create the Angular Library and Angular Application as discussed. Use below commands to create the Library and Applications.

ng g lib my-counter
ng g application elementApp
ng g application counterelement
  1. elementAppwill be used to showcase how we can use our Elements within an Angular Application.

2. counterelementwill be used to create a build which we can use later in the HTML page.

Once the installation is done, let’s add NgRx and Angular Elements as a dependency to our project with commands given below. We are also using Angular Material in our showcase application, but it is optional.

ng add @ngrx/store --project=my-counter
ng add @angular/elements

The only problem is ng add @angular/elements makes changes to default project, in this case, elementApp. You have to copy the changes to counterelement as well. There is an issue logged on Angular.

You will notice below property included inside scripts section of elementApp inside angular.json, copy and paste the same to the scripts section of counterelement

"scripts": [
{"input": "node_modules/document-register-element/build/document-register-element.js"}
]

Time to Create the Library

Run the commands below to create new components, modules and we will also create action and reducer. We will see the complete implementation of increment-counter here.

ng g module counter --project=my-counter
ng g c counter --project=my-counter --flat=true
ng g c counter-increment --project=my-counter
ng g c counter-decrement --project=my-counter
ng g c counter-reset --project=my-counter

In this post, we are going to use the same example mentioned on NgRx.io, add the counter and reducer code into your lib folder.

Now let’s add the code in our component. Every component will inject the Store to access or update the counter. All components are standard angular components, no changes here.

Add the below code in counter.component.ts :

Now make the changes to the counter-increment.component.ts and counter-increment.component.html files.

There is nothing new in the above code if you know the basics of NgRx, we are dispatching the Increment action here, which will update the counter.

Now we need to make changes to thecounter.module.ts file

In the above code, you may notice some difference from a typical Angular Module.

  1. We have included each of our components in theentryComponents array, because they are required to be loaded as Angular Elements.
  2. Usage of createCustomElement , we have used this API to register the Angular Component as Angular Elements. Where the first parameter is the component and the second parameter is the injector instance.

After making all these changes, make sure to add below code to public-api.ts file available in the library:

Now it is time to build and check the library, to make sure the library gets compiled use below command:

ng build my-counter

Making changes to Angular App

First, we will make our Angular Element work with the Angular Application which is in our case is elementApp

  1. Changes to app.module.ts

So let’s see what we have done differently here:

  1. import { CounterModule } from 'my-counter' Here we have imported the module from our library so we can utilize the functionalities provided, and added the same to imports array.
  2. schemas: [CUSTOM_ELEMENTS_SCHEMA] This is required so we can use Custom elements within our app.

Add the below lines of code to include the Custom Elements in our app.component.html

Before we can build and run our app, we have to include one polyfill to our application, go ahead and run the below command from the root of the project:

npm i @webcomponents/webcomponentsjs -save

Once installed add below import to polyfills.ts, you can read more about this polyfill. The below line of code is also required in other apps, please add the same import to polyfills.ts insidecounterelement app as well.

import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js';

Time to run our app to see the changes in action now, run the below command which will build our application and run the application on port 4200:

ng build my-counter && ng serve — project=elementApp -o
Application using Angular Elements

Making changes to run Custom Elements in a static page

Now we will learn, how to create the build and use the Angular Elements inside a static HTML page.

  1. Changes to app.module.ts in customelelment Application.

Let’s see what we have done differently here:

  1. We have removed the AppComponent from the bootstrap array, as we want to bootstrap the app manually, notice ngDoBootstrap being called here.

Creating counter-element.js

Time to create the .js file which can be used outside an Angular App.

  1. Install the packages which will help us to create the build, the jscat package will help us to concatenate the multiple files and create the output file, which will be our counter-element.js file.
npm install jscat --save-dev

2. Add the below command in package.json

"build-element": "ng build my-counter && ng build --project=counterelement --prod --output-hashing=none","package": "jscat ./dist/counterelement/runtime.js ./dist/counterelement/polyfills.js ./dist/counterelement/scripts.js ./dist/counterelement/main.js > htmlapp/counter-element.js",

Run the first command npm run build-element to create a build, you will notice a new dist/counterelement folder.

3. Create a folder htmlapp in the root directory, add the index.html file in the folder and add below code.

4. Run the npm run package it will create a new file named counter-element.js inside this newly created htmlapp folder.

5. make sure you have http-server npm package installed globally, run the below command from the inside htmapp folder

http-server

This command will start a local server on port 8081.

Http server in action

Now move to http://localhost:8081/ to see Angular Elements in action with a static page.

Source Code Repository:

You can download the entire code from:

https://github.com/santoshyadav198613/ngRxElementDemo

Conclusion

There is no difference in using NgRx state management with Angular Elements, you can easily use the same code which you may have written, convert them to Angular Elements and still utilize the NgRx state management functionality within an Angular App or any with any other framework or library.

Special thanks to Tim Deschryver Wes Grimes Alex Okrushko Brandon Roberts for feedback.

Angular In Depth

The place where advanced Angular concepts are explained

Thanks to Wes Grimes, Tim Deschryver, Brandon Roberts, Alex Okrushko, and Lars Gyrup Brink Nielsen

Santosh Yadav

Written by

Santosh is GDE for Angular and Web Technologies, he is open source contributor for Angular, NgRx and Writer at AngularInDepth and DotNetTricks.

Angular In Depth

The place where advanced Angular concepts are explained

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade