Advanced

Data Drivers

Webix provides a special mixin called DataDriver. It allows you to manage loading of data into Webix components in the formats different from JSON a lot easier. The mixin provides a set of predefined data parsers for the common formats: json, xml, html, csv, jsarray, excel (Webix Pro only) and htmltable. Data drivers convert data from any of these formats to JSON to make them suitable for data components to work with.

Data drivers possibilities

Customizing Data Driver

XML

In case of XML you can redefine the following:

ElementTypeCode
data tag xpath
webix.DataDriver.xml.records="/*/item";
configuration tag xpath
webix.DataDriver.xml.config="/*/config";
child tag tag name
webix.DataDriver.xml.child="item";

For example to alert the default processing of XML data you can add the following line to your code:

webix.DataDriver.xml.records = "/*/book";
webix.DataDriver.xml.child = "part";

The line above will redefine data parsing logic for all XML sources. If you want to separate default and custom logic you need to create a custom XML processor on the base of the default one.

var myxml = webix.DataDriver.myxml = webix.copy(webix.DataDriver.xml);
myxml.records = "/*/book";
myxml.child = "part";

Related sample:  Tree: XML Dataset

Child tags can be specified by a function:

var myxml2 = webix.DataDriver.myxml2 = webix.copy(webix.DataDriver.xml);
myxml2.records = "/*/book";
myxml2.child = function(obj){
    if (obj.$level == 1)
        return obj.part;
    if (obj.$level == 2)
        return obj.page;
}

Related sample:  Tree: XML Dataset

CSV

It is possible to define row and cell separators:

webix.DataDriver.csv.row = "\n";
webix.DataDriver.csv.cell = ",";

The above line resets processing of all the CSV sources in the application. To avoid this, create a custom CSV format:

var mycsv = webix.DataDriver.mycsv = webix.copy(webix.DataDriver.csv);
csv.row = "\n";
csv.cell = ",";

HTML

You can redefine which tag in HTML will be processed as a data tag:

webix.DataDriver.html.tag = "LI";

The above line resets processing of all the HTML sources in the application. To avoid this, create a custom HTML format:

var myhtml = webix.DataDriver.myhtml = webix.copy(webix.DataDriver.html);
html.tag = "LI";

JSON

You can redefine what object property stores sub-items (used for hierarchical dataset, e.g. tree, treegrid, grouplist, etc.):

webix.DataDriver.json.child = "data";

The above line resets processing of all the JSON sources in the application. To avoid this, create a custom JSON format:

var myjson = webix.DataDriver.json = webix.copy(webix.DataDriver.json);
myjson.child = "data";

Child tag can also be specified as a function, if you want to create different tags for child items of different levels:

myjson.child = function(obj){
    if (obj.$level == 1)
        return obj.parts;
    if (obj.$level == 2)
        return obj.pages;
};

Any custom child collection will be converted to "data", while the original child fields are removed from the data item during parsing.

Unlike static tags, dynamic fields are not removed from data items, because the field name varies. If you need to remove them, do it explicitly in the child method:

myjson.child = function(obj) {
    var data;
    if (obj.$level == 1) {
        data = obj.parts;
        delete obj.parts;
    }
    if (obj.$level == 2) {
        data = obj.pages;
        delete obj.pages;
    }
    return data;
}

Data Driver Methods

All data drivers share the following methods:

//converts string to object
var data = driver.toObject(data);
 
//returns array of all records in data source
var records = driver.getRecords(data);
 
//returns single data object
var data = driver.getDetails(records[0]);

XML specific methods

//runs xpath
var elements = driver.xpath("/some/xpath", data);
 
//converts xml tag to json object
var obj = driver.tagToObject(elements[0]);
 
//converts string to js data-types, numbers and booleans
obj = driver.assignTypes(obj);

Creating New Data Driver

In addition to the built-in data types, it is possible to define custom ones by creating a custom data driver.

The structure of a driver is the following:

webix.DataDriver.driverName={ //driverName - the name of the type
    toObject:function(text,xml){
        // ...
        return text; 
    },
    getRecords:function(data){ 
        var result = [];
        // ...
        return result;
    },
    getDetails:function(data){
        var result = {}
        // ... 
        return result;
    },
    getInfo:function(data){
        return { 
           size:0, 
           from:0 
        };
    }
};

You can check the structure of the existing data drivers in the Webix source code (/sources/load/drivers/driver_name.js).

For a start, we have some data that we want to use as a new data type. The first thing we need to make with this data is to convert it into an intermediate object (an object that will be used as an input parameter in other functions).

1 . So, our first step is the toObject(text, xml) function. The function is called after data loading or directly in the parse method and returns the intermediate data object:

  • text - incoming data;
  • xml - xml object (for xml loading scenario. For other data types can be ignored).

2 . Then, we form an array of records using data from our intermediate object with the help of the getRecords(data) function. It takes the only parameter:

  • data - the intermediate object from the previous step.

3 . Having an array of records we need to specify a set of properties for each single record via the getDetails(data) method. It takes the only parameter:

  • data - an element of the array from the previous step.

4 . The last action makes sense just for dynamic data loading scenarios. It's about the getInfo(data) function that gets total count of the data and position at which new data needs to be inserted. The method accepts the following parameter:

  • data - the intermediate object from step 1.

The function returns an object with the following properties:

  • size - total count of the data (total_count) or 0 is dynamic loading is not enabled/not possible
  • from - index of the last data item at the moment (pos) or 0 if dynamic loading is not enabled/not possible.

JSON and XML data drivers add extra properties to this object:

  • parent - index of the root branch
  • config - configuration object loaded together with the data
  • key - security key (webix_security).

So, taking these four or even three steps you can specify any data type and then use it while developing.

Creating New Data Driver Based on Existing

Creating a completely new driver is not a most common task, but user may need to alter the processing logic of some built-in driver.

It can be done with the help of Webix extending pattern that allows to extend any JSON object:

webix.DataDriver.custom = webix.extend({
    records:"/data/items/item",
    getDetails:function(obj){
        var res = {};
        var cells = this.xpath(obj, "cell");
        for (var i = 0; i < cells.length; i++)
            res[cells[i].getAttribute("id")] = this.nodeValue(cells[i]);
        return res;
    }
}, webix.DataDriver.xml);

Related sample:  Loading from Custom XML

Back to top