Getting Started with Angular Elements
Preston Lamb
Posted on May 29, 2019
Do you ever work on a non-Angular project? It could be a Wordpress theme, a JAM stack project (like this site!), or a .NET Core app, just to name a few. Now, pretend that you are working on one of those apps but need some amount of front end functionality included. You want it to work like Angular, but you can't actually write an Angular app (for one reason or another). I was recently in this situation and was pointed in the direction of Angular Elements.
Angular Elements provides a way to write custom elements in Angular that can be compiled and used on any site. If you'd like to read a little more about custom elements, go check out this site. Essentially, it's a way to define new HTML elements that can be used just like any native HTML element.
So let's see how to get started with Angular elements!
Let's start with a basic header component, one that just shows a static message wherever you use it. Maybe it's a company logo, or something you don't want to duplicate the code for over and over. In your Angular application, use the CLI to generate a component; ng g c custom-header
will do. For demonstration's sake, let's say the template is simple and as follows:
<h1>My Company Header</h1>
Again, this is just something simple, but that we don't want to repeat on all our different sites. So, how do we go about using this in a non-Angular application? It's really pretty simple!
There are 5 steps for doing this: install the @angular/elements
package, change the target in your tsconfig.json file, list your desired component in the entryComponents
array and register the custom elements in the ngModule
, build the project to get the needed scripts, and lastly include it in your non-Angular project.
Step 1 — Install @angular/elements
Turns out this step is pretty simple. Start by running ng add @angular/elements
in your terminal. And that will do most of the work for you. The Angular CLI and schematics are incredible. The Angular and CLI teams have been incredible in that sense.
Step 2 — Edit tsconfig.json
For the build to work and allow for you to use your custom elements in another project, you need to change the target attribute in the tsconfig.json file. The default value when the project is created is "es5"; change that to "es2015" and you should be good to go.
Step 3 — ngModule
Work
After installing @angular/elements
and building your components, the majority of the work is done in the ngModule
. The first part is in the decorator. In the decorator, add an array called entryComponents
and add your component from above (CompanyHeaderComponent
) to that array:
@ngModule({
...
// Make sure to remove the bootstrap attribute
entryComponents: [CompanyHeaderComponent],
})
export class AppModule {}
The next part of this step is registering the Angular element as a custom element in the constructor of the AppModule
. This is pretty simple using functions from the @angular/elements package:
export class AppModule {
constructor(private injector: Injector) {
const companyHeader = createCustomElement(CompanyHeaderComponent, { injector });
customElements.define('custom-header', customHeader);
}
// This is required so that the component will bootstrap in the project where it's included
ngDoBootstrap() {}
}
That's really all there is to it: add the component to the header, define the custom element, invoke the ngDoBootstrap() {} method. Simple as that.
Step 4 — Build the Project
The next step is to build the application and get the resulting scripts so that it can be included in your external project. Here's a build script you can use, but be sure to replace project-name
with the name of your angular project and ../path/to/output/
to the location on your disk where the output file should be saved. Here's the script:
ng build --prod --output-hashing=none && cat dist/project-name/runtime.js dist/project-name/polyfills.js dist/project-name/scripts.js dist/project-name/main.js > ../path/to/output/ngelements.js
That bash script builds the project, takes the needed files from the output and concatenates them into a single file, and then places it in a location that you choose. I will point out that it's important to have concatenate in the above order. If you do it out of order, the script won't work. I learned that the hard way. But that's it! Now you're ready to use it in your external project.
Step 5 — Implement your Custom Element
To implement the custom element, include the script output in step 3 in the HTML file for the project where it'll be used. Then, in the HTML, use it in the following manner:
<custom-header></custom-header>
It's amazing, but that's all it takes. With that, your custom header will now be included on the page! I know it sounds too good to be true, but that's really all it takes.
More Options
A static header is great, but we really need more flexibility. In Angular, this includes @Input()
s and @Output()
s. In your components, you use them the exact same as you normally would. Then register the custom elements and build the project the same as in steps two and three above. Include the resulting script in your external project, and you're ready to go.
Now, let's assume you've provided an @Input()
named companyName
on the CustomHeaderComponent
. When you put this in the HTML, it'll look like this:
<custom-header company-name="My Company Name"></custom-header>
The value you put in that company-name
attribute will be output wherever you've chosen in the component.
@Output()
s are easy to deal with as well. In a new script, you need to get a reference to the custom-header
element and add an event listener with the same name as the @Output()
. Then, when it's triggered, you'll be able to access that event's data. Here's an example:
const customHeaderEl = document.querySelector('custom-header');
customHeaderEl.addEventListener('myCustomOutput'. (evt) => {
console.log(evt);
});
Again, I know this looks too simple to possibly be true, but it really is this easy. I was surprised when I was learning this at just how easy it was.
Conclusion and Next Steps
I really do believe that this is the future of web development. Build custom elements and distribute them to be used by anyone on any platform, wherever they are. And Angular has made it so easy to do just that. Develop them in a familiar environment, easily build them, and easily implement them.
My next steps are to figure out how to use content projection in conjunction with custom elements. Custom elements are great, but the developer building the component will determine the UI. It would be nice if they could provide the UI while you provide the functionality. That's what content projection is for, so if we can use that here, it'll be great. If you have already done this, please reach out to let me know! Also let me know if you've used custom elements in any of your projects!
Posted on May 29, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.