Aurelia

Aurelia and Kendo UI

Introduction

Aurelia

Aurelia


Aurelia and Kendo UI

Posted by Aurelia on .
Featured

Aurelia and Kendo UI

Posted by Aurelia on .

Today, I'm really excited to introduce to you three innovative community members: Nikolaj Ivancic, Charles Pockert and Jeroen Vinke. They've been working together to create native Aurelia components for the Kendo UI suite, as well as a number of other tools for "bridging" the gap between existing component libraries and Aurelia. I asked them to put together a blog post that we could share with you here, announcing and explaining their work. Read on to learn more about the Aurelia UI Toolkits project.


Introduction

This article describes the motivation for, the work on and the structure of the project we named a bridge (Image 1 below) to indicate its primary purpose: to create the interface (an alternative word for a bridge in this context) for Aurelia application developers to KendoUI toolkit.

Image 1

This bridge is a structured, configurable collection of JavaScript classes that "wrap" KendoUI native controls, presenting them to the Aurelia developer in the form of Aurelia components.

We started with the Aurelia standard plugin setup as the skeleton for our bridge application, carefully reviewed all KendoUI controls and decided to present KendoUI to Aurelia Developers in the form of the KendoUI Components Catalog. This catalog is an Aurelia application skilfully created to serve several important roles:

  • During the bridge development process it allows the bridge developer to immediately verify the correct function of the "wrapper" code which presents the KendoUI native control as an Aurelia component.

  • It continuously shares the status of the project by providing rich navigation support demonstrating several different ways of using each component to render KendoUI controls (see image 2 below)

Image 2

  • By adding the extensive online help pages with installation instructions, several tutorials and samples, this catalog can be used as a teaching tool (Image 3 below):

Image 3


Why Aurelia?

Aurelia is a next generation UI framework. Whether you're building apps for the browser, mobile or desktop, Aurelia can enable you to not only create amazing UI, but do it in a way that is maintainable, testable and extensible.

Aurelia is just JavaScript. However, it's not yesterday's JavaScript, but the JavaScript of tomorrow. By using modern tooling we've been able to write Aurelia from the ground up in ECMAScript 2016. This means we have native modules, classes, decorators and more at our disposal...and you have them too.

Not only is Aurelia written in modern and future JavaScript, but it also takes a modern approach to architecture. In the past, frameworks have been monolithic beasts. Not Aurelia though. It's built as a series of collaborating libraries. Taken together, they form a powerful and robust framework for building Single Page Apps (SPAs). However, Aurelia's libraries can often be used individually, in traditional web sites or even on the server-side through technologies like NodeJS.

Aurelia is open source, but unlike much open source in the JavaScript space, Aurelia is an official product with commercial backing. If your business is going to spend significant money building software, you want to do it on a platform that's committed to you as a customer. You want to be able to form a relationship with your technology provider to ensure that you and your developers have a solid platform upon which to build your business now and in the years to come.

Why KendoUI?

Kendo UI is an HTML5 user interface framework for building interactive and high-performance websites and applications. The framework comes with a library of 70+ UI widgets, an abundance of data-visualization gadgets, client-side data source, built-in MVVM (Model-View-ViewModel) library. Kendo UI provides AngularJS, Bootstrap - and soon Aurelia integration.

Kendo UI Professional is one of the commercial versions of Kendo UI. It is a comprehensive framework providing 70+ Kendo UI widgets, and includes a simple and consistent programming interface, a rock-solid DataSource, out-of-the-box themes, an MVVM framework, and more. Kendo UI Professional includes widgets for enterprise-grade line-of-business applications and is suitable for creating professional websites that require expert and timely technical support.

Kendo UI Core is the free and open-source Kendo UI distribution, released under Apache v2.0 License. It provides access to a limited number of widgets and framework features, and to 1,000+ tests running across browsers for each commit to the Kendo UI Core GitHub repository. Kendo UI Core is suitable for open-source or commercial projects that do not require complex UI, such as Grid, Chart, etc., nor dedicated technical support. Kendo UI Core does not offer dedicated technical support.

How did this project start?

  • (Charles:) I wanted a grid for a project rapidly prototyped in Aurelia. There's no reason why I couldn't pick up Kendo now and start using it in my project. In fact, Kendo even supports MVVM scenarios using observables that are built into the Kendo framework. However, these mechanisms do not integrate with Aurelia without the help of some plugin interface. You would need to use jQuery selectors to find your target element and initialize your widgets in JavaScript.
  • (Jeroen): I used Kendo controls in a rather large ERP application (built on top of Aurelia) and noticed the large amount of code it took to instantiate even a simple Kendo control. I first created a couple of wrappers for these controls myself but then noticed that Charles was doing this as well. Charles and I wanted to team up and create this plugin but never really took the initiative until Nikolaj brought us together.
  • (Nik) some 8 years ago, I wrote a complex Silverlight application using KendoUI as the user interface toolkit. Naturally once I discovered Aurelia and decided that this where I'd stay for a long time, my first move was to find out the means of getting hold of KendoUI in this new context.

