Please ensure Javascript is enabled for purposes of website accessibility
Powered by Zoomin Software. For more details please contactZoomin

AVEVA™ Work Tasks

Knockout Bindings for Kendo UI

  • Last UpdatedMar 12, 2021
  • 12 minute read

/*

* knockout-kendo 0.8.1

* Copyright © 2013 Ryan Niemeyer & Telerik

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

* http://www.apache.org/licenses/LICENSE-2.0

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

(function (factory)

{

// CommonJS

if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object')

{

factory(require('knockout'), require('jquery'), require('kendo'));

// AMD

} else if (typeof define === 'function' && define.amd)

{

define(['knockout', 'jquery', 'kendo'], factory);

// Normal script tag

} else

{

factory(window.ko, window.jQuery, window.kendo);

}

}(function (ko, $, kendo, undefined)

{

//handle require.js scenarios where kendo is not actually returned

kendo = kendo || window.kendo;

ko.kendo = ko.kendo || {};

ko.kendo.BindingFactory = function ()

{

var self = this;

this.createBinding = function (widgetConfig)

{

//only support widgets that are available when this script runs

if (!$()[widgetConfig.parent || widgetConfig.name])

{

return;

}

var binding = {};

//the binding handler's init function

binding.init = function (element, valueAccessor, all, vm, context)

{

//step 1: build appropriate options for the widget from values passed in and global options

var options = self.buildOptions(widgetConfig, valueAccessor);

//apply async, so inner templates can finish content needed during widget initialization

if (options.async === true || (widgetConfig.async === true && options.async !== false))

{

setTimeout(function ()

{

binding.setup(element, options, context);

}, 0);

return;

}

binding.setup(element, options, context);

if (options && options.useKOTemplates)

{

return { controlsDescendantBindings: true };

}

};

//build the core logic for the init function

binding.setup = function (element, options, context)

{

var widget, $element = $(element);

//step 2: setup templates

self.setupTemplates(widgetConfig.templates, options, element, context);

////

//// Note:

//// Below fix is for the Data Grid firing dataBound Event Multiple Times on Load

//// Instead of adding watch, using data for setting the grid dataSource

//// Before the kendo grid widget is initialized, options.dataSource is set to options.data

////

//// ---- Code Added ----

if (options.useKOTemplates === true && options.data !== undefined)

{

options.dataSource = options.data;

}

//// ---- /Code Added ----

//step 3: initialize widget

widget = self.getWidget(widgetConfig, options, $element);

//step 4: add handlers for events that we need to react to for updating the model

self.handleEvents(options, widgetConfig, element, widget, context);

//step 5: set up computed observables to update the widget when observable model values change

self.watchValues(widget, options, widgetConfig, element);

//step 6: handle disposal, if there is a destroy method on the widget

if (widget.destroy)

{

ko.utils.domNodeDisposal.addDisposeCallback(element, function ()

{

widget.destroy();

});

}

};

binding.options = {}; //global options

binding.widgetConfig = widgetConfig; //expose the options to use in generating tests

ko.bindingHandlers[widgetConfig.bindingName || widgetConfig.name] = binding;

};

//combine options passed in binding with global options

this.buildOptions = function (widgetConfig, valueAccessor)

{

var defaultOption = widgetConfig.defaultOption,

options = ko.utils.extend({}, ko.bindingHandlers[widgetConfig.name].options),

valueOrOptions = ko.utils.unwrapObservable(valueAccessor());

if (valueOrOptions instanceof kendo.data.DataSource || typeof valueOrOptions !== "object" || valueOrOptions === null || (defaultOption && !(defaultOption in valueOrOptions)))

{

options[defaultOption] = valueAccessor();

} else

{

ko.utils.extend(options, valueOrOptions);

}

return options;

};

var templateRenderer = function (id, context)

{

return function (data)

{

return ko.renderTemplate(id, context.createChildContext((data._raw && data._raw()) || data));

};

};

//prepare templates, if the widget uses them

this.setupTemplates = function (templateConfig, options, element, context)

{

var i, j, option, existingHandler;

if (templateConfig && options && options.useKOTemplates)

{

//create a function to render each configured template

for (i = 0, j = templateConfig.length; i < j; i++)

{

option = templateConfig[i];

if (options[option])

{

options[option] = templateRenderer(options[option], context);

}

}

//initialize bindings in dataBound event

existingHandler = options.dataBound;

options.dataBound = function ()

{

ko.memoization.unmemoizeDomNodeAndDescendants(element);

if (existingHandler)

{

existingHandler.apply(this, arguments);

}

};

}

};

//unless the object is a kendo datasource, get a clean object with one level unwrapped

this.unwrapOneLevel = function (object)

{

var prop,

result = {};

if (object)

{

if (object instanceof kendo.data.DataSource)

{

result = object;

}

else if (typeof object === "object")

{

for (prop in object)

{

//include things on prototype

result[prop] = ko.utils.unwrapObservable(object[prop]);

}

}

}

return result;

};

//return the actual widget

this.getWidget = function (widgetConfig, options, $element)

{

var widget;

if (widgetConfig.parent)

{

//locate the actual widget

var parent = $element.closest("[data-bind*='" + widgetConfig.parent + ":']");

widget = parent.length ? parent.data(widgetConfig.parent) : null;

} else

{

widget = $element[widgetConfig.name](this.unwrapOneLevel(options)).data(widgetConfig.name);

}

//if the widget option was specified, then fill it with our widget

if (ko.isObservable(options.widget))

{

options.widget(widget);

}

return widget;

};

//respond to changes in the view model

this.watchValues = function (widget, options, widgetConfig, element)

{

var watchProp, watchValues = widgetConfig.watch;

if (watchValues)

{

for (watchProp in watchValues)

{

if (watchValues.hasOwnProperty(watchProp))

{

self.watchOneValue(watchProp, widget, options, widgetConfig, element);

}

}

}

};

this.watchOneValue = function (prop, widget, options, widgetConfig, element)

{

var computed = ko.computed({

read: function ()

{

var existing, custom,

action = widgetConfig.watch[prop],

value = ko.utils.unwrapObservable(options[prop]),

params = widgetConfig.parent ? [element] : []; //child bindings pass element first to APIs

//support passing multiple events like ["open", "close"]

if ($.isArray(action))

{

action = widget[value ? action[0] : action[1]];

} else if (typeof action === "string")

{

action = widget[action];

} else

{

custom = true; //running a custom function

}

if (action && options[prop] !== undefined)

{

if (!custom)

{

existing = action.apply(widget, params);

if (widgetConfig.name === "kendoColorPicker" && prop === "value" && !value)

{

value = "#1b1b1b";

}

params.push(value);

} else

{

params.push(value, options);

}

//try to avoid unnecessary updates when the new value matches the current value

if (custom || existing !== value)

{

action.apply(widget, params);

}

}

},

disposeWhenNodeIsRemoved: element

}).extend({ throttle: (options.throttle || options.throttle === 0) ? options.throttle : 1 });

//if option is not observable, then dispose up front after executing the logic once

if (!ko.isObservable(options[prop]))

{

computed.dispose();

}

};

//write changes to the widgets back to the model

this.handleEvents = function (options, widgetConfig, element, widget, context)

{

var prop, eventConfig, events = widgetConfig.events;

if (events)

{

for (prop in events)

{

if (events.hasOwnProperty(prop))

{

eventConfig = events[prop];

if (typeof eventConfig === "string")

{

eventConfig = { value: eventConfig, writeTo: eventConfig };

}

self.handleOneEvent(prop, eventConfig, options, element, widget, widgetConfig.childProp, context);

}

}

}

};

//bind to a single event

this.handleOneEvent = function (eventName, eventConfig, options, element, widget, childProp, context)

{

var handler = typeof eventConfig === "function" ? eventConfig : options[eventConfig.call];

//call a function defined directly in the binding definition, supply options that were passed to the binding

if (typeof eventConfig === "function")

{

handler = handler.bind(context.$data, options);

}

//use function passed in binding options as handler with normal KO args

else if (eventConfig.call && typeof options[eventConfig.call] === "function")

{

handler = options[eventConfig.call].bind(context.$data, context.$data);

}

//option is observable, determine what to write to it

else if (eventConfig.writeTo && ko.isWriteableObservable(options[eventConfig.writeTo]))

{

handler = function (e)

{

var propOrValue, value;

if (!childProp || !e[childProp] || e[childProp] === element)

{

propOrValue = eventConfig.value;

value = (typeof propOrValue === "string" && this[propOrValue]) ? this[propOrValue](childProp && element) : propOrValue;

options[eventConfig.writeTo](value);

}

};

}

if (handler)

{

widget.bind(eventName, handler);

}

};

};

ko.kendo.bindingFactory = new ko.kendo.BindingFactory();

//utility to set the dataSource with a clean copy of data. Could be overridden at run-time.

ko.kendo.setDataSource = function (widget, data, options)

{

var isMapped, cleanData;

if (data instanceof kendo.data.DataSource)

{

widget.setDataSource(data);

return;

}

if (!options || !options.useKOTemplates)

{

isMapped = ko.mapping && data && data.__ko_mapping__;

cleanData = data && isMapped ? ko.mapping.toJS(data) : ko.toJS(data);

}

widget.dataSource.data(cleanData || data);

};

//attach the raw data after Kendo wraps our items

(function ()

{

var existing = kendo.data.ObservableArray.fn.wrap;

kendo.data.ObservableArray.fn.wrap = function (object)

{

var result = existing.apply(this, arguments);

result._raw = function ()

{

return object;

};

return result;

};

})();

//private utility function generator for gauges

var extendAndRedraw = function (prop)

{

return function (value)

{

if (value)

{

ko.utils.extend(this.options[prop], value);

this.redraw();

this.value(0.001 + this.value());

}

};

};

//library is in a closure, use this private variable to reduce size of minified file

var createBinding = ko.kendo.bindingFactory.createBinding.bind(ko.kendo.bindingFactory);

//use constants to ensure consistency and to help reduce minified file size

var CLICK = "click",

CLICKED = "clicked",

CLOSE = "close",

COLLAPSE = "collapse",

CONTENT = "content",

DATA = "data",

ENABLE = "enable",

EXPAND = "expand",

ENABLED = "enabled",

EXPANDED = "expanded",

ERROR = "error",

FILTER = "filter",

HIDE = "hide",

INFO = "info",

ISOPEN = "isOpen",

MAX = "max",

MIN = "min",

OPEN = "open",

PALETTE = "palette",

READONLY = "readonly",

RESIZE = "resize",

SEARCH = "search",

SELECT = "select",

SELECTED = "selected",

SHOW = "show",

SUCCESS = "success",

SIZE = "size",

TARGET = "target",

TITLE = "title",

VALUE = "value",

VALUES = "values",

WARNING = "warning";

//createBinding({

// name: "kendoAutoComplete",

// events: {

// change: VALUE,

// open: {

// writeTo: ISOPEN,

// value: true

// },

// close: {

// writeTo: ISOPEN,

// value: false

// }

// },

// watch: {

// enabled: ENABLE,

// search: [SEARCH, CLOSE],

// data: function (value)

// {

// ko.kendo.setDataSource(this, value);

// },

// value: VALUE

// }

//});

//createBinding({

// name: "kendoButton",

// defaultOption: CLICKED,

// events: {

// click: {

// call: CLICKED

// }

// },

// watch: {

// enabled: ENABLE

// }

//});

createBinding({

name: "kendoCalendar",

defaultOption: VALUE,

events: {

change: VALUE

},

watch: {

max: MAX,

min: MIN,

value: VALUE

}

});

createBinding({

name: "kendoColorPicker",

events: {

change: VALUE,

open: {

writeTo: ISOPEN,

value: true

},

close: {

writeTo: ISOPEN,

value: false

}

},

watch: {

enabled: ENABLE,

value: VALUE,

color: VALUE,

palette: PALETTE

}

});

//createBinding({

// name: "kendoComboBox",

// events: {

// change: VALUE,

// open: {

// writeTo: ISOPEN,

// value: true

// },

// close: {

// writeTo: ISOPEN,

// value: false

// }

// },

// watch: {

// enabled: ENABLE,

// isOpen: [OPEN, CLOSE],

// data: function (value)

// {

// ko.kendo.setDataSource(this, value);

// },

// value: VALUE

// }

//});

createBinding({

name: "kendoDatePicker",

defaultOption: VALUE,

events: {

change: VALUE,

open:

{

writeTo: ISOPEN,

value: true

},

close: {

writeTo: ISOPEN,

value: false

}

},

watch: {

readOnly: READONLY,

enabled: ENABLE,

max: MAX,

min: MIN,

value: VALUE,

isOpen: [OPEN, CLOSE]

}

});

createBinding({

name: "kendoDateTimePicker",

defaultOption: VALUE,

events: {

change: VALUE,

open:

{

writeTo: ISOPEN,

value: true

},

close: {

writeTo: ISOPEN,

value: false

}

},

watch: {

readOnly: READONLY,

enabled: ENABLE,

max: MAX,

min: MIN,

value: VALUE,

isOpen: [OPEN, CLOSE]

}

});

//createBinding({

// name: "kendoDropDownList",

// events: {

// change: VALUE,

// open: {

// writeTo: ISOPEN,

// value: true

// },

// close: {

// writeTo: ISOPEN,

// value: false

// }

// },

// watch: {

// enabled: ENABLE,

// isOpen: [OPEN, CLOSE],

// data: function (value)

// {

// ko.kendo.setDataSource(this, value);

// //if nothing is selected and there is an optionLabel, select it

// if (value.length && this.options.optionLabel && this.select() < 0)

// {

// this.select(0);

// }

// },

// value: VALUE

// }

//});

//createBinding({

// name: "kendoEditor",

// defaultOption: VALUE,

// events: {

// change: VALUE

// },

// watch: {

// enabled: ENABLE,

// value: VALUE

// }

//});

////

//// Note: { Prafulla.Jain }

//// Below fix is for the Data Grid firing dataBound Event Multiple Times on Load

//// Instead of adding watch, using data for setting the grid dataSource

//// Before the kendo grid widget is initialized, options.dataSource is set to options.data

////

//// ---- Original Code ----

////createBinding({

//// name: "kendoGrid",

//// defaultOption: DATA,

//// watch: {

//// data: function (value, options)

//// {

//// ko.kendo.setDataSource(this, value, options);

//// }

//// },

//// templates: ["rowTemplate", "altRowTemplate"]

////});

//// ---- Modified Code ----

createBinding({

name: "kendoGrid",

defaultOption: DATA,

watch: "data",

templates: ["rowTemplate", "altRowTemplate"]

});

//createBinding({

// name: "kendoListView",

// defaultOption: DATA,

// watch: {

// data: function (value, options)

// {

// ko.kendo.setDataSource(this, value, options);

// }

// },

// templates: ["template"]

//});

//createBinding({

// name: "kendoMaskedTextBox",

// defaultOption: VALUE,

// events: {

// change: VALUE

// },

// watch: {

// enabled: ENABLE,

// isReadOnly: READONLY,

// value: VALUE

// }

//});

//createBinding({

// name: "kendoMenu",

// async: true

//});

//createBinding({

// name: "kendoMenuItem",

// parent: "kendoMenu",

// watch: {

// enabled: ENABLE,

// isOpen: [OPEN, CLOSE]

// },

// async: true

//});

//createBinding({

// name: "kendoMultiSelect",

// events: {

// change: VALUE,

// open: {

// writeTo: ISOPEN,

// value: true

// },

// close: {

// writeTo: ISOPEN,

// value: false

// }

// },

// watch: {

// enabled: ENABLE,

// search: [SEARCH, CLOSE],

// data: function (value)

// {

// ko.kendo.setDataSource(this, value);

// },

// value: VALUE

// }

//});

//var notificationHandler = function (type, value)

//{

// if (value || value === 0)

// {

// this.show(value, type);

// }

// else

// {

// this.hide();

// }

//};

//createBinding({

// name: "kendoNotification",

// watch: {

// error: function (value)

// {

// notificationHandler.call(this, ERROR, value);

// },

// info: function (value)

// {

// notificationHandler.call(this, INFO, value);

// },

// success: function (value)

// {

// notificationHandler.call(this, SUCCESS, value);

// },

// warning: function (value)

// {

// notificationHandler.call(this, WARNING, value);

// }

// }

//});

createBinding({

name: "kendoNumericTextBox",

defaultOption: VALUE,

events: {

change: VALUE

},

watch: {

readOnly: READONLY,

enabled: ENABLE,

value: VALUE,

max: function (newMax)

{

this.options.max = newMax;

//make sure current value is still valid

////var value = this.value();

////if ((value || value === 0) && value > newMax)

////{

//// this.value(newMax);

////}

},

min: function (newMin)

{

this.options.min = newMin;

//make sure that current value is still valid

////var value = this.value();

////if ((value || value === 0) && value < newMin)

////{

//// this.value(newMin);

////}

}

}

});

//createBinding({

// name: "kendoPanelBar",

// async: true

//});

//createBinding({

// name: "kendoPanelItem",

// parent: "kendoPanelBar",

// watch: {

// enabled: ENABLE,

// expanded: [EXPAND, COLLAPSE],

// selected: [SELECT]

// },

// childProp: "item",

// events: {

// expand: {

// writeTo: EXPANDED,

// value: true

// },

// collapse: {

// writeTo: EXPANDED,

// value: false

// },

// select: {

// writeTo: SELECTED,

// value: VALUE

// }

// },

// async: true

//});

//createBinding({

// name: "kendoProgressBar",

// defaultOption: VALUE,

// events: {

// change: VALUE

// },

// watch: {

// enabled: ENABLE,

// value: VALUE

// }

//});

//createBinding({

// name: "kendoRangeSlider",

// defaultOption: VALUES,

// events: {

// change: VALUES

// },

// watch: {

// values: VALUES,

// enabled: ENABLE

// }

//});

//createBinding({

// async: true,

// name: "kendoScheduler",

// watch: {

// data: function (value, options)

// {

// ko.kendo.setDataSource(this, value, options);

// }

// }

//});

//createBinding({

// name: "kendoSlider",

// defaultOption: VALUE,

// events: {

// change: VALUE

// },

// watch: {

// value: VALUE,

// enabled: ENABLE

// }

//});

//createBinding({

// name: "kendoSortable",

// defaultOption: DATA,

// events: {

// end: function (options, e)

// {

// var dataKey = "__ko_kendo_sortable_data__",

// data = e.action !== "receive" ? ko.dataFor(e.item[0]) : e.draggableEvent[dataKey],

// items = options.data,

// underlyingArray = options.data;

// //remove item from its original position

// if (e.action === "sort" || e.action === "remove")

// {

// underlyingArray.splice(e.oldIndex, 1);

// //keep track of the item between remove and receive

// if (e.action === "remove")

// {

// e.draggableEvent[dataKey] = data;

// }

// }

// //add the item to its new position

// if (e.action === "sort" || e.action === "receive")

// {

// underlyingArray.splice(e.newIndex, 0, data);

// //clear the data we passed

// delete e.draggableEvent[dataKey];

// //we are moving the item ourselves via the observableArray, cancel the draggable and hide the animation

// $(e.draggableEvent.target).hide();

// e.preventDefault();

// }

// //signal that the observableArray has changed now that we are done changing the array

// items.valueHasMutated();

// }

// }

//});

//createBinding({

// name: "kendoSplitter",

// async: true

//});

//createBinding({

// name: "kendoSplitterPane",

// parent: "kendoSplitter",

// watch: {

// max: MAX,

// min: MIN,

// size: SIZE,

// expanded: [EXPAND, COLLAPSE]

// },

// childProp: "pane",

// events: {

// collapse: {

// writeTo: EXPANDED,

// value: false

// },

// expand: {

// writeTo: EXPANDED,

// value: true

// },

// resize: SIZE

// },

// async: true

//});

//createBinding({

// name: "kendoTabStrip",

// async: true

//});

//createBinding({

// name: "kendoTab",

// parent: "kendoTabStrip",

// watch: {

// enabled: ENABLE

// },

// childProp: "item",

// async: true

//});

//createBinding({

// name: "kendoTooltip",

// events: {},

// watch: {

// content: CONTENT,

// filter: FILTER

// }

//});

createBinding({

name: "kendoTimePicker",

defaultOption: VALUE,

events: {

change: VALUE

},

watch: {

readOnly: READONLY,

max: MAX,

min: MIN,

value: VALUE,

enabled: ENABLE,

isOpen: [OPEN, CLOSE]

}

});

//createBinding({

// name: "kendoTreeView",

// async: true

//});

//createBinding({

// name: "kendoTreeItem",

// parent: "kendoTreeView",

// watch: {

// enabled: ENABLE,

// expanded: [EXPAND, COLLAPSE],

// selected: function (element, value)

// {

// if (value)

// {

// this.select(element);

// } else if (this.select()[0] == element)

// {

// this.select(null);

// }

// }

// },

// childProp: "node",

// events: {

// collapse: {

// writeTo: EXPANDED,

// value: false

// },

// expand: {

// writeTo: EXPANDED,

// value: true

// },

// select: {

// writeTo: SELECTED,

// value: true

// }

// },

// async: true

//});

//createBinding({

// name: "kendoUpload",

// watch: {

// enabled: ENABLE

// }

//});

//createBinding({

// async: true,

// name: "kendoWindow",

// events: {

// open: {

// writeTo: ISOPEN,

// value: true

// },

// close: {

// writeTo: ISOPEN,

// value: false

// }

// },

// watch: {

// content: CONTENT,

// title: TITLE,

// isOpen: [OPEN, CLOSE]

// }

//});

//createBinding({

// name: "kendoChart",

// watch: {

// data: function (value)

// {

// ko.kendo.setDataSource(this, value);

// }

// }

//});

//createBinding({

// name: "kendoLinearGauge",

// defaultOption: VALUE,

// watch: {

// value: VALUE,

// gaugeArea: extendAndRedraw("gaugeArea"),

// pointer: extendAndRedraw("pointer"),

// scale: extendAndRedraw("scale")

// }

//});

//createBinding({

// name: "kendoRadialGauge",

// defaultOption: VALUE,

// watch: {

// value: VALUE,

// gaugeArea: extendAndRedraw("gaugeArea"),

// pointer: extendAndRedraw("pointer"),

// scale: extendAndRedraw("scale")

// }

//});

}));

TitleResults for “How to create a CRG?”Also Available in