-
Notifications
You must be signed in to change notification settings - Fork 21
How to build and use aurelia kendoui plugin
The internal organization of this plugin is slightly different (we believe that it is more convenient) than Aurelia's standard plugin.
The following three sections describe the details of the plugin structure and building process
The plugin's src
folder contains the common
subfolder with utilities used by more than one KendoUI controls "wrapped" by this plugin. The class events.js
for example handles the creation of "fake" input events that need to be created in order to allow Aurelia to handle the jQuery raised events. If this sounds confusing, please check the blog jquery-ui datepicker with Aurelia by Jeremy Danyow
function createEvent(name) {
var event = document.createEvent('Event');
event.initEvent(name, true, true);
return event;
}
export function fireEvent(element, name) {
var event = createEvent(name);
element.dispatchEvent(event);
}
In addition to the just described utility of the common
folder, the src
folder contains a subfolder for each of the KendoUI control that is wrapped (componentized) by this plugin. The above screenshot indicates that the current version of the plugin wraps KendoUI autocomplete and button controls:
import {customAttribute, bindable, bindingMode, inject} from 'aurelia-framework';
import {fireEvent} from '../common/events';
import {pruneOptions} from '../common/options';
import $ from 'jquery';
import 'kendo-ui/src/js/kendo.autocomplete';
@customAttribute('au-kendo-autocomplete')
//@bindable({ name: 'value', changeHandler: 'valueChanged', defaultValue: [], defaultBindingMode: bindingMode.twoWay })
//@bindable({ name: 'data', changeHandler: 'dataChanged', defaultValue: [], defaultBindingMode: bindingMode.oneWay })
//@bindable({ name: 'options', changeHandler: 'optionsChanged', defaultValue: {}, defaultBindingMode: bindingMode.oneWay })
//@bindable({ name: 'class', defaultValue: '', defaultBindingMode: bindingMode.oneWay })
@inject(Element)
export class AuKendoAutoComplete {
element;
// Autocomplete API
// Full options object if you want to set options that way
@bindable options = {};
// Individual properties - default values need setting
@bindable animation;
@bindable dataSource;
@bindable dataTextField = null;
@bindable delay = 200;
@bindable enable = true;
@bindable filter = "startswith";
@bindable fixedGroupTemplate;
@bindable groupTemplate;
@bindable height;
@bindable highlightFirst;
@bindable ignoreCase;
@bindable minLength;
@bindable placeholder;
@bindable popup;
@bindable separator = "";
@bindable suggest = true;
@bindable headerTemplate;
@bindable template;
@bindable valuePrimitive;
@bindable virtual;
// Aurelia value-added API
@bindable value;
constructor(element) {
this.element = element;
}
bind() {
this._component = $(this.element).kendoAutoComplete(this.getOptions()).data("kendoAutoComplete");
this._component.bind('change', (event) => {
this.value = event.sender.value();
// Update the kendo binding
fireEvent(this.element, 'input');
});
this._component.bind('select', (event) => {
this.value = event.sender.value();
// Update the kendo binding
fireEvent(this.element, 'input');
});
}
detached() {
this._component.destroy();
}
getOptions() {
var options = pruneOptions({
animation: this.animation,
dataSource: this.dataSource,
dataTextField: this.dataTextField,
delay: this.delay,
enable: this.enable,
filter: this.filter,
fixedGroupTemplate: this.fixedGroupTemplate,
groupTemplate: this.groupTemplate,
height: this.height,
highlightFirst: this.highlightFirst,
ignoreCase: this.ignoreCase,
minLength: this.minLength,
placeholder: this.placeholder,
popup: this.popup,
separator: this.separator,
suggest: this.suggest,
headerTemplate: this.headerTemplate,
template: this.template,
valuePrimitive: this.valuePrimitive,
virtual: this.virtual
});
return Object.assign({}, this.options, options);
}
enableChanged(newValue) {
if (this._component)
this._component.enable(newValue);
}
}
import {customAttribute, bindable, inject} from 'aurelia-framework';
import {pruneOptions} from '../common/options';
import $ from 'jquery';
import 'kendo-ui/src/js/kendo.button';
@customAttribute('au-kendo-button')
@inject(Element)
export class AuKendoButton {
_component;
@bindable enable = true;
@bindable icon;
@bindable imageUrl;
@bindable spriteCssClass;
@bindable options;
constructor(element) {
this.element = element;
this.options = {};
}
bind() {
this._component = $(this.element).kendoButton(this.getOptions()).data('kendoButton');
}
detached() {
if(this._component)
this._component.destroy();
}
getOptions() {
var options = pruneOptions({
icon: this.icon,
enable: this.enable,
imageUrl: this.imageUrl,
spriteCssClass: this.spriteCssClass
});
return Object.assign({}, this.options, options);
}
enableChanged(newValue) {
if(this._component)
this._component.enable(newValue);
}
}
This file declares the resources (KendoUI wrapped controls) that this plugin exports - with the intent to provide them to the plugin consumer (sample application residing in the sample
folder) as API.
// TODO: Do we import the common styles here or let the user do it in their app?
import 'kendo-ui/src/styles/web/kendo.common.core.css!';
export function configure(aurelia){
var resources = [
'button/button',
'autocomplete/autocomplete'
];
aurelia.globalResources(resources);
}
Note: the intent to consume the exports from the above presented file index.js
is declared in the sample/src/main.js
class:
...
aurelia.use
.standardConfiguration()
.developmentLogging()
.plugin('aurelia-kendoui-plugin');
...
##### Color codes: - **yellow**: application runtime - created by running the **`jspm install`** command in the **`aurelia-kendoui-plugin/sample`** folder - **orange**: KendoUI controls hosted by this sample app (these controls are the consumers of the Aurelia-KendoUI-plugin) - **bluish**: Standard Aurelia application files collection - **olive**: Standard Aurelia application configuration/ css / html / js files
At this point it makes a lot of sense to stop looking at all details and go back to a very high level view of this "combo" (plugin and consuming app in the same project).
In the standard situation - like the case with Aurelia-Skeleton-Navigation app, the application's bootstraping process starts in the index.html
file by loading the two generated files:
In our specific case, the index.html
is constructed differently - as shown on the following screen shot:
This "dynamically constructed" instance of the system.js class allows this sample to use the name of the plugin as specified in the package.json file rather than depending on the more static specification of the plugin name that would have to exist in jspm directory or in github - like the case with defining the access to kendo-ui-core module:
"telerik/kendo-ui-core": "github:telerik/kendo-ui-core@^2015.3.930"
which is defined here