Web Components - Custom Elements in Angular

JS
R
JavaScript

Angular Elements - Custom Element API (Web Components) A web component is basically a re-usable, cross-browser, encapsulated HTML Tag which is framework independent (runs anywhere). There is a browser API to create Web Component. Angular brings it on the board with `Custom Elements` Angular Custom Element, allows us to create or own Element. Underneath it just creates an ES6 Class and registers the component in the Browsers' Web Component API. This post is based on ngConf 04/18: Elements in v6 and Beyond - Rob Wormald https://www.youtube.com/watch?v=Z1gLFPLVJjY&t=4s https://angular.io/guide/elements https://www.webcomponents.org/community/articles/web-components-best-practices

1// Good Realworld example: https://github.com/angular/angular/tree/master/aio/src/app
2// https://next.angular.io/
3// Is the host element
4@Component({
5  selector: 'funny-component',
6  template: `
7  <h1> Hello </h1>
8  <input type="text" [(ngModel)]="name">
9  <button (click)="onChangeName()"> Save </button>
10  `;
11})
12
13@class FunnyComponent {
14  @Input() name: string;
15  @Output() nameChange = new EventEmitter();
16  onChangeName() {
17    this.nameChange.emit(this.name);
18  }
19
20  constructor(el: ElementRef) {
21    console.log(el.nativeElement); // Angular element
22  }
23
24  @HostListener('click')
25  onHostClick($event){}
26
27  @HostBinding('attr.selected')
28  isActive: boolean;
29}
30
31
32// Module
33import { NgModule } from '@angular/core';
34import { BrowserModule } from '@angular/platform-browser';
35
36@NgModule({
37  imports: [],
38  declarations: [],
39  entryComponents: []
40})
41
42class FunnyModule {
43  // start the module but not the component
44  ngDoBootstrap();
45}
46
47// Platform Browser w/ custom elements
48import { createCustomElement } from '@angular/elements';
49import { FunnyComponent } from './funny-component';
50platformBrowser()
51  .bootstrapModuleFactory(FunnyModuleFactory)
52  .then(({injector}) => {
53    // ES6 generic component
54    const funnyElement = createCustomElement(FunnyComponent, {injector})
55    customElements.define('funny-component', funnyElement);
56  });
57
58
59// Usage
60const funnyComponentElement = document.createEkement('funny-component');
61document.body.appendChild(funnyComponentElement);
62funnyComponentElement.name = 'coderecipes';
63funnyComponentElement.addEventListemer('onChangeName', (evt) => {
64  //..
65});
66
67<funny-component> </funny-component>
68
69
70/* Dependency Injection
71  1- Platform Injector (Renderer, Sanitizer)
72  2- Module Injector (Services)
73  3- Component Injector (ChangeDetector)
74*/
75const recoverMyComponent = customElements.get('funny-component');
76const myComponent = new FunnyComponent(funnyInjector);
77
78// Shadow DOM - View Encapsulation
79// To use shadowDom, please set view
80
81
82
83// Folder Structure
84.
85├── angular.json
86├── package.json
87├── projects/
88│   └── library1/
89│       ├── CHANGELOG.md
90│       ├── package.json
91│       ├── src/
92│       │   ├── elements/
93│       │   │   ├── environments/
94│       │   │   │   ├── environment.prod.ts
95│       │   │   │   └── environment.ts
96│       │   │   ├── index.html
97│       │   │   ├── index.ts
98│       │   │   ├── main.ts
99│       │   │   ├── polyfills.ts
100│       │   │   ├── library1.module.ts
101│       │   │   └── public_api.ts
102│       │   ├── index.ts
103│       │   ├── lib/
104│       │   │   ├── index.ts
105│       │   │   ├── my-component/
106│       │   │   └── library1.module.ts
107│       │   └── public_api.ts
108│       ├── tsconfig.elements.json
109│       └── tsconfig.lib.json
110├── src/
111│   ├── app/
112│   ├── environments/
113│   ├── index.html
114│   ├── main.ts
115│   └── tsconfig.app.json
116└── tsconfig.json

Created on 2/26/2019