Работа с привязанными компонентами

Привязка данных определяет выбранный элемент компонента как источник данных для другого. Например, форму часто привязывают к какому-либо компоненту данных:

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

Далее мы рассмотрим другие примеры, а также тонкости использования привязки данных.

Курсор для привязанных компонентов

Курсор используется для определения активного элемента данных. Курсор хранит ID элемента данных, выбранного в текущий момент в компоненте-мастере.

Когда в компоненте данных выбран какой-либо элемент, компонент отмечает его курсором. Поскольку в коллекции данных выбирать элементы нельзя, вам необходимо сделать это самостоятельно. Для этого и предназначен курсор в DataCollection.

Курсор необхоим в ситуациях, когда несколько компонентов привязаны/синхронизированны с одним источником данных, например коллекцией данных. Он нужен для того, чтобы избежать конфликтов между компонентами, которые ссылаются на один и тот же источник данных и изменяют его.

Вы можете получить/задать курсор с помощью следующих методов:

  • setCursor(cursor) - (string, number) - задаёт курсор; ID элемента в качестве параметра;
  • getCursor() - получает позицию курсора.
var cursor = master.getCursor();

Чтобы удалить текущую привязку, задайте null в качестве параметра метода setCursor:

master.setCursor(null);

Если форма (зависимый компонент) привязана к списку (мастеру), а курсор снят со списка, то форма очистится.

Курсор может быть полезен при работе с DataCollections.

События привязки

Когда вы привязываете компоненты, зависимый компонент получает 3 события:

  • onBindApply – срабатывает в момент привязки;
  • onBindRequest - срабатывает, когда компонент готов принять данные из компонента-мастера;
  • onBindUpdate – срабатывает, когда значение зависимого компонента изменено и вызван метод save().
$$("files").bind($$("folders"));
 
$$("files").attachEvent("onBindApply", function(){
    // очищает превью темплейт
    $$("preview").setHTML("");
});

Как предупредить значения undefined

Это касается только тех компонентов, у которых есть свойство template. В form и htmlform привязка осуществляется согласно их свойству name.

Если в мастере нет выбранных компонентов, зависимый компонент покажет значения undefined. Для такой ситуации вы можете задать значения по умолчанию. Используйте свойство мастера - defaultData:

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

Более подробно о CollectionBind API.

Работа с привязанными формами

Когда форма привязана к компоненту, данные выбранного элемента приходят в форму. Любые изменения в форме автоматически отображаются в выбранном элементе. Это происходит при вызове метода save():

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

Если при вызове метода форма будет пустой, то в мастер добавится новый элемент.

Вы также можете сохранять дополнительные данные вместе со значениями формы. Для этого получите значения формы, добавьте необходимые свойства и передайте полученный объект в метод form.save():

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

Если к компоненту привязаны 2 формы и вы сохраняете каждую из форм по отдельности, данные из первой сохранённой формы исчезнут.

Существуют два возможных решения:

1) Получить данные обеих форм и объединить их с помощью extend:

var v1 = $$("form1").getValues();
var v2 = $$("form2").getDirtyValues();
$$("form1").save( webix.extend(v1, v2, true) ); // комбинирует данные двух форм

2) Использовать метод saveBatch который сохраняет данные нескольких форм, вместе с методом getDirtyValues, который блокирует переопределение данных

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

Метод getDirtyValues возвращает только те поля, которые были изменены.

Привязка виджетов с несколькими значениями

Кастомизация возможна только если у зависимого компонента есть DataStore или TreeStore (DataTable, Tree, List, Chart, и т.д.).

Правила для шаблона привязки

Вы можете изменить шаблон привязки по умолчанию, согласно которому записи в зависимом компоненте фильтруются с помощью rules. Вы можете определить rule как функцию или строку и передать её в метод bind() вторым параметром.

Правило в виде функции

В виде функции, правило принимает 2 параметра:

  • slave - зависимый объект данных;
  • master - объект-мастер или значение в зависимости от типа компонента.

Давайте привяжем список к richselect и установим правило: данные списка фильтруются в зависимости от выбранной опции в richselect:

Зависимый список отображает элементы категории равной значению в мастере

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

Related sample:  List Data Bound to Richselect

Вы также можете использовать правило-функцию, чтобы заблокировать привязку динамически. Давайте привяжем две таблицы и если в мастере не будет выбранных элементов - заблокируем ёё:

Зависимая таблица показывает, записи равные записям в мастере

gridb.bind(grida, function(slave, master){
    if (!master) return false; // блокируем привязку
    return master.id == slave.movie;
});

Related sample:  Linking Tables

Обратите внимание, задавать значение для компонента-мастера нужно после загрузки данных.

Правило в виде строки

Правило-строка приходится кстати, когда вы привязываете компонент к иерархическим данным (Tree, TreeTable). Правило поможет решить, какие уровни данных передавать в зависимый компонент. Правило может включать следующие флаги:

  • $level - добавлять прямых наследников выбранного элемента;
  • $data - добавлять только объект (без дочерних элементов); используется вместе спараметром format).

Давайте привяжем таблицу к дереву и добавим дочерние элементы выбранного в таблицу:

$$("grid").bind( $$("tree"), "$level");
 
// иерархические данные выбранного узла
{ id:"3", value:"Node 3", data:[
    // будут показаны в зависимом компоненте
    { id:"3.1", value:"Subnode 3.1" },
    { id:"3.2", value:"Subnode 3.1" }
]}

Related sample:  Tree Data Binding

Формат привязанных данных

Эта особенность также полезна при привязке к иерархическим данным. По умолчанию, дочерние элементы представлены свойством data во всех поддерживаемых форматах данных. Если вы хотите добавить данные под другим ключём (например "records"), передайте имя ключа как формат строки. format передаётся в качестве третьего параметра в метод bind().

Давайте привяжем таблицу к иерархическим данным и воспользуемся правилом $data вместе с форматом records:

$$("grid1").bind( $$("tree"), "$data", "records");
 
// иерархические данные выбранного узла
{ id:"3", value:"Node 3", records:[
    // будут показаны в зависимом компоненте
    { id:"3.1", value:"Subnode 3.1" },
    { id:"3.2", value:"Subnode 3.1" }
]}

Related sample:  Tree Data Binding: Subdata

Формат можно задать в виде функции и описать в ней логику привязки вручную. Например, давайте зададим функцию, которая будет добавлять data и records из выбранного узла:

$$("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);
});

Мы получили дочерние элементы узла с помощью метода getBranch(). Затем скомбинировали их с данными по ключу records и импортировали полученный массив в зависимую таблицу.

Related sample:  Tree Data Binding: Subdata

Привязка на серверной стороне

Как правило, зависимый компонент не общается с сервером напрямую. Он получает данные из своего мастера. Изменённые же данные сначала отправляются в мастер, который передаёт их на сервер.

Однако вы можете получить серверные данные для зависимого компонента с помощью dataFeed.

webix.ui({
    view:"form",
    id:"myform",
    // ...конфиг
    dataFeed: "slave_data.php"
});
 
$$("myform").bind($$("mydatatable"));

Свойство задаёт URL, которым воспользуется зависимый компонент и отправит запрос на сервер в момент смены выбранного элемента в мастере.

Это также работает для форм и коллекций (компонентов данных), но параметры URL отличаются:

  • для форм: "action=get&id="+obj.id
  • для данных: "filter[id]="+obj.id

где obj выбранный объект даннык в мастере.

Наверх