Working with Bound Components

Binding makes selected record of one component a data source for another. The basic binding tie is established between two components using their IDs of variables they are stored in (if any).

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

It has already been described.

Here different aspects of data binding are examined.

Binding Rules

The bind() method can take two optional parameters to customize the binding pattern - rule format.

The customization is only possible in case slave component is based on DataStore (all data management components except for tree-like) or TreeStore (tree and treetable).

Binding rule defines a scheme according to which records in the slave component are filtered. It can be either a string or a function.

Binding rule as a function

As function, binding rule takes 2 parameters:

  • slave - slave data object;
  • master - master data object.

Slave list displays records with category equal to master value

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

Here list data is filtered according to the option you choose within a richselect control.

Related sample:  List Data Bound to Richselect

Additionally, binding rule can cancel bind applying in runtime.

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

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

Here binding is canceled in case no data is sent from master (i.e. no record is selected in master).

Related sample:  Linking tables

Pay attention that selected value for a master view should be set after data is loaded.

Binding rule as a string

If master component is loaded with hierarchical data you can define a binding rule with the help of the following flags:

  • $level - only immediate children of a selected item are pushed to slave component. By default children are introduced by data key in all the supported data formats:

Grid will show only children of a selected tree node

$$("grid").bind( $$("tree"), "$level");

Input JSON of such a tree is as follows:

{ id:"..", value:"..", data:[
    //will be shown in slave component
    { id:"..", value:".." },
    { id:"..", value:".." }
]}

Related sample:  Tree Data Binding

  • $data - the object of a selected item (without children) is pushed to a slave component. Here you should pass the format of sub-data presentation to specify data items necessary for the slave.

Format of bound data presentation

Format can be a string that defines the key by which desired data is set in the item object. As a rule, it differs from the key by which children are set (if they are set via "data" (default), it's more reasonable to use $level rule):

$$("grid1").bind( $$("tree"), "$data", "records");

Input JSON data of such a tree is as follows:

{ id:"..", value:"..", records:[
    //will be shown in slave component
    { id:"..", value:".." },
    { id:"..", value:".." }
]}

Related sample:  Data binding - subdata

Format can be set via a function where you describe binding behavior manually:

$$("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:  Data binding - subdata

Binding 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

What happens when no selection is made in the master component? If no measures are taken, the slave component would show undefined values.

This concerns only data components that have template property in their constructor and doesn't concern form and htmlform where binding is set according to the names of their inputs.

The defaultData property of the master one helps solve the problem.

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

Now, when no item is selected in the list, template will show default values (as set by the defaultData) instead of undefined ones.

Look to CollectionBind API for more details.

Cursor Concept for Bound Collections

Cursor concept is used to control focus within the application with bound and synced data-management components. Its position is the ID of the active data item.

Simply put, cursor stores the ID of a data item from the master control for which binding is performed at the moment.

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();

Cursor can be deleted to remove the current bind link:

master.setCursor(null);

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

Cursor is as well useful when working with non-visible DataCollections.

Using Binding for Server Side

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

However, there exists a possibility to get server-side data for the slave based on master selection - dataFeed functionality.

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

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

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

  • for forms the request URL looks like: "slave_data.php?action=get&id="+obj.id
  • for data components the request URL is as follows: "slave_data.php?filter[id]="+obj.id

where obj is selected data item in the master component.

Saving Data of Multiple Bound Forms

When a form is bound to a component, data from the selected item is transmitted to the form as well as any changes you make within the form are saved automatically to the selected item.

It happens on calling the save(); method

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

But 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 two possible solutions:

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

The saveBatch method is called from the master component rather than from either of the slave forms. The getDirtyValues method returns only the fields that were changed in the form.

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

2) To save data in both forms without using saveBatch() with the help of the following technique:

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

Saving Extra Data with the Bound Form

It is possible to save some extra data together with the changes made in the form to the bound component.

For this you need to get values of all form elements and specify the name of the field that contains an extra value. Then pass form values to the form.save() method:

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