Create custom element in angular 6

1) Create Angular Project

ng new <project name> --prefix custom --style=scss --skip-tests

2) Use schematics to add angular element support

ng add @angular/elements

3) Use angular-cli to generate new component and specify encapsulation is ViewEncapsulation.Native

4) REmove the document-create-element polyfill from script array.

5) Install custom-lements polyfill, “@webcomponents/custom-elements”

yarn add @webcomponents/custom-elements

6) Update polyfills.ts to include native-shim polyfill

// Shim for Browsers supporting Custom Elements
// Needed b/c Custom Elements ist defined for ES6+
// while we are downleveling to ES5.
import "@webcomponents/custom-elements/src/native-shim.js";

7) Include custom elements in entryComponents array of module

  1. @NgModule({
  2.   imports: [CommonModule, HttpClientModule, FormsModule, NgbModule],
  3.   declarations: [
  4.     InputTimeFormComponent,
  5.     InputThemeComponent,
  6.     ...
  7.   ],
  8.   entryComponents: [InputTimeFormComponent, InputThemeComponent],
  9.   exports: [InputTimeFormComponent, InputThemeComponent]
  10. })
  11. export class TimeZoneModule {}

8) Assume the custom element uses Bootstrap 4 for styling. Then, import Bootstrap Sass in scss file of the component.

$icon-font-path: "../../../../node_modules/bootstrap-sass/assets/fonts/bootstrap/";
@import "~bootstrap/scss/bootstrap";

6) AppModule does not bootstrap or declare AppComponent. It also defines ngDoBoostrap function to register custom elements in custom element registry. createCustomElement creates custom element class based on Angular Component and define function of customElements registers the new custom element class.

  1. import { BrowserModule } from "@angular/platform-browser";
  2. import { NgModule, Injector } from "@angular/core";
  3. import { FormsModule } from "@angular/forms";
  4. import { HttpClientModule } from "@angular/common/http";
  5. import { createCustomElement } from "@angular/elements";
  6.  
  7. import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
  8. import {
  9.   InputTimeFormComponent,
  10.   TimeZoneModule,
  11.   InputThemeComponent
  12. } from "./time-zone/";
  13.  
  14. @NgModule({
  15.   imports: [
  16.     BrowserModule,
  17.     FormsModule,
  18.     HttpClientModule,
  19.     NgbModule.forRoot(),
  20.     TimeZoneModule
  21.   ]
  22. })
  23. export class AppModule {
  24.   constructor(private injector: Injector) {}
  25.  
  26.   ngDoBootstrap() {
  27.     console.log("AppModule ngDoBootstrap");
  28.     const timeConverterElement = createCustomElement(InputTimeFormComponent, {
  29.       injector: this.injector
  30.     });
  31.     const timeThemeElement = createCustomElement(InputThemeComponent, {
  32.       injector: this.injector
  33.     });
  34.     customElements.define("time-converter", timeConverterElement);
  35.     customElements.define("time-theme", timeThemeElement);
  36.   }
  37. }

9) After AppModule is bootstrapped in main.ts, optionally assigns value to attribute of custom element

  1. platformBrowserDynamic()
  2.   .bootstrapModule(AppModule)
  3.   .then(() => {
  4.     const color = 'goldenrod';
  5.     const themeChooser = document.getElementsByTagName("time-theme")[0];
  6.     themeChooser.setAttribute("theme", color);
  7.  
  8.     const converter = document.getElementsByTagName("time-converter")[0];
  9.     converter.setAttribute("theme", color);
  10.   })
  11.   .catch(err => console.log(err));

8) Build a nodeJS script to concatenate runtime.js, polyfill.js, script.js, main.js into time-converter.js. The time-converter.js can be used in other JS Frameworks and static website.

  1.  
  2. const fs = require("fs-extra");
  3. const concat = require("concat");
  4. (async function build() {
  5.   const files = [
  6.     "./dist/ng-time-converter/runtime.js",
  7.     "./dist/ng-time-converter/polyfills.js",
  8.     "./dist/ng-time-converter/scripts.js",
  9.     "./dist/ng-time-converter/main.js"
  10.   ];
  11.   await fs.ensureDir("elements");
  12.   await fs.emptyDir("elements");
  13.   await concat(files, "elements/time-converter.js");
  14.   await fs.copyFile(
  15.     "./dist/ng-time-converter/styles.css",
  16.     "elements/styles.css"
  17.   );
  18.   await fs.copy("./dist/ng-time-converter/assets/", "elements/assets/");
  19.   await fs.copyFile("./src/demo.html", "elements/index.html");
  20.   await fs.copyFile("CNAME", "elements/CNAME");
  21. })();

Articles I want to read

Tensorflow

https://towardsdatascience.com/how-to-build-a-gesture-controlled-web-based-game-using-tensorflow-object-detection-api-587fb7e0f907

Ngrx

https://medium.com/@bo.vandersteene/advanced-pagination-with-ngrx-store-and-angular-5-f26ca4761cef
https://medium.com/@vlado.tesanovic/handling-keyboard-shortcuts-in-angular-with-redux-ngrx-c88907f17ca8

Angular
https://blog.angularindepth.com/angular-ivy-change-detection-execution-are-you-prepared-ab68d4231f2c
https://medium.com/frontend-coach/self-or-optional-host-the-visual-guide-to-angular-di-decorators-73fbbb5c8658
https://medium.com/@davidibl/advanced-reusable-custom-angular-validator-9ca5febef583
https://malcoded.com/posts/web-assembly-angular?utm_source=mybridge&utm_medium=blog&utm_campaign=read_more

JS
https://blog.logrocket.com/using-trampolines-to-manage-large-recursive-loops-in-javascript-d8c9db095ae3

React Native
https://medium.freecodecamp.org/after-building-my-first-react-native-app-im-now-convinced-it-s-the-future-d3c5e74f8fa8

Projects built in May, 2018

Vue

CSS Grid

Angular

Angular Reactive Form Articles

Angular Reactive Form

Reactive Forms Form Array Dynamic Fields
https://alligator.io/angular/reactive-forms-formarray-dynamic-fields/

Angular Reactive Form
https://angular.io/guide/reactive-forms
Reactive Form (Stackblitz)

Angular 2 Reactive Form
https://toddmotto.com/angular-2-forms-reactive

REACTIVE FORMS IN ANGULAR
https://blog.thoughtram.io/angular/2016/06/22/model-driven-forms-in-angular-2.html

Reactive Form and Formarrayname
https://github.com/railsstudent/dnd

Build dynamic reactive form
https://juristr.com/blog/2017/10/demystify-dynamic-angular-forms/

Projects built in April, 2018

Angular 5

Build a Todo App with Angular 5 and Ngrx 5. Ngrx 5 is an open source state management library powered by RxJS.
So far, I used ngrx/store to define a store that stores todo, course and instructor entities. Ngrx entity generates entity state that is an object with mandatory ids and entities properties. As their names implied, ids hold an array of object ids and entities is a mapping of id to object. If you want the entity state to have custom attributes, they are initialized in getInitialState function of Adapter class.

Adapter.getInitialState({
loading: false
});

Ngrx effect, on the other hand, observes some actions, causes side effects and returns the result actions to reducer function. Reducer function accepts the result action, processes the payload and updates the store with new state. Ngrx effect class is a good candidate to make HTTP requests to backend, extract response data, construct payload and provide resultant action.

Furthermore, todo and learnings are designed as lazy loaded modules to reduce initial load time and they only get loaded when navigating to route of the module.

Projects built in March, 2018