Integrating Polymer 3 Components on Angular 5, more simple…
Recently published an article about my experiments with Angular, Origami and Polymer 3, but it was not until few days ago that I understood a comment by Andrew Mitchell -author of Origami- a little better about not having to use the patch-cli for patch the Angular CLI for integration with Polymer 3, -he was on the correct way-. The starter project of Vaadin for Angular not patch the Angular CLI and use Polymer 3.
Reviewing the starter project of Vaadin for Angular (Vaadin-Angular) and my previous experiences in the integration I found some steps that differ with the previous integration solution:
- Vaadin-Angular project´s not include the webcomponents polyfills on the index.html -like Origami- else on polyfills.ts -like does Rob Dodson and Stephen Fluin in “Using Web Components in Angular”-.
- Vaadin-Angular project´s team use webcomponents-sd-ce.js not webcomponents-loader.js, this last more convenient because is used for load appropriated polyfills by browser, if were necessary.
Keeping these things in mind I made some changes on my test integration project and verified that, if I use the webcomponents-loader.js in polyfills.ts thrown error on Firefox because not are loaded the appropriated polyfills, in Chrome work because not need polyfills. On other hand, if I include the webcomponents-loader.js on index.html and previously move on runtime webcomponents-loader.js to Angular app root folder (src), its work.
In this sense, the proposed solution could be:
Load a certain polyfill for all browsers adding it to the polyfills.ts
Or
Modify the angular-cli.json for move in runtime the polyfills to the src and include the webcomponents-loader.js on index.html.
On other test, that second solution not work on Firefox, if Angular application is served with ng serve --prod
. Work with command for production, if use the command ng serve --prod --aot false
, other valid point for first solution despite of the load needless the polyfills for some browser as Chrome.
Updated June 8th, 2018
Note: The test above was realized with
@webcomponents/webcomponentsjs@1.1.0
. Recently realized this test with version2.0.0
and the web components was charged and working appropriately usingng serve --prod
. Although the Origami’s directives likeironControl
related with form’s directives like[(ngModel)]
not work. This, may be, could are related with the asynchronous charge of the polyfills.
The steps to achieve integration are quite similar to those specified in Origami and are describe below.
Integration
Analyzing the above elements the example of integration will be like:
Create an Angular CLI Project
Note: I proove this the example with Angular CLI 1.7.3 and 1.7.4
ng new [project-name]
Install Origami and WebComponents Polyfills
npm i --save @codebakery/origami @webcomponents/webcomponentsjs
Load the polyfills
In this step, you have two variants, you should use one or other:
- Load a certain polyfill for all browsers
Add in src/polyfills.ts
the following line:
src/polyfills.ts
/** Polyfill required for web components **/import '@webcomponents/webcomponentsjs/webcomponents-sd-ce.js';
Updated June 8th, 2018
Note: If use
@webcomponents/webcomponentsjs@2.0.0
, instead ofwebcomponents-sd-ce.js
you must usewebcomponents-bundle.js
- Move in runtime the polyfills under app root and include the webcomponents-loader.js on index.html.
Note: Remember this variant has trouble generating the Angular project for production with the current stable CLI.
Add the following line to assets array on the .agular-cli.json
:
.angular-cli.json
{"glob": "web*.js", "input": "../node_modules/@webcomponents/webcomponentsjs", "output": "./wc_polyfills/"}
Updated June 8th, 2018
Note: If use
@webcomponents/webcomponentsjs@2.0.0
, must add this other line to assets array:
{"glob": "web*.js", "input": "../node_modules/@webcomponents/webcomponentsjs/bundles", "output": "./wc_polyfills/bundles/"
In addition, add this line to the head of index.html
src/index.html
<script src="wc_polyfills/webcomponents-loader.js"></script>
Other steps are the same that are described in previous article from this point
Wait to bootstrap Angular until the polyfills are loaded
Modify your main.ts
and wait for the polyfills.
main.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { webcomponentsReady } from '@codebakery/origami';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';if (environment.production) {
enableProdMode();
}webcomponentsReady().then(() => {
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err));
});
Import Origami
Import Origami into your topmost root NgModule
. In any modules where you use Custom Elements, add CUSTOM_ELEMENTS_SCHEMA
to the module. This prevents the Angular compiler from emitting errors on unknown element tags.
app.module.ts
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { PolymerModule } from '@codebakery/origami';
import { AppComponent } from './app.component';@NgModule({
imports: [
BrowserModule,
FormsModule, // Origami requires the Angular Forms module
PolymerModule.forRoot() // Do not call .forRoot() when importing in child modules
],
declarations: [
AppComponent
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
bootstrap: [AppComponent]
})
export class AppModule { }
Install and use custom elements
Install elements! Persist them to package.json
with the --save
flag.
npm install --save @polymer/paper-checkbox@nextnpm install --save @polymer/paper-input@next
Note: The polymer components have the suffix @next, this is necessary for now because Polymer is still on preview.
Next, import the element in the Angular component that you want to use it in. Add the [ironControl]
directive to elements that use Angular form directives.
app.components.ts
import { Component } from '@angular/core';import '@polymer/paper-checkbox/paper-checkbox';
import '@polymer/paper-input/paper-input';@Component({
selector: 'app-root',
template: `
<paper-input label="Hello from Polymer" ironControl [(ngModel)]="value"></paper-input>
<paper-checkbox [checked]="checked" (checked-changed)="checked = $event.detail.value"></paper-checkbox>`
})
export class AppComponent {
value: string;
checked: boolean;
}
Run the application
Inside the Angular project execute the command ng serve
and validate that it work.
Good coding!!!
Final Note: This is one of three closely related articles. In chronological order they are: