Using Angular Elements — Why and How? — Part 2

Learn How To Build Truly Reusable Components with Angular Elements

Rajat S
Bits and Pieces

--

Angular Elements is awesome 😍! By implementing this awesome feature in your Angular Apps, you can:

  • Convert a regular component into a truly native web element
  • Compile the component into a standalone custom element
  • Communicate with Angular Elements through Inputs and Events

But in my honest opinion, these are some of the simple things that we can do with Angular Elements. In this post, we will continue on this adventure called Angular Elements and learn how to use it to insert an Angular Component inside other frameworks and libraries such as React and Vue. You will also get to see how Angular Elements can create multiple root components inside Angular.

So let’s get started!

This is Part 2 of my series on Angular Elements. I strongly suggest that you read Part 1 before moving forward.

Angular in React!

JavaScript is as big as the world itself! It has so many different libraries and frameworks such as React, Vue, Angular, and all of them are special in their own way.

So wouldn’t it be cool if we could somehow mix these libraries and frameworks together so that we get something that has the advantages of all these frameworks? Maybe doing this also fills up some of the holes/deficits that we faced while using these libraries/frameworks.

This is what Angular Elements does for us by allowing us to use our Angular Components inside other JavaScript libraries such as React and Vue. Let’s take a look at how we can do this with React.

First, let’s create a new React application where we can insert our Angular Component. You can either install the create-react-app CLI and use it to create the React application.

$ npm install -g create-react-app
$ create-react-app angular-react
$ cd angular-react
$ yarn start

But I would suggest you to use the npx utility tool to do this. By using npx we can the CLI even if it is not installed on your system. And you get the latest version of React as well!

$ npx create-react-app angular-react
$ cd angular-react
$ yarn start

yarn start command will run the start script and deploy a development version of the React application on the browser.

Back in Part 1, we have already created a custom component in Angular. It is a simple text and a button element that displays an alert when clicked.

To insert this into the React app, go the Angular project and copy the angularapp.js file from the preview folder. Then go back to the React project, and paste the angularapp.js file inside the public folder. There is a index.html file inside the same folder, and you need to insert a script tag pointing to the angularapp.js file at the bottom of the body section.

<body>
...
<script src="./assets/angularapp.js"></script>
</body>

The Angular Element is now connected to the React Application! But we still need to add it inside our application.

To do this, go to the src folder and rewrite the App.js file as shown below:

import React, {Component} from 'react';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<app-hello-world
title="Batman"
rname="Bruce Wayne"
occupation="World's Greatest Detective"
location="Gotham"
first="Detective Comics #27"
></app-hello-world>

</div>
);
}
}
export default App;

You App will then look like this in the browser:

Click on the button… and nothing will happen!

That is because we haven’t told React what to do when the user clicks on the button. Usually, you would do this by adding a onClick attribute to the button and passing it some function. But the button is inside the Angular Element and we do not have direct access to it. We need to implement some kind of workaround.

First, use the ref attribute to refer the app-hello-world component and pass a function named handleClick to it.

<app-hello-world
title="Batman"
rname="Bruce Wayne"
occupation="World's Greatest Detective"
location="Gotham"
first="Detective Comics #27"
ref={this.handleClick}
></app-hello-world>

This function is still something that we need to create, and all it will do is set the component at the class level. Also, create another function called showInfo that will actually do what we want the entire component to do.

hanldeClick = component => {
this.component = component;
}
showInfo(event) {
alert(event.detail);
}

The showInfo function needs to be triggered whenever the display event is triggered by the button. We do this by passing it to the addEventListener function of the component inside the componentDidMount lifecycle hook. Similarly, we need to pass it to the removeEventListener inside the componentWillUnmount lifecycle hook.

componentDidMount() {
this.component.addEventListener('display', this.showInfo);
}
componentWillUnmount() {
this.component.removeEventListener('display', this.showInfo);
}

All this just to make a button work 😓. Go back to the browser and see what you get:

Tada! The Angular component is working perfectly inside a React app!

Angular communicating with React

To further prove that our angular component can communicate with React, let’s create a new button element called Change that will make some changes to in the application.

One of the most well-known things about React is its state. Let’s refactor our App component so that it uses state instead of writing the value directly into the app-hello-world component.

state = {
title: 'Batman',
rname: 'Bruce Wayne',
occupation: 'World's Greatest Detective',
location: 'Gotham',
first: 'Detective Comics #27'
}

Next, create a new function named change that will change the values of the state using setState.

change = () => {
if (this.state.title == 'Batman') {
this.setState({
title: 'Superman',
rname: 'Clark Kent',
occupation: 'Man of Steel',
location: 'Metropolis',
first: 'Action Comics #1'
})
}
else {
this.setState({
title: 'Batman',
rname: 'Bruce Wayne',
occupation: "World's Greatest Detective",
location: 'Gotham',
first: 'Detective Comics #27'
})
}
}

Finally, make the following changes to the app-hello-world component:

<app-hello-world
title={this.state.title}
rname={this.state.rname}
occupation={this.state.occupation}
location={this.state.location}
first={this.state.first}
ref={this.handleRef}

