5.20232.939
Wijmo API Module wijmo.knockout.base Wijmo API Module

wijmo.knockout.base Module

Contains KnockoutJS bindings for the Wijmo controls.

The bindings allow you to add Wijmo controls to KnockoutJS applications using simple markup in HTML pages.

To add a Wijmo control to a certain place in a page's markup, add the <div> element and define a binding for the control in the data-bind attribute. The binding name corresponds to the control name with a wj prefix. For example, the wjInputNumber binding represents the Wijmo InputNumber control. The binding value is an object literal containing properties corresponding to the control's read-write property and event names, with their values defining the corresponding control property values and event handlers.

The following markup creates a Wijmo InputNumber control with the value property bound to the view model's theValue property, the step property set to 1 and the inputType property set to 'text':

<div data-bind="wjInputNumber: { value: theValue, step: 1, inputType: 'text' }"></div>

Custom elements

As an alternative to the standard Knockout binding syntax, the Wijmo for Knockout provides a possibility to declare controls in the page markup as custom elements, where the tag name corresponds to the control binding name and the attribute names correspond to the control property names. The element and parameter names must be formatted as lower-case with dashes instead of camel-case. The control in the example above can be defined as follows using the custom element syntax:
<wj-input-number value="theValue" step="1" input-type="'text'"></wj-input-number>

Note that attribute values should be defined using exactly the same JavaScript expressions syntax as you use in data-bind definitions. The Wijmo for Knockout preprocessor converts such elements to the conventional data-bind form, see the Custom elements preprocessor topic for more details.

Binding to control properties

Wijmo binding for KnockoutJS supports binding to any read-write properties on the control. You can assign any valid KnockoutJS expressions (e.g. constants, view model observable properties, or complex expressions) to the property.

Note that binding expression should resolve (after calling ko.unwrap(expression) on it) to a pure JavaScript value understandable by the corresponding Wijmo JavaScript control. This in particular means that you can’t bind the itemsSource property of Wijmo controls to a Knockout observableArray, or to array whose items’ properties are Knockout observable(s).

Most of the properties provide one-way binding, which means that changes in the bound observable view model property cause changes in the control property that the observable is bound to, but not vice versa. But some properties support two-way binding, which means that changes made in the control property are propagated back to an observable bound to the control property as well. Two-way bindings are used for properties that can be changed by the control itself, by user interaction with the control, or by other occurences. For example, the InputNumber control provides two-way binding for the value and text properties, which are changed by the control while a user is typing a new value. The rest of the InputNumber properties operate in the one-way binding mode.

Binding to control events

To attach a handler to a control event, specify the event name as a property of the object literal defining the control binding, and the function to call on this event as a value of this property. Wijmo bindings follow the same rules for defining an event handler as used for the intrinsic KnockoutJS bindings like click and event. The event handler receives the following set of parameters, in the specified order:
  • data: The current model value, the same as for native KnockoutJS bindings like click and event.
  • sender: The sender of the event.
  • args: The event arguments.

The following example creates an InputNumber control and adds an event handler for the valueChanged event showing a dialog with a new control value.

<!-- HTML -->
<div data-bind="wjInputNumber: { value: theValue, step: 1, valueChanged: valueChangedEH }"></div>
 
//View Model
this.valueChangedEH = function (data, sender, args) {
    alert('The new value is: ' + sender.value);
}

The same control defined using the custom element syntax:

<wj-input-number value="theValue" step="1" value-changed="valueChangedEH"></wj-input-number>

Binding to undefined observables

View model observable properties assigned to an undefined value get special treatment by Wijmo bindings during the initialization phase. For example, if you create an observable as ko.observable(undefined) or ko.observable() and bind it to a control property, Wijmo does not assign a value to the control. Instead, for properties supporting two-way bindings, this is the way to initialize the observable with the control's default value, because after initialization the control binding updates bound observables with the control values of such properties. Note that an observable with a null value, e.g. ko.observable(null), gets the usual treatment and assigns null to the control property that it is bound to. After the primary initialization has finished, observables with undefined values go back to getting the usual treatment from Wijmo, and assign the control property with undefined.

In the example below, the value property of the InputNumber control has its default value of 0 after initialization, and this same value is assigned to the view model theValue property:

<!-- HTML -->
<div data-bind="wjInputNumber: { value: theValue }"></div>
 
//View Model
this.theValue = ko.observable();

Defining complex and array properties

Some Wijmo controls have properties that contain an array or a complex object. For example, the FlexChart control exposes axisX and axisY properties that represent an Axis object; and the series property is an array of Series objects. Wijmo provides special bindings for such types that we add to child elements of the control element. If the control exposes multiple properties of the same complex type, then the wjProperty property of the complex type binding specifies which control property it defines.