Motivations behind this project.

All three developers (Charles, Jeroen and Nik) discovered Aurelia the same way: after getting disappointed with the slow pace of evolution of Angular we all got excited hearing the news that Rob Eisenberg of Caliburn Micro fame (which we all knew) is joining the Angular team. Then, after a pretty long wait for Angular 2.0, we got hold of two pieces of news: Angular 2.0 is not going to be what we hoped for and more importantly, Rob left the Angular team and announced Aurelia - which we recognized in a few days as the framework we all waited for.

The problem with Aurelia, however, was that it was very new. Don't get us wrong, the framework was impressive and really easy to work with, but it was lacking any out-of-the-box UI components. Rather than waiting to see someone else provide such UI components and having sufficiently good experience with KendoUI we decided to take a plunge and try to create a bridge that would make KendoUI controls shine as Aurelia Components.

Take the following example that briefly explains our intentions:

In the KendoUI native programming model, a Kendo grid layout is defined in the view-model (JavaScript):

$(element).kendoGrid({
 columns: [
   { field: "CustomerId", template: "Customer: ${ CustomerId }" },
   { field: "CustomerName", template: "${ CustomerName }" }
 ];
});

We wanted to express the same information as Aurelia components:

<k-grid>  
  <k-col field="CustomerId">Customer: ${ CustomerId }</k-col>
  <k-col field="CustomerName">${ CustomerName }</k-col>
</k-grid>  

This latter approach is more declarative and easier to visualize / understand. It also sits in the correct place in the MV* model -- and all these improvements are the consequences of using Aurelia's powerful binding and templating features.

Some interesting problems we encountered.

Repetitive Code

After implementing the first few wrappers, we started to see a pattern emerge. Our code contained a lot of @bindable property declarations in order to expose Kendo's API to Aurelia's binding system:

export class Grid {

  @children('k-col') columns;

