Angular 2 Can Do Kendo Too!

Michael K. Snead

msnead@paylocity.com

Angular2Kendo:

Topic of Discussion

  • Create an Angular 2.0 Component
  • ...without a custom element
  • Injecting the native DOM element
  • Hooking up to the Angular 2.0 lifecycle
  • Create/destroy/update kendo widgets
  • Render Component children

Integrating frameworks isn't actually that hard...

Building with Angular 2: Tools

  • Visual Studio 2015
    (Web Storm 11 is 'da bomb' though!)
  • WebPack
    (module loader/bundler)
  • Babel
    (transpile)

Bundle.js

A single entry-point (usually 'app.js') begins the tree of dependencies, which node-based webpack includes in the bundle.

Babel converts ES-next (ES6+) to ES-today

'import' statements become CommonJS 'require' that node.js understands

ES*

ES*

ES*

CJS

CJS

CJS

Create A Component

import { Component, View } from 'angular2/angular2';

/* Using this element would be something like ...
    template: `
        <div>Hey, this is a cool app!</div>
        <div><kendocomponent widgetname="Foo!"></kendocomponent></div>
    `
*/

@Component({
    selector: 'kendocomponent',
    inputs: ['widgetname'],
    //outputs: [...], <- if we had events, like our own 'onChange'
})
@View({ template: '<span>You told me it was {{widgetname}}</span>' })
export class KendoComponent { }

No custom element

import { Component, View } from 'angular2/angular2';

/* Using this element would be something like ...
    template: `
        <div>Hey, this is a cool app!</div>
        <div><p data-role="kendocomponent" widgetname="Foo!"></p></div>
    `
*/

@Component({
    selector: '[data-role=kendocomponent]',
    inputs: ['widgetname'],
    //outputs: [...], <- if we had events, like our own 'onChange'
})
@View({ template: '<span>You told me it was {{widgetname}}</span>' })
export class KendoComponent { }

Inject native DOM element

import { Component, View, ElementRef } from 'angular2/angular2';

@Component({
    selector: '[data-role=kendocomponent]',
    inputs: ['widgetname']
})
@View({ template: '<span>You told me it was {{widgetname}}</span>' })
export class KendoComponent {
    static get parameters() {
        return [[ElementRef]];
    }
    constructor(elementRef) {
        var domElement = elementRef.nativeElement;
        $(domElement).attr('style', 'background-color: blue;');
    }
}

Hook up lifecycle

import { Component, View, ElementRef } from 'angular2/angular2';

@Component({
    selector: '[data-role=kendocomponent]',
    inputs: ['widgetname'],
    bindings: [ElementRef]
})
@View({ template: '<span>You told me it was {{widgetname}}</span>' })
export class KendoComponent {
    static get parameters() {
        return [[ElementRef]];
    } 
    constructor(elementRef) {
        // Fires one time when component instantiated
        console.log("Hey, I'm constructed! widgetname is", this.widgetname);
        var domElement = elementRef.nativeElement;
        $(domElement).attr('style', 'background-color: blue;');
    }
    onInit() {
        // Fires one time at the beginning
        console.log("Hey, I'm initialized! widgetname is", this.widgetname);
    }
    onChanges(changes) {
        // Fires once in the beginning and whenever bindings are updated
        console.log("Hey, I'm changing! widgetname is", this.widgetname);
    }
    onDestroy() {
        // Fired when the component is to be disposed of
        console.log("Hey, I'm being destroyed! It's quite painful ...");
    }
}

CRUD the Kendo Widget

import { Component, View, ElementRef } from 'angular2/angular2';

@Component({
  selector: '[data-role=kendocomponent]',
  inputs: ['widgetname', 'bound'], // we want a new binding to send arguments to kendo
  bindings: [ElementRef]
})
@View({ template: '' }) //We want an empty template, kendo will fill it
export class KendoComponent {
  static get parameters() {
    return [[ElementRef]];
  } 
  constructor(elementRef) {
    this.domElement = elementRef.nativeElement;
    this.initialized = false;
  }
  onInit() {}
  onChanges(changes) {
    if(!this.initialized) { this.init(); this.initialized = true; }
    if(changes.bound) { //if the 'bound' binding changed...
      $(this.domElement).data('kendo' + this.widgetname).value(changes.bound.currentValue.value);
    }
  }
  init() {
    $(this.domElement)['kendo' + this.widgetname](this.bound);
  }
  onDestroy() {
    $(this.domElement).data('kendo' + this.widgetname).destroy();
    $(this.domElement).empty();
  }
}

Render children

import { Component, View, ElementRef } from 'angular2/angular2';

@Component({
  selector: '[data-role=kendocomponent]',
  inputs: ['widgetname', 'bound'], // we want a new binding to send arguments to kendo
  bindings: [ElementRef]
})
@View({ template: '<ng-content></ng-content>' }) //Tell Angular 2 to render children
export class KendoComponent {
  static get parameters() {
    return [[ElementRef]];
  } 
  constructor(elementRef) {
    this.domElement = elementRef.nativeElement;
    this.initialized = false;
  }
  onInit() {}
  onChanges(changes) {
    if(!this.initialized) { this.init(); this.initialized = true; }
    if(changes.bound) { //if the 'bound' binding changed...
      $(this.domElement).data('kendo' + this.widgetname).value(changes.bound.currentValue.value);
    }
  }
  init() {
    $(this.domElement)['kendo' + this.widgetname](this.bound);
  }
  onDestroy() {
    $(this.domElement).data('kendo' + this.widgetname).destroy();
    $(this.domElement).empty();
  }
}

Next steps...

  • Make bound properties dynamic
  • Make specific components + selectors for each Kendo widget
    (ie: DatePicker, DropDownList, Grid, Editor)
  • etc...

Further reading ...

Get to know...

ECMAScript 6 and 7 (ES2015, ES2016)
What browsers support ES6 and ES7?
https://kangax.github.io/compat-table/es6/
ES6 Features
https://github.com/lukehoban/es6features
Try ES-next in your browser
https://babeljs.io/repl/
ECMAScript 6 - New Features: Overview & Comparison
http://es6-features.org/

Taming the asynchronous beast with ES7
http://pouchdb.com/2015/03/05/taming-the-async-beast-with-es7.html
JavaScript Decorators
https://github.com/wycats/javascript-decorators
ECMAScript 6 modules: the final syntax
http://www.2ality.com/2014/09/es6-modules-final.html

Questions?

Thanks for your time.

Angular 2 Can Do Kendo Too

By Michael Snead

Angular 2 Can Do Kendo Too

Illustrate how to create Angular 2 components that wrap Kendo UI widgets.

  • 5,418