Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Creating GUI Component APIs in Angular and Web Components

Creating GUI Component APIs in Angular and Web Components

So you’ve embraced architecting your Angular application with reusable components – cheers to you! But you have UI components that need to communicate with each other or expose public methods, and you’re wondering about your options. In this talk, we’ll cover how new web component standards, like Custom Elements, handle this. Next, we’ll walk through how to accomplish it today in Angular 1.x – and bring it all together into what a solution will look like in upcoming Angular 2. Afterwards, you'll know how to design and implement the public HTML and JavaScript interfaces of GUI components.

Talk presented at Angular Connect in October 2015.

Rachael L Moore

October 20, 2015
Tweet

More Decks by Rachael L Moore

Other Decks in Technology

Transcript

  1. Rachael L Moore Sr UI Engineer OpenTable morewry Creating GUI

    Component APIs in Angular and Web Components (speaker notes included) Kara Erickson Software Engineer OpenTable kara | karaforthewin Angular Connect 20 & 21 October 2015 ExCel London London, UK
  2. Periodic Table of HTML Elements style script cite samp sup

    ruby bdo code pre li dd textarea button progress h6 details tfoot device video audio track canvas iframe source param object embed map area img link noscript q var sub mark kbd wbr figure ul dt input output keygen h5 article summary thead base rp abbr time b strong del br figcaption ol dl label option datalist h4 nav command tbody title a meter select aside h2 section caption td meta rt dfn em i small ins hr p div blockquote legend optgroup address h3 header menu th head span fieldset form body h1 colgroup tr html col table footer
  3. Periodic Table of HTML Elements style script cite samp sup

    ruby bdo code pre li dd textarea button progress h6 details tfoot device video audio track canvas iframe source param object embed map area img link noscript q var sub mark kbd wbr figure ul dt input output keygen h5 article summary thead base rp abbr time b strong del br figcaption ol dl label option datalist h4 nav command tbody title a meter select aside h2 section caption td meta rt dfn em i small ins hr p div blockquote legend optgroup address h3 header menu th head span fieldset form body h1 colgroup tr html col table footer canvas
  4. Standard Elements - DOM Interfaces var select = $("select")[0]; <select>

    <option>Opt 1</option> </select> Standard Elements - DOM Interfaces
  5. var select = $("select")[0]; select.options select.options.length // 1 Standard Elements

    - DOM Interfaces <select> <option>Opt 1</option> </select> Standard Elements - DOM Interfaces
  6. var select = $("select")[0]; select.options select.options.length // 1 Standard Elements

    - DOM Interfaces <select> <option>Opt 1</option> </select> Standard Elements - DOM Interfaces
  7. <select> <option>Opt 1</option> <option>Opt 2</option> </select> Standard Elements - DOM

    Interfaces var select = $("select")[0]; select.add( new Option("Opt 2") ); Standard Elements - DOM Interfaces
  8. <select> <option>Opt 1</option> <option>Opt 2</option> </select> Standard Elements - DOM

    Interfaces var select = $("select")[0]; select.add( new Option("Opt 2") ); Standard Elements - DOM Interfaces
  9. <*> <ng-transclude> <select> <option>... <custom-element> // HTMLElement // HTMLUnknownElement //

    HTMLSelectElement // HTMLOptionElement // WHATEVER I WANT! Elements - DOM Interfaces Elements - DOM Interfaces
  10. <*> <ng-transclude> <select> <option>... <custom-element> // HTMLElement // HTMLUnknownElement //

    HTMLSelectElement // HTMLOptionElement // WHATEVER I WANT! Elements - DOM Interfaces Elements - DOM Interfaces
  11. <*> <ng-transclude> <select> <option>... <custom-element> // HTMLElement // HTMLUnknownElement //

    HTMLSelectElement // HTMLOptionElement // WHATEVER I WANT! Elements - DOM Interfaces Elements - DOM Interfaces
  12. <*> <ng-transclude> <select> <option>... <custom-element> // HTMLElement // HTMLUnknownElement //

    HTMLSelectElement // HTMLOptionElement // WHATEVER I WANT! Elements - DOM Interfaces Elements - DOM Interfaces
  13. <*> <ng-transclude> <select> <option>... <custom-element> // HTMLElement // HTMLUnknownElement //

    HTMLSelectElement // HTMLOptionElement // WHATEVER I WANT! Elements - DOM Interfaces Elements - DOM Interfaces
  14. Requirements - open modal.confirm() <modal /> modal.open() Modal Opens -

    Pseudocode Request Confirmation Confirmation Modal Modal Opens
  15. Requirements - content modal.confirm() <modal> <!-- custom --> </modal> modal.open()

    Custom Modal Content - Pseudocode Request Confirmation Confirmation Modal Modal Opens Custom Modal Content
  16. Requirements - multiple 2 modal.confirm() <modal> <!-- custom --> </modal>

    modal.open() Multiple Modals - Pseudocode Request Confirmation Confirmation Modal Modal Opens Custom Modal Content Multiple Modals
  17. Requirements - close modal.confirm() <modal> <!-- custom --> </modal> modal.open()

    modal.close() Modal Closes - Pseudocode Request Confirmation Confirmation Modal Modal Opens Custom Modal Content Multiple Modals Modal Closes
  18. Requirements - proceed modal.confirm() <modal> <!-- custom --> </modal> modal.open()

    modal.close() modal.proceed() Proceed Afterwards - Pseudocode Request Confirmation Confirmation Modal Modal Opens Custom Modal Content Multiple Modals Modal Closes Proceed Afterwards
  19. Requirements - callback modal.confirm(callback) <modal> <!-- custom --> </modal> modal.open()

    modal.close() modal.proceed() Proceed Afterwards - Pseudocode Request Confirmation Confirmation Modal Modal Opens Custom Modal Content Multiple Modals Modal Closes Proceed Afterwards
  20. Confirmation Modal Template - <div id="modal"> <div id="overlay"></div> <section id="dialog">

    <svg id="x"></svg> <button id="cancel"> Cancel </button> <button id="confirm"> Confirm </button> </section> </div> Confirmation Modal Template -
  21. <div id="modal"> <div id="overlay"></div> <section id="dialog"> <svg id="x"></svg> <button id="cancel">

    Cancel </button> <button id="confirm"> Confirm </button> </section> </div> Confirmation Modal Template - Confirmation Modal Template -
  22. <div id="modal"> <div id="overlay"></div> <section id="dialog"> <svg id="x"></svg> <button id="cancel">

    Cancel </button> <button id="confirm"> Confirm </button> </section> </div> Confirmation Modal Template - Confirmation Modal Template -
  23. <div id="modal"> <div id="overlay"></div> <section id="dialog"> <svg id="x"></svg> <button id="cancel">

    Cancel </button> <button id="confirm"> Confirm </button> </section> </div> Confirmation Modal Template - Confirmation Modal Template -
  24. <div id="modal"> <div id="overlay"></div> <section id="dialog"> <svg id="x"></svg> <button id="cancel">

    Cancel </button> <button id="confirm"> Confirm </button> </section> </div> Confirmation Modal Template - Confirmation Modal Template -
  25. <div id="modal"> <div id="overlay"></div> <section id="dialog"> <svg id="x"></svg> <button id="cancel">

    Cancel </button> <button id="confirm"> Confirm </button> </section> </div> Confirmation Modal Template - Confirmation Modal Template -
  26. <div id="modal"> <div id="overlay"></div> <section id="dialog"> <svg id="x"></svg> <button id="cancel">

    Cancel </button> <button id="confirm"> Confirm </button> </section> </div> Confirmation Modal Template - Confirmation Modal Template -
  27. class OTConfirmModalElement extends HTMLElement { ... createdCallback () { //

    see Content Container talk from ng-conf  } }; ng-conf - OTConfirmModal.js
  28. class OTConfirmModalElement extends HTMLElement { ... open () {} close

    () {} }; open & close methods - OTConfirmModal.js
  29. class OTConfirmModalElement extends HTMLElement { ... open () { this.hidden

    = false; } close () { this.hidden = true; } }; hidden property - OTConfirmModal.js
  30. <ot-confirm-modal hidden> ... </ot-confirm-modal> OTConfirmModal.js - hidden attribute ...extends HTMLElement

    { ... open () { this.hidden = false; } close () { this.hidden = true; } }; OTConfirmModal.js - hidden attribute
  31. class OTConfirmModalElement extends HTMLElement { ... confirm (callback) { this.onProceed

    = callback; this.open(); } }; confirm - OTConfirmModal.js
  32. class OTConfirmModalElement extends HTMLElement { createdCallback open close confirm (callback)

    proceed }; Angular-Connect-2015  Pseudocode Summary - OTConfirmModal.js
  33. <ot-confirm-modal id="block"> Blocking will prevent diners from making reservations online.

    </ot-confirm-modal> Tag - Integration with Application - index.html
  34. Summary - Integration with Application - index.html <ot-confirm-modal id="block"> Blocking

    will prevent diners from making reservations online. </ot-confirm-modal> $("#block")[0].confirm(blockReservations);
  35. Declarative custom tag Imperative access to API <ot-confirm-modal id="id"> Are

    you sure? </ot-confirm-modal> $("#id")[0].confirm(cb); Custom Elements Custom elements
  36. Declarative custom tag Imperative access to API <ot-confirm-modal id="id"> Are

    you sure? </ot-confirm-modal> $("#id")[0].confirm(cb); Custom Elements Custom elements
  37. Declarative custom tag Imperative access to API <ot-confirm-modal id="id"> Are

    you sure? </ot-confirm-modal> $("#id")[0].confirm(cb); Custom Elements Custom elements
  38. Angular 1 Custom elements <ot-confirm-modal id="id"> Are you sure? </ot-confirm-modal>

    // Declarative custom tag $("#id")[0].confirm(cb); // Flexible imperative API <ot-confirm-modal id="id"> Are you sure? </ot-confirm-modal> // ?
  39. $rootScope AppController trigger modal "confirm-" + modal Confirmation Modal -

    Scope tree "confirm-" + this.id $rootScope.$emit $rootScope.$on
  40. Angular 1 Custom elements <ot-confirm-modal id="id"> Are you sure? </ot-confirm-modal>

    // Declarative custom tag $("#id")[0].confirm(cb); // Flexible imperative API <ot-confirm-modal id="id"> Are you sure? </ot-confirm-modal> $rootScope.$emit("confirm-id")
  41. Angular 1 Custom elements <ot-confirm-modal id="id"> Are you sure? </ot-confirm-modal>

    // Declarative custom tag $("#id")[0].confirm(cb); // Flexible imperative API <ot-confirm-modal id="id"> Are you sure? </ot-confirm-modal> $rootScope.$emit("confirm-id") // or <button on-confirm="cb()" ot-confirm-with="id">
  42. Angular 1 Custom elements <ot-confirm-modal id="id"> Are you sure? </ot-confirm-modal>

    // Declarative custom tag $("#id")[0].confirm(cb); // Flexible imperative API
  43. Angular 1 <ot-confirm-required> <button ot-on-confirm /> <ot-confirm-modal> Are you sure?

    </ot-confirm-modal> </ot-confirm-required> require: "^otConfirmModal", link: (s, e, a, ctrl) => { ctrl.confirm(cb); } Custom elements <ot-confirm-modal id="id"> Are you sure? </ot-confirm-modal> // Declarative custom tag $("#id")[0].confirm(cb); // Flexible imperative API
  44. open: 1. get modal template 2. compile the modal manually

    $compile(template)(scope) index.html Toggling the modal <button ng-click="confirm()"> Block </button>
  45. open: 1. get modal template 2. compile the modal manually

    index.html Toggling the modal <button ng-click="confirm()"> Block </button> <!-- <ot-confirm-modal> Custom content here. </ot-confirm-modal> -->
  46. open: 1. get modal template 2. compile the modal manually

    3. add custom content index.html Toggling the modal <button ng-click="confirm()"> Block </button> /* confirmModal.confirm({ callback: this.block, template: "feature.html" }) */
  47. open: 1. get modal template 2. compile the modal manually

    3. add custom content 4. append to DOM index.html Toggling the modal <button ng-click="confirm()"> Block </button>
  48. open: 1. get modal template 2. compile the modal manually

    3. add custom content 4. append to DOM close: index.html Toggling the modal <button ng-click="confirm()"> Block </button>
  49. open: 1. get modal template 2. compile the modal manually

    3. add custom content 4. append to DOM close: 1. remove element 2. destroy scope index.html Toggling the modal <button ng-click="confirm()"> Block </button>
  50. Angular 1 Custom elements <ot-confirm-modal id="id"> Are you sure? </ot-confirm-modal>

    // Declarative custom tag $("#id")[0].confirm(cb); // Flexible imperative API // modal.html confirmModal.confirm({ callback: block, template: "modal.html" }); <button on-confirm="block()" ot-confirm-with="modal.html">
  51. @Component({ selector: "ot-confirm-modal", template: ` <div class="modal" [hidden]="!isOpen"> <ng-content></ng-content> <button>Cancel</button>

    <button>Confirm</button> </div> <div class="overlay" [hidden]="!isOpen"></div>` }) class OtConfirmModal {} Angular 2
  52. @Component({ selector: "ot-confirm-modal", template: ` <div class="modal" [hidden]="!isOpen"> <ng-content></ng-content> <button

    (click)="close()">Cancel</button> <button>Confirm</button> </div> <div class="overlay" [hidden]="!isOpen" (click)="close()"></div>` }) class OtConfirmModal {} Angular 2
  53. @Component({ selector: "ot-confirm-modal", template: ` <div class="modal" [hidden]="!isOpen"> <ng-content></ng-content> <button

    (click)="close()">Cancel</button> <button (click)="proceed()">Confirm</button> </div> <div class="overlay" [hidden]="!isOpen" (click)="close()"></div>` }) class OtConfirmModal {} Angular 2
  54. @Component({...}) class OtConfirmModal { isOpen: boolean = false; open() {

    this.isOpen = true; } close() { this.isOpen = false; } } Angular 2
  55. @Component({...}) class OtConfirmModal { isOpen: boolean = false; open() {

    this.isOpen = true; } close() { this.isOpen = false; } proceed() { this.onProceed(); this.close(); } confirm(callback) { this.onProceed = callback; this.open(); } Angular 2 ...
  56. @Component({ selector: "app", template: ` <button (click)="">Block</button> <ot-confirm-modal> Are you

    sure? </ot-confirm-modal>`, directives: [OtConfirmModal] }) class App {} app.ts
  57. Local variables Angular 2 Strategies var-a #a <input #a (keyup)>

    <p> {{ a.value }} </p> <ot-confirm-modal #main> //  main OtConfirmModal instance Pseudocode
  58. @Component({ selector: "app", template: ` <button (click)="">Block</button> <ot-confirm-modal> Are you

    sure? </ot-confirm-modal>`, directives: [OtConfirmModal] }) class App {} app.ts
  59. @Component({ selector: "app", template: ` <button (click)="">Block</button> <ot-confirm-modal #main> Are

    you sure? </ot-confirm-modal>`, directives: [OtConfirmModal] }) class App {} app.ts
  60. @Component({ selector: "app", template: ` <button (click)="main.confirm(block)">Block</button> <ot-confirm-modal #main> Custom

    content here. </ot-confirm-modal>`, directives: [OtConfirmModal] }) class App {...} app.ts
  61. @Component({ selector: "app", template: ` <button (click)="main.confirm(block)">Block</button> <ot-confirm-modal #main> Custom

    content here. </ot-confirm-modal>`, directives: [OtConfirmModal] }) class App {...} app.ts
  62. Angular 2 <ot-confirm-modal #id> Are you sure? </ot-confirm-modal> id.confirm(cb); Custom

    elements <ot-confirm-modal id="id"> Are you sure? </ot-confirm-modal> // Declarative custom tag $("#id")[0].confirm(cb); // Flexible imperative API
  63. @Component({ selector: "app", template: ` <button (click)="main.confirm(block)"> Block </button> <ot-confirm-modal

    #main> Custom content here. </ot-confirm-modal>`, directives: [OtConfirmModal] }) ... app.ts
  64. @Component({ selector: "app", template: ` <button [confirm-with]="main" (confirm)="block()"> Block </button>

    <ot-confirm-modal #main> Custom content here. </ot-confirm-modal>`, directives: [OtConfirmModal] }) ... app.ts
  65. @Directive({ selector: "[ot-confirm-with]" }) class OtConfirmWith { @Input("ot-confirm-with") modal: OtConfirmModal;

    @HostListener("click") requestConfirm() { this.modal.confirm(); } } Angular 2 $element.on("click", requestConfirm)
  66. @Directive({ selector: "[ot-confirm-with]" }) class OtConfirmWith { @Input("ot-confirm-with") modal: OtConfirmModal;

    @Output() confirm: EventEmitter = new EventEmitter(); @HostListener("click") requestConfirm() { this.modal.confirm(); } } Angular 2
  67. @Directive({ selector: "[ot-confirm-with]" }) class OtConfirmWith { @Input("ot-confirm-with") modal: OtConfirmModal;

    @Output() confirm: EventEmitter = new EventEmitter(); @HostListener("click") requestConfirm() { this.modal.confirm(); } emitConfirmEvent() { this.confirm.next(); } Angular 2 ...
  68. @Directive({ selector: "[ot-confirm-with]" }) class OtConfirmWith { @Input("ot-confirm-with") modal: OtConfirmModal;

    @Output() confirm: EventEmitter = new EventEmitter(); @HostListener("click") requestConfirm() { this.modal.confirm(this.emitConfirmEvent.bind(this)); } emitConfirmEvent() { this.confirm.next(); } Angular 2 ...
  69. @Directive({ selector: "[ot-confirm-with]" }) class OtConfirmWith { @Input("ot-confirm-with") modal: OtConfirmModal;

    @Output() confirm: EventEmitter = new EventEmitter(); @HostListener("click") requestConfirm() { this.modal.confirm(this.emitConfirmEvent.bind(this)); } emitConfirmEvent() { this.confirm.next(); } } Angular 2
  70. Thanks OpenTable, Sara Rahimian, Simon Attley, Guest Center Web team

    Links Creating Container Components talk Custom Element Examples Angular Examples Photos Gratisography & Unsplash All photos public domain. Thanks OpenTable, Sara Rahimian, Simon Attley, Guest Center Web team Links Creating Container Components talk Custom Element Examples Angular Examples Photos Gratisography & Unsplash All 3rd party photos public domain.
  71. OpenTable is hiring! We’re hiring! Visit our careers page at

    opentable.com/careers/ We’re hiring! Visit our careers page at opentable.com/careers/