></app-hello-world>

Go back to the browser and click on the new change button:

Multiple Components

Back in Part 1, you saw how to use Angular Elements in order to turn a regular Angular Component into a standalone element. This means that I don’t need to import that component inside the Angular App, I can just add it anywhere I want as a single script file, and it would still work.

If you haven’t realized it yet, then let me tell you that being able to do something like this help you a lot if you want to import that component into other frameworks. This way, you can add new features to your pre-existing application without having to shuffle things around or even break the app.

In such scenarios, it is better to keep the Angular Component separated from the rest of the application. The Component should also be kept as simple as possible and most likely it should do just one thing for us.

Until now, we have used Angular Elements to create a single component. But what if you want to create multiple components? It would be a waste of time, memory space, and developer’s energy if you had to create new Angular Apps for every standalone element.

Thankfully, we can create multiple components in a single app and use them together or separately, and share the state with each other.

Let’s head back to the Angular App from Part 1 and create a new component. If you don’t have the code from that article, you can go over there and write it down.

Or you can clone this GitHub repository into your system.

$ git clone https://github.com/rajatk16/angular-element-1
$ cd angular-element-1
$ yarn install // or npm run install

Then using Angular CLI, create a new component called hero-form

$ ng g c hero-form

These two commands will create a folder called hero-form that contains the following files:

  • hero-form.component.css
  • hero-form.component.html
  • hero-form.component.spec.ts
  • hero-form.component.ts

Step 1: Form

I feel that a form will be a great example to show how Angular Elements can be used in to create multiple components. Also, I love to build forms! 😍

Let’s quickly build a simple form that contains a couple of Inputs and Button. First, go to the html file inside hero-form and write the following code:

<form [formGroup]="heroForm" (ngSubmit)="onSubmit(heroForm)">
<div>
<label>Title</label>
<input type="text" placeholder="Enter the Hero's Name">
</div>
<div>
<label>Real Name</label>
<input type="text" placeholder="Enter the Hero's Real Name">
</div>
<div>
<label>Occupation</label>
<input type="text" placeholder="Enter the Hero's Real Name">
</div>
<div>
<label>Location</label>
<input type="text" placeholder="Enter the Hero's Real Name">
</div>
<div>
<label>First Appearance</label>
<input type="text" placeholder="Enter the Hero's Real Name">
</div>
<button>Submit</button>
</form>

Then go to the ts file in the same folder and write the following code:

Also, go to the app.module.ts file and add the FormsModule and ReactiveFormsModule from @angular/forms to the imports.

import {FormsModule, ReactiveFormsModule} from '@angular/forms';@NgModule({
declarations: [HelloWorldComponent, HeroComponent, HeroFormComponent],
imports: [BrowserModule,FormsModule, ReactiveFormsModule],
entryComponents: [HelloWorldComponent, HeroFormComponent],
providers: []
})

Step 2: The Rest

We also need to register the new web component inside the app.module.ts file. First, add it to the entryComponents section inside the @NgModule.

@NgModule({
declarations: [HelloWorldComponent, HeroFormComponent],
imports: [BrowserModule, FormsModule, ReactiveFormsModule],
entryComponents: [HelloWorldComponent, HeroFormComponent],
providers: []
})

Then you can register the component inside the AppModule class as shown below:

constructor(injector: Injector) {
const custom = createCustomElement(HelloWorldComponent, {injector});
customElements.define('app-hello-world', custom);

const heroformComponent = createCustomElement(HeroFormComponent, {injector});
customElements.define('app-hero-form', heroformComponent)

}

Run the ./customBuild.sh file in a Bash Shell.

$ ./customBuild.sh

If you are a window user, you can easily get a Bash Shell called Git Bash by installing Git on your system.

Once the build is finished, go to the preview folder and open the index.html file and add the app-hero-form tag inside the body. Leave everything else as it is.

<app-hero-form></app-hero-form>

Then run the index.html file on the browser using the live-server tool.

$ npx live-server index.html

You will then see all these things in your browser.

From this, you can see that Angular Elements has created to standalone components for us. First is the component that renders the text of “Batman” and the “Display” button that we created in Part 1, and the second component is the Form that we just built. The form doesn’t really do anything for us. I just built it for the sake of this article.

Conclusion

Congrats! You have now reached the end of this post. You can now use Angular Elements to:

  • Turn a regular Angular Component into a custom element
  • Compile that custom element so that it can be used in a standalone capacity
  • Communicate with custom elements with Inputs and Events
  • Insert the Angular Component into other JavaScript libraries such as React and Vue, make it communicate with the Angular Component
  • Build multiple custom standalone element in a single Angular Project

With this, you have reached the end of Part 2 of this series on Angular Elements. If you haven’t already, then check out Part 1 here:

Thank you for reading this really, really long post. I hope it helped you understand how to use Angular Elements in your Angular applications. Please feel free to comment here or hit me up on Twitter if you have any thoughts to share with me! Cheers 🍺

--

--