Mix and Match: Angular + Custom Elements (Polymer)
In my previous post — Polymer 3.0 Preview — Building a mini card game, We use Polymer 3.0 Preview to create custom elements for our mini card game.
Since Angular plays well with custom elements (as mention in https://custom-elements-everywhere.com/, 100% tests passed), let’s try to mix them together!
I would also like to take this opportunity to introduce awesome Angular to my Polymer friends too. :)
Please note that:-
Custom elements ≠ Polymer
Custom elements is part of the web component spec, it is a capability for creating your own custom HTML. It is and will be part of the browser natively. Polymer is one of the tools that simplify the building of custom elements easier. There are many other ways to write custom elements. More explanation here: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements.
Here are the links for:
The Component Structure
Let’s look at our component structure:
We will create a new
app component in Angular, while reusing the other 4 Custom Elements (
my-pop-up-modal) we created with Polymer 3.0 Preview in previous post.
And here again, the overview of our components.
Setting up Project
Setting up project in Angular is as simple as ABC.
A. Install CLI globally
npm install @angular/cli -g
// or yarn
yarn global add @angular/cli
B. Creating a new project with CLI
ng new <your-project-name>
C. Start the project, see it live at http://localhost:4200.
// or yarn
Yes, it’s that simple. Angular CLI does all the miscellaneous tasks for you (of course, it’s always good to find out and learn what exactly it did, then you’ll appreciate more). It’s similar to Polymer CLI. Love all the CLIs! ❤
Including the Custom Elements
- Create a
- Include our custom elements file in the
Where is this file came from? It is from our previous post, it is the JS file generated when you run
yarn run build command ( in
dist folder, we rename it from
*in actual production environment, one should deploy that as a npm module and
npm install it accordingly.
3. Same as previous post, you need polyfills as not all browser fully support custom elements yet. We will be using
webcomponents-loader.js. Install this package:
// with npm
npm install @webcomponents/webcomponentsjs --save
// or yarn
yarn add @webcomponents/webcomponentsjs
4. Now, we have these two files in our project. We need to include these two files as part of the build. There are a few ways to do this. In Angular, the quickest way would be to include these file paths in
.angular-cli.json file, the
assets property like this:
"input": "./scripts", "output": "./scripts/"
With the above lines, Angular will picks these files and output to the
scripts folder after build.
5. Load them in our
index.html. Add these two lines:
<!-- index.html -->
Cool, we can use these custom elements now. Let’s move to our app component.
* In production however, one should create a file(e.g.
vendor.ts) to import all custom elements instead of include it in script tag.
App component template
Let’s take a look at our
app.component.html. Here is the code:
compare to Polymer template in previous post:
No big differences right?
All 4 HTML tags above are the custom elements we created using Polymer earlier. Let’s go thought some important notes here (especially if you are from Polymer).
- In Angular, we call custom element a component, therefore, you will see I use the term “custom element” and “component” interchangeably.
- In Polymer, custom event in template must start with on-*. This is not the case in Angular. For example, in Polymer we handle the
on-reset-clicked. In Angular, we can directly bind that with
reset-clicked. We use bracket for Angular event binding, e.g.
- In Polymer event handler MUST be function name only, without bracket (e.g.
resetGame). In Angular, it’s the opposite. It has to be
- For property binding, Angular user
. For example, we bind the top message component’s
time(we call it ‘input’ in Angular) to
currentTimevariable by using
- The conditional statement looks simpler in Angular. Look at the pop up modal, Angular use
*ngIf. You might feel weird with the
*here. Allow me explain a little bit further here:
In Polymer, you will need to write this long code for conditional statement:
<template is="dom-if" if="...">
You can definitely write something similar in Angular:
Rest assure that the above syntax is a valid Angular conditional syntax, and will work exactly as expected.
However, even better, Angular gives you a shortcut
*ngIf, it is a
syntactic sugar, so you can achieve the same result with less complicated syntax.
Isn’t that cool? Angular provide a pretty detail explanation on the * syntax here. Check it out.
App component TS
Next, look at our component code:
The code logic is exactly same as the
app component in my previous post. Just copy pasted it over. With a few things to note here :
In Polymer, a
custom element must be a class. We create a new element by extending the
In Angular, a component is a class as well. However, you don’t need to extend from any base class, simply use the
@Component class decorator to mark it as Angular component.
* Decorator is currently in stage 2 TC39 https://tc39.github.io/proposal-decorators/
Template, styling and name
When defining the template in Polymer, you need to override the
template getter, css live in template as well. The custom element name must be in kebab case. One assign element’s name by override the
is getter or do it during
In Angular, template can be either inline or external file. You can do it by configure the metadata object in
@Component class decorator,
templateUrl property. In our case, we are using external template.
Component name in Angular can be either kebab case
my-component or camel case
myComponent. We define the name in metadata
Styling in Angular component can be done both inline or by external files as well. You can configure that with
styles metadata property. Since we are using Angular CLI, SCSS and LESS are supported out of the box.
Angular CLI also provide an easy way to generate new component by running
ng generate component <your-component-name>. Pretty handy.
Polymer has lifecycle hooks, so does Angular. The closest lifecycle to Polymer
ready would be Angular
ngOnInit. Read the full list of Angular lifecycle events is here.
Nice. We are almost there. Left the ONE LAST STEP.
Allowing custom elements
Refreshing your page now, you should see a blank page. Look at the console, you will get a long list of errors:
Why? It’s because:
my-top-baris not a Angular component, no
@Componentclass created for that.
my-top-baris a custom element that we have. Angular doesn’t know about that. Therefore, we need to tell Angular that “Hey, it’s ok, I know what I am doing, I have some custom elements that you don’t know, stop throw me error please”)
app.module.ts file, add in these lines:
More explanation about schema here: https://angular.io/api/core/NgModule#schemas
Great. Refresh your browser again, everything should work like a charm.
That’s it. Happy coding!
Here are the links for: