Write Once, Use Everywhere

- Angular Elements

@pankajparkar

Angular

React

Vue

Aurelia

preact

.
.
.

Pankaj Parkar

Technical Lead

Synerzip Softech India PVT LTD

  • Microsoft MVP

  • Opensource Contributor

  • Stackoverflow Topuser for Angular and AngularJS

  • 100k+ reps on Stackoverflow

  • .Net and Angular Developer

  • Currently working on React, GraphQL & Nodejs

@pankajparkar

Angular is ideal for building complete applications

Rob Wormald, Angular Team

But it becomes challenging for scenarios that don't fit in Single Page Application Model

@pankajparkar

Challenges

  1. Reusability of code (cross platform)

  2. Enhance existing application & CMS pages

  3. Embed Widgets inside another app

@pankajparkar

Running Angular on Mixed environment

  • AngularJS
  • React
  • Polymer 
  • jQuery
  • Aurelia
  • Vue
  • Vanilla JS
  • etc..

@pankajparkar

Angular components are tough to use outside Angular

Rob Wormald, Angular Team

Why you want to use Angular outside?

@pankajparkar

Why you want to use Angular outside? ctd..

@pankajparkar

Ecosystem

Can we use something that follow Web Standards and address our issue?

Web Component

@pankajparkar

Before moving further, lets flashback

@pankajparkar

HTML 1

HTML 2

(1990)

INPUT   FORM  SELECT

@pankajparkar

BODY   A  H2   IMG   UL   LI

(1995)

HTML 5

@pankajparkar

INPUT    FORM    SELECT

BUTTON   VIDEO   AUDIO

DIALOG   CANVAS   TEXTAREA

DATALIST   IMG   PROGRESS

Input had 8 types when it got introduced

Now input have 22 types

Unix

@pankajparkar

(1970)

ls

lpr

cat

grep

sort

chmod

echo

alias

less

more

head

who

time

find

tail

echo

kill

mkdir

pwd

ps

.
.

Do One Thing and Do It Well

Unix Philosophy

source: https://en.wikipedia.org/wiki/Unix_philosophy

  • Write programs that do one thing and do it well.
  • Write programs to work together.
  • Write programs to handle text streams, because that is a universal interface.
  • Output of one program should become input for other.

Web Component

  1. Template
  2. Shadow DOM
  3. Html Imports
  4. Custom Elements

@pankajparkar

Web Components are a set of features currently being added by the W3C to the HTML and DOM specifications that allow for the creation of reusable widgets or components in web documents and web applications.

Specs

1. Template

<template id="content">
  <h1>Hello World!</h1>
  <img src="success.jpg" />
  <script> 
    //some big javascript 
  </script>
</template>
var content = document.getElementById('content');
var div = document.createElement('div');
var clone = document.importNode(template.content, true);
document.body.appendChild(div);

@pankajparkar

We have similar technique, that used inside `ng-template`

2. Shadow DOM

<body>
  <div>
    <#shadow-root>
      <h1 class=”title”></h1>
    </shadow-root>
  </div>
</body>

We can do this for component using encapsulation set to Native.

@pankajparkar

<body>
    <div>Hello, World!</div>
    <script>
      var host = document.querySelector(‘div’);
      var root = host.createShadowRoot();
      root.textContent = ‘Hello, Treehouse!’;
    </script>
</body>

3. HTML Imports

<head>
   <link 
    rel="import" 
    href="my-widget.html" />
</head>

This spec is deprecated, this is not going to implement by browsers.

@pankajparkar

4. Custom Element

<body>
  <my-navbar></my-navbar>
  <div class="content">
    <my-sidebar></my-sidebar>
    <my-main-content></my-main-content> 
  </div>
  <my-footer></my-footer>
</body>

@pankajparkar

Custom Element

  • Standard way of defining web component
  • Extend the browser vocabulary

Custom element should have dash used in their name, they can't be single word

@pankajparkar

Web Component Support

@pankajparkar

Custom Elements

class FancyDatePicker extends HTMLElement {}

window.customElements
  .define(‘fancy-datepicker’, FancyDatePicker);

@pankajparkar

It has below native DOM objects

  1. Attributes

  2. Events

  3. Properties

  4. Method

@pankajparkar

Custom Elements - Attributes

class FancyDatePicker extends HTMLElement {

  static observedAttributes = [‘current-date’];

  attributeChangedCallback(oldV, newV, key){
    //update the DOM somehow
  }
}
<fancy-datepicker 
  current-date=”10/10/2017”>
</fancy-datepicker>
const picker = document.querySelector(‘fancy-datepicker’);
picker.setAttribute(‘current-date’, new Date().toString());

Declarative

Imperative

@pankajparkar

Custom Elements - Properties

class FancyDatePicker extends HTMLElement {

  set currentDate(value){
    //update the DOM
  }

  get currentDate(){ … }  
}
const fancyDatePicker = 
    document.querySelector(‘fancy-datepicker’);
fancyDatePicker.currentDate = new Date();

@pankajparkar

Custom Elements - Event

const picker = document.querySelector(‘fancy-datepicker’);

const onDateChange = (date) => console.log(date);
picker.addEventListener(‘date-change’, onDateChange);

@pankajparkar

Custom Elements - Method

class FancyDatePicker extends HTMLElement {
  emitDateChange(details){
    let dateChangeEv = 
       new CustomEvent(‘date-change’,{details});
    this.dispatchEvent(dateChangeEv);
  } 
}
const fancyDatePicker = 
     document.querySelector(‘fancy-datepicker’);
fancyDatePicker.emitDateChange();

@pankajparkar

Custom Elements - Reactions /Lifecycle Hooks

class FancyDatePicker extends HTMLElement {