  @bindable autoBind = true;
  @bindable columnMenu;
  @bindable dataSource;
  @bindable editable;
  @bindable filterable;
  @bindable group;
  // .. and more

That wasn't all - our wrappers also contained what we called "event proxies" which delegate events raised by the Kendo control. Before the optimizations, we had to write an event proxy for every event in every wrapper:

cancel: (e) => fireKendoEvent(this.element, 'cancel', e),
change: (e) => fireKendoEvent(this.element, 'change', e),
columnHide: (e) => fireKendoEvent(this.element, 'column-hide', e),
columnLock: (e) => fireKendoEvent(this.element, 'column-lock', e),
columnUnlock: (e) => fireKendoEvent(this.element, 'column-unlock', e),
columnMenuInit: (e) => fireKendoEvent(this.element, 'column-menu-init', e),
columnReorder: (e) => fireKendoEvent(this.element, 'column-reorder', e),
columnResize: (e) => fireKendoEvent(this.element, 'column-resize', e),
// .. and more

It's safe to say that this was not optimal. If we missed an event or the Kendo API changed we would need to issue a new version of the plugin.

A more robust approach was necessary.

Fortunately, the KendoUI source contains a list of properties from which we can generate part of the wrapper implementation:

Image 4

This gives us all possible properties and their default values for each KendoUI control.

Because Aurelia is open source, we were able to take a peek into the implementation of the @bindable decorator, and create a [@generateBindables](
https://github.com/aurelia-ui-toolkits/aurelia-kendoui-bridge/blob/343767e7fe5e484e80d1541a28e7a8e75f52cf70/src/common/decorators.js#L11-L37) decorator. This makes the code much cleaner:

@customElement('k-grid')
@generateBindables('kendoGrid')
@inject(Element, WidgetBase)
export class Grid  {  
  @children('k-col') columns;
  @bindable options = {};

The event proxies mentioned earlier are also generated, reducing the size of our codebase even more and ensuring that the plugin is resilient to future API changes.

Inheritance

In order to extract some common logic between these wrappers, we started with a WidgetBase super class. This worked fine for a while, until we wanted to create a @bindable property on the WidgetBase to expose certain properties.

This caused some very strange behavior - Aurelia doesn't yet support @bindable decorators on super classes.

In addition, it became increasingly difficult to unit test.

The current implementation uses a composition based approach. WidgetBase still exists as a property on each wrapper, encapsulating any common functionality.

Template Compilation

One of the nicest features of this plugin has got to be the ability to use Aurelia templates in Kendo controls. We got some help from Telerik on how to approach this, and found that we could leverage the angular hook that Kendo controls call whenever they want to have a DOM element compiled.

After we got that tip from Telerik, we began to search for a way to compile DOM elements (which the angular hook provides us) with Aurelia. We found Aurelia's enhance capability to be a great fit.

When we had gathered all the information about the angular hook and Aurelia's enhance capability, it was not difficult to write a template-compiler. The template-compiler's responsibility is to compile DOM elements whenever a Kendo control asks for it. As every Kendo control calls this hook, Aurelia templates can now be used wherever you can supply a template.

File collisions in the dist folder

Every plugin has a dist folder that contains the transpiled code that is downloaded by the users of a plugin, so it is absolutely necessary to have this dist folder in the Git repository.

The files in this dist folder are generated with the gulp build command, which is used a lot during development. The format and content of the dist folder can differ per machine. Different versions of gulp/npm can cause the content of these files to be different, even when the source is the same.

Whenever someone pushed a change to the dist folder, the other developers were getting file collisions when they tried to pull the changes in. This happened quite often and got quite annoying.

After a while we started to look for alternatives. We first tried to add the dist folder to the .gitignore file, but this didn't work out as we still needed to have the dist folder in the Git repository. Then we decided to not push any changes to the dist folder by excluding these files from any commit. This was not ideal because we sometimes wanted to push these changes in order to test the plugin in a seperate application.

Then we came up with the idea to create two different gulp build commands: one for development and one for releasing. One command builds to the dist directory and the other builds to a dev directory which we added to the .gitignore file. Problem solved!

Moving ahead

This current Alpha (0.1.0) release is provided as a "pre-anouncement" of the Beta version that will follow next, where we already offer several interesting features:

Feature 1

In order to help Aurelia Application developers get a solid understanding of what we did and how to use this Bridge, we packaged it as a relatively sophisticated Aurelia application, described as an amalgamation of two standard Aurelia repositories: Skeleton Navigation and Skeleton Plugin. For the user's convenience, we are providing the Bridge hosted in GitHub in the form of Aurelia KendoUI components catalog. Each of the Aurelia components in that catalog (note that Aurelia component means the native KendoUI control wrapped in this bridge's plugin) illustrates several different examples showing how to use that component by showing the actual view, view model and eventual "local" css file. Here are the code snippets for Grid components:

view

<template>  
    <require from="./basic-use.css"></require>

   <k-grid k-data-source.bind="datasource" k-pageable.bind="pageable" k-sortable.bind="true">
      <k-col title="Contact Name" field="ContactName">
        <div class='customer-photo' style="background-image: url(http://demos.telerik.com/kendo-ui/content/web/Customers/${CustomerID}.jpg);"></div>
        <div class='customer-name'>${ContactName}</div>
      </k-col>
      <k-col title="Contact Name" field="ContactName"></k-col>
      <k-col title="Contact Title" field="ContactTitle"></k-col>
      <k-col title="Company Name" field="CompanyName"></k-col>
      <k-col field="Country"></k-col>
    </k-grid>
</template>  

view model

export class BasicUse {

  pageable = {
    refresh: true,
    pageSizes: true,
    buttonCount: 10
  };

  constructor() {
    this.datasource = {
      type: 'odata',
      transport: {
        read: '//demos.telerik.com/kendo-ui/service/Northwind.svc/Customers'
      },
      pageSize: 5
    };
  }
}

style.css

.customer-photo {
    display: inline-block;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background-size: 32px 35px;
    background-position: center center;
    vertical-align: middle;
    line-height: 32px;
    box-shadow: inset 0 0 1px #999, inset 0 0 10px rgba(0,0,0,.2);
    margin-left: 5px;
}

.customer-name {
    display: inline-block;
    vertical-align: middle;
    line-height: 32px;
    padding-left: 3px;
}
Feature 2

Besides the hope that many Aurelia application developers will use this Bridge, we also hope to get more Aurelia enthusiast to help finish this drive (here is the description of the process to do that). We already know that this description of how to contribute is necessary - but not nearly sufficient as we realized in the phase of creating the current Aurelia Tools team. The Bridge / Aurelia KendoUI components catalog help addresses this additional need, with Bridge developers tutorials and Bridge developers notes sections. All these documents are "live" in the sense that they will be always current with respect to the Bridge status (see the current status).

Feature 3

We took the same approach to creating this Bridge that is often encountered in building complex applications meant to run on a less capable OS - once the app is built, we look for everything that can be extracted to become the part of the OS. The most notorious example of such behavior is the very first instance of Word for Windows that was built on Microsoft's DOS.

As a result, we created a new project, skeleton bridge, which contains all "platform independent" infrastructure from an actual bridge. We have already proved the value of this tool (our experience transitioning from KendoUI bridge to Materialize bridge resulted in 5x "compression of time" as our team member @thanood happily reported).

The skeleton bridge is at very early stage of its evolution (check this article for more details) -- and its core is the plugin builder component, already used extensively in the KendoUI bridge here and here.

Editor's Remarks

Hats off to the great community efforts made by the Aurelia UI Toolkits team. They've managed to not only create Aurelia components for Kendo UI, but also to abstract infrastructure that will enable more easily integrating with other widget libraries in the future. They've even started work on others, such as MaterializeCSS. As I watched the project progress, I also became convinced of something else: Aurelia might well be the very best way to build Kendo UI applications today.

View Comments...