The following example shows the markup used to create a FlexChart with axisX and axisY properties and two series objects defined:

<div data-bind="wjFlexChart: { itemsSource: data, bindingX: 'country' }">
    <div data-bind="wjFlexChartAxis: { wjProperty: 'axisX', title: chartProps.titleX }"></div>
    <div data-bind="wjFlexChartAxis: { wjProperty: 'axisY', title: chartProps.titleY }"></div>
    <div data-bind="wjFlexChartSeries: { name: 'Sales', binding: 'sales' }"></div>
    <div data-bind="wjFlexChartSeries: { name: 'Downloads', binding: 'downloads' }"></div>
</div>

The same control defined using the custom element syntax:

<wj-flex-chart items-source="data" binding-x="'country'">
    <wj-flex-chart-axis wj-property="'axisX'" title="chartProps.titleX"></wj-flex-chart-axis>
    <wj-flex-chart-axis wj-property="'axisY'" title="chartProps.titleY"></wj-flex-chart-axis>
    <wj-flex-chart-series name="'Sales'" binding"'sales'"></wj-flex-chart-series>
    <wj-flex-chart-series name="'Downloads'" binding"'downloads'"></wj-flex-chart-series>
</wj-flex-chart>

The control property

Each Wijmo control binding exposes a control property that references the Wijmo control instance created by the binding. This allows you to reference the control in view model code or in other bindings.

For example, the following markup creates a FlexGrid control whose reference is stored in the flex observable property of a view model and is used in the button click event handler to move to the next grid record:

<!-- HTML -->
<div data-bind="'wjFlexGrid': { itemsSource: data, control: flex }"></div>
<button data-bind="click: moveToNext">Next</button>
 
//View Model
this.flex = ko.observable();
this.moveToNext = function () {
    this.flex().collectionView.moveCurrentToNext();
}

The initialized event

Each Wijmo control binding exposes an initialized event and a Boolean isInitialized property. The event occurs right after the binding creates the control and fully initializes it with the values specified in the binding attributes. For bindings containing child bindings, for example, a wjFlexGrid with child wjFlexGridColumn bindings, this also means that child bindings have fully initialized and have been applied to the control represented by the parent binding. The isInitialized property is set to true right before triggering the initialized event. You can bind a view model observable property to the binding’s isInitialized property to access its value.

The following example adjusts FlexGridColumn formatting after the control fully initializes with its bindings, which guarantees that these formats are not overwritten with formats defined in the bindings:

<!-- HTML -->
<div data-bind="'wjFlexGrid': { itemsSource: dataArray, initialized: flexInitialized }">
     <div data-bind="wjFlexGridColumn: { binding: 'sales', format: 'n2' }"></div>
     <div data-bind="wjFlexGridColumn: { binding: 'downloads', format: 'n2' }"></div>
</div>
 
//View Model
this.flexInitialized = function (data, sender, args) {
    var columns = sender.columns;
    for (var i = 0; i < columns.length; i++) {
        if (columns[i].dataType = wijmo.DataType.Number) {
            columns[i].format = 'n0’;
        }
    }
}

Custom elements preprocessor

The Wijmo Knockout preprocessor uses the standard Knockout ko.bindingProvider.instance.preprocessNode API. This may cause problems in cases where other custom preprocessors are used on the same page, because Knockout offers a single instance property for attaching a preprocessor function, and the next registering preprocessor removes the registration of the previous one.

To honor another attached preprocessor, the Wijmo Knockout preprocessor stores the currently registered preprocessor during initialization and delegates the work to it in cases where another processing node is not recognized as a Wijmo control element, thus organizing a preprocessor stack. But if you register another preprocessor after the Wijmo for Knockout preprocessor (that is, after the <script> reference to the wijmo.knockout.js module is executed) then you need to ensure that the other preprocessor behaves in a similar way; otherwise, the Wijmo Knockout preprocessor is disabled.

If you prefer to disable the Wijmo Knockout preprocessor, set the wijmo.disableKnockoutTags property to false before the wijmo.knockout.js module reference and after the references to the core Wijmo modules, for example:

<script src="scripts/wijmo.js"></script>
<script src="scripts/wijmo.input.js"></script>
<script>
    wijmo.disableKnockoutTags = true;
</script>
<script src="scripts/wijmo.knockout.js"></script>

Note that in this case you can use only the conventional data-bind syntax for adding Wijmo controls to the page markup; the Wijmo custom elements are not recognized.