  connectedCallback(){ … }

  disconnectedCallback(){ … }

  attributeChangedCallback(oldV, newV, key){ … }

  adoptedCallback(){ … }

}

@pankajparkar

Web Component works out of the box in Angular, it supports by design

<my-angular-app>
  <facy-datepicker
    [attr.currentDate]=”currentDate”
    [placement]=”placement”
    (dateChanged)=”dateChanged($event)”>
   </my-input>
</my-angular-app>

Angular with Web Component

@pankajparkar

Then why not use Web Components?

Text

https://developers.google.com/web/fundamentals/web-components/examples/howto-checkbox

Source: http://pascalprecht.github.io/slides/angular-elements/#/14

@pankajparkar

Angular API looks similar to CE

NG

CE

@HostBindings

@Input

@Output

@Lifecycle Hooks

Attributes

Properties

CustomEvent

Reactions

@pankajparkar

@pankajparkar

Angular Elements

Angular Elements

  • Export Angular Components as custom-element that can re-usable on any application
  • Self bootstrapping
  • Follow current web standard
  • Now zone is optional since Angular version 5

Angular Component packaged as web component

@pankajparkar

web-component

Angular Component

Even other guys are doing it

SkateJS

@pankajparkar

How to setup Angular elements

// app.module.ts
import { HelloWorldComponent } from './hello-world';

export const CEComponents = [HelloWorldComponent];

@NgModule({
  imports: [BrowserModule],
  declarations: CEComponents,
  //all custom-element should be here
  entryComponents: CEComponents
})
export class CustomElementsModule {
  ngDoBootstrap() {} // required in bootstrap module
}

@pankajparkar

import { NgModule, Injector } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { createCustomElement } from '@angular/elements';
import { FancyDatepickerComponent } from './fancy-date-picker/fancy-date-picker.component';
@NgModule({
  declarations: [FancyDatepickerComponent],
  imports: [BrowserModule],
  entryComponents: [FancyDatepickerComponent]
})
export class AppModule { 
  constructor(private injector: Injector)
  ngDoBootstrap(app){
    let currentElement = createCustomElement(
       FancyDatepickerComponent, {
       injector: this.injector
    });
    customElements.define('vote-cmp', currentElement)
  }
}

1

2

In Future it could be simpler

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'fancy-datepicker',
  templateUrl: './fancy-datepicker.html',
  styleUrls: ['./fancy-datepicker.css'],
  customElement: true
})
export class FancyDatepickerComponent implements OnInit {

  constructor(){}

  ngOnInit() {}

}
export class FancyDatepickerComponent {

  static ngElementDef = defineElementDef({ ... })

}

Ivy Output

Usage

<fancy-datepicker
  currentDate="21-07-2018">
</fancy-datepicker>

Declarative

Imperative

var fancyDatepicker = 
    docuement.createElement('fancy-datepicker')
fancyDatepicker.currentDate = '21-07-2018'; // set date

// Change date function call
fancyDatepicker.dateChanged('21-07-2018')

Content Projection

Manual Injector

let fancyDatepciker = customElements.get('fancy-datepicker')
let newElemenent = new fancyDatepciker(this);
<fancy-datepicker currentDate="21-07-2018">
  <div>
    My Project / Transcluded Content
  </div>
</fancy-datepicker>

How it look in general

<html>
  <head>
    ...
    ...
    <script src="my-customelement.bundle.js"></script>
    ...
  </head>
  <body>
    ...
    <my-ng-component></my-ng-component>
    ...
  </body>
</html>

@pankajparkar

Where is it heading?

<html>
  <head>
    ...
    ...
    <script src="angular-mini.js"></script>
    <script src="my-custom-element.bundles.js"></script>
    ...
  </head>
  <body>
    ...
    <my-ng-component></my-ng-component>
    ...
  </body>
</html>

@pankajparkar

jQuery datepicker

Jquery dialog modal example

<html>
  <head>
    ...
    ...
    <script src="jquery.js"></script>
    <script src="jquery.datepicker.js"></script>
    ...
  </head>
  <body>
    ...
    <input id="my-datepicker" />
    <script type="javascript">
       $('#my-datepicker').datePicker({
         format: 'dd-MM-yyyy'
       })
    </script>
    ...
  </body>
</html>

@pankajparkar

Demo Time

  • Angular with CE Component - Demo
  • ReactJS - Demo
  • VueJS - Demo

@pankajparkar

With ZoneJS Without ZoneJS
Bundle Size 213kb 199kb
Bundle Size 71kb 58kb

Future

Angular Ivy Renderer (beta) +

Angular Elements

@pankajparkar

@pankajparkar

https://bit.ly/write-once-use-everywhere

Q & A

References

  • https://blog.angular.io/the-angular-team-at-angularmix-2d56fd7fde65

  • https://github.com/angular/angular/issues/21706

  • http://slides.com/andreiantal/ng-europe_angular-elements#/33

  • http://slides.com/andreiantal/ng-europe_angular-elements#/3

  • https://github.com/andrei-antal/ng-europe-demo-angular-elements (Thanks Andrei Antal)

  • https://github.com/pankajparkar/ng-india-angular-elements-demo

  • https://github.com/pankajparkar/ng-india-vueapp

  • https://github.com/pankajparkar/ng-india-reactapp

  • https://medium.com/@ezekizibzibadze/angular-and-web-components-a-k-a-angular-elements-e009b057cd75

  • https://en.wikipedia.org/wiki/Unix_philosophy

web-component

Angular Component

Write once, use everywhere - Angular Elements

By Pankaj Parkar

Write once, use everywhere - Angular Elements

Angular Elements for using Angular outside Angular.

  • 1,069