Working with Bound Components

Data binding makes the selected record of one component the data source for another one. A typical use case is binding a form with a data component, e.g.:

$$("myform").bind($$("list"));
// ...
$$("myform").save();

Here you will find more details and use cases of data binding.

Cursor for Bound Collections

The data cursor is used to control the position on the active data item. The cursor stores the ID of a data item that is currently selected in the master component.

When an item is selected in a data component, the component places the cursor on the selected item. Since there is no selection in DataCollection, it cannot focus on the item. You have to do it. That is where the DataCollection cursor is used.

Cursor should be set if several components are bound to or synced with one and the same source, e.g. a DataCollection. It is needed to avoid conflicts between different components referring to one and the same data source and making changes in it.

You can get and set cursor position with the help of the following methods:

  • setCursor(cursor); - string, number - sets the position of the cursor, the ID of the necessary data item.
  • getCursor(); - gets the current cursor position.
var cursor = master.getCursor();

The cursor can be deleted to remove the current bind link:

master.setCursor(null);

If a form (slave) is bound to a list (master) and the cursor is removed from the list, the form will be emptied.

Cursor is as well useful when working with DataCollections.

Binding Events

When you bind components, the slave component gets three events:

  • onBindApply – fires the moment binding is applied;
  • onBindRequest - fires when the component is ready to receive data from the master component;
  • onBindUpdate – fires when the value in the slave view changes and save() is called to update master.
$$("files").bind($$("folders"));
 
$$("files").attachEvent("onBindApply", function(){
    // makes the preview template empty
    $$("preview").setHTML("");
});

Preventing from Undefined Values

This concerns only data components that have the template property in their configuration. In a form and an htmlform binding is set according to the names of their inputs.

When no selection is made in the master component, the slave component would show undefined values. You can set the default values that should be displayed when nothing is selected. Use the defaultData property of the master:

webix.ui({
    rows:[
        {
            view:"list",
            template:"#rank#.#title#",
            // data: ...
            defaultData:{
                rank:"0",
                title:"default Item"
            }
        },
        { view:"template", template:"#rank#.#title#" }
    ]
})
 
$$("template1").bind($$("list1"));

Related sample:  Default Data

Look to CollectionBind API for more details.

Working with Bound Forms

When a form is bound to a component, the data from the selected item is pushed to the form. Any changes you make within the form are saved automatically to the selected item. It happens on calling the save(); method:

$$("myform").save();

If the form was not filled with the data from the master when the save() method was called, the form will add a new element into the master.

You can save some extra data together with the values from the form. Get the form values, add necessary properties there and pass the resulting object to the form.save() method:

var values = form.getValues();
values.myfield = "My value";
 
form.save(values);

If you have two forms bound to one and the same component and you save each of the forms separately, the data from the previously saved one is lost.

There are two possible solutions:

1) To get values from both forms and uniting them with extend:

var v1 = $$("form1").getValues();
var v2 = $$("form2").getDirtyValues();
$$("form1").save( webix.extend(v1, v2, true) ); // combine values from both forms

2) To use the saveBatch method that makes simultaneous saving of several forms together with the getDirtyValues method that prevents data overwriting.

$$("datatable1").saveBatch(function(){
    $$("form1").save();
    $$("form2").save( $$("form2").getDirtyValues() );
});

The getDirtyValues method returns only the fields that were changed in the form.

Binding Multiple-Value Widgets

Customization is possible only if the slave component has DataStore or TreeStore (DataTable, Tree, List, Chart, etc).

Rules for Binding Pattern

You can change the default pattern, according to which the records in a slave component are filtered with the help of rules. You can specify a rule as a function or a string and pass it as the second parameter of the bind() method.

Binding rule as a function

As a function, a binding rule receives 2 parameters:

  • slave - the slave data object;
  • master - the master data object or value depending on the type of the component.

For example, let's bind a list to a richselect and set the rule, according to which the list data are filtered depending on the selected option in the richselect:

Slave list displays records with the category equal to the master value

$$("list").bind($$("richselect"), function(slave, master){
    return slave.category == master;
});

Related sample:  List Data Bound to Richselect

You can also use the rule function to cancel binding at runtime. For example, let's bind two Datatables and cancel binding if no record is selected in master:

Slave datatable displays only records with movie property equal to master record ID

gridb.bind(grida, function(slave, master){
    if (!master) return false; //canceling binding
    return master.id == slave.movie;
});

Related sample:  Linking Tables

Pay attention that the selected value for the master view should be set after the data are loaded.

Binding rule as a string

A rule string is helpful when you bind a view to a hierarchical data component (e.g. Tree, TreeTable). The rule can help you decide which data levels to push to the slave. The rule can contain the following flags:

  • $level - push only the immediate children of a selected item;
  • $data - push only the object of a selected item without the children (used together with the format parameter).

Let's bind a DataTable to a Tree and push the children of the selected item into the DataTable:

$$("grid").bind( $$("tree"), "$level");
 
// where the tree data of the selected node is something like
{ id:"3", value:"Node 3", data:[
    // will be shown in slave component
    { id:"3.1", value:"Subnode 3.1" },
    { id:"3.2", value:"Subnode 3.1" }
]}

Related sample:  Tree Data Binding

The Format of Bound Data Presentation

This feature is also handy for binding with a hierarchical component. By default, the children of a data item are introduced by the data key in all the supported data formats. If you want to push data stored by a different key ("records", for example), you can pass its name as the format string. The format is passed as the third parameter of the bind() method.

Let's bind a DataTable to a Tree and use the $data rule together with the records format:

$$("grid1").bind( $$("tree"), "$data", "records");
 
// where the tree data of the selected node is something like
{ id:"3", value:"Node 3", records:[
    // will be shown in slave component
    { id:"3.1", value:"Subnode 3.1" },
    { id:"3.2", value:"Subnode 3.1" }
]}

Related sample:  Tree Data Binding: Subdata

Format can be set as a function where you can define the binding behavior manually. For example, let's define a function that will push both data and records from the selected node:

$$("grid2").bind( $$("tree"), "$data", function(obj, source){
    if (!obj) return this.clearAll();
    var fulldata = [].concat(source.data.getBranch(obj.id)).concat(obj.records);
    this.data.importData(fulldata, true);
});

Here we get item children with the help of a getBranch() method, combine them with data set by records key and import the resulting array into slave datatable.

Related sample:  Tree Data Binding: Subdata

Using Binding for Server Side

As a rule, a slave component doesn't communicate directly with the server side. It receives data from its master, and the changed data are sent first to the master that handles communication with the server.

However, you can get server-side data for the slave based on master selection with the help of the dataFeed functionality.

webix.ui({
    view:"form",
    id:"myform",
    // ...config
    dataFeed: "slave_data.php"
});
 
$$("myform").bind($$("mydatatable"));

Data feed defines the URL that will be used by the slave to send a server-side request the moment selection in the master component changes.

The functionality works the same for a form and collections (data components) yet the URL parameters sent with a request differ:

  • for forms: "action=get&id="+obj.id
  • for data: "filter[id]="+obj.id

where obj is the selected data item in the master component.

Back to top