Projects built in July, 2018

Angular

Vanilla JS, SCSS, HTML

Import bootstrap, ng-bootstrap and font-awesome in angular app

1) yarn add bootstrap @ng-bootstrap/ng-bootstrap font-awesome

yarn add bootstrap @ng-bootstrap/ng-bootstrap font-awesome

2) In style.scss, import bootstrap and font-awesome

  1. @import "~bootstrap/scss/bootstrap";
  2. $fa-font-path : '../node_modules/font-awesome/fonts';
  3. @import "~font-awesome/scss/font-awesome";

4) type ng serve to launch application in development mode. Index page should open at url http://localhost:4200.

ng serve

How to build webcomponentjs v0 polyfill and include in angular

1) git clone https://github.com/webcomponents/webcomponentsjs repository
2) check out v0 branch
3) install gulp globally

  1. npm install -g gulp

4) build webcomponentjs manually

  1.  npm install
  2.  gulp build

5) Find the generate js files in dist/ folder
6) Copy webcomponents.min.js to assets folder of angular project
7) import webcomponents.min.js to polyfill.ts

  1. import "./assets/webcomponents.min";

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. })();