Биндинги – это набор значений, которые доступны для использования в шаблоне. Они сохраняются в свойстве binding
. Это авторасширяемое поле, поэтому при создании класса, производного от basis.ui.Node
, или экземпляра этих классов, новое значение не перезаписывает старое, а дополняет.
Биндинг представляет из себя функцию, которая принимает единственный параметр node
– владелец шаблона, для которого вычисляется значение. Результат выполнения такой функции передается шаблону. Функция не должна иметь побочного эффекта, то есть не должна что-то менять в объектах.
var Node = basis.require('basis.ui').Node;
var Foo = Node.subclass({
template: basis.resource('./path/to/template.tmpl'),
binding: {
value: function(node){ // теперь шаблон может использовать {value}
return node.value;
}
}
});
Функция биндинга вычисляется сразу после создания экземпляра шаблона, но только в том случае, если шаблон использует биндинг. По этой причине не важно количество биндингов: вычисляться будут только используемые.
var Node = basis.require('basis.ui').Node;
var node = new Node({
template: '<span>{used}</span>',
binding: {
used: function(){
console.log('"used" binding calculated');
return true;
},
unused: function(node){
console.log('"unused" binding calculated');
return true;
}
}
});
// console> "used" binding calculated
В случае, если что-то поменялось, и нужно перевычислить значение биндинга, необходимо вызвать метод updateBind
, которому передается имя биндинга. Если изменения сопровождаются событием (событиями), можно указать это в описании биндинга (для этого используется расширенная форма) и избавиться от самостоятельного вызова updateBind
. В этом случае биндинг будет вычисляться (если используется шаблоном) при создании шаблона и при возникновении событий из указанного списка.
var Node = basis.require('basis.ui').Node;
var Foo = Node.subclass({
template: basis.resource('./path/to/template.tmpl'),
binding: {
value: function(node){ // простая запись, без указания событий;
return node.value; // для обновления используем updateBind
},
selected: { // расширенная форма
events: 'select unselect', // указываем список событий
getter: function(node){ // функция вычисления значения
return node.selected;
}
},
disabled: {
events: ['disable', 'enable'], // список событий можно указать как массив строк
getter: function(node){
return node.isDisabled();
}
},
title: ['update', function(node){ // еще один возможный вариант описать биндинг с событием
return node.data.title;
}]
},
setValue: function(){
this.value = value;
this.updateBind('value');
}
});
Так же в качестве описания биндига принимаются некоторые специальные значения:
объект, поддерживающий механизм binding bridge
– значение отдается в шаблон как есть;
var Node = basis.require('basis.ui').Node;
var Value = basis.require('basis.data').Value;
// экземпляры basis.data.Value имеют интерфейс bindingBridge
var count = new Value({ value: 123 });
var node = new Node({
binding: {
count: count, // эквивалентно
// count: function(){
// return count;
// }
double: count.as(function(value){ // метод as возвращает basis.Token, который
return value * value; // тоже поддерживает механизм binding bridge
})
}
});
строка – используется, если возможно, преобразование сокращения, иначе значение оборачивается в basis.getter;
var node = new Node({
binding: {
value: 'value' // эквивалентно
// value: basis.getter('value')
}
});
экземпляр basis.ui.Node
– при первом вычислении экземпляр добавляется в список satellite
узла, а в шаблон отдается значение его свойства element
.
var Node = basis.require('basis.ui').Node;
var satelliteNode = new Node();
var node = new Node({
binding: {
foo: satelliteNode // эквивалентно
// foo: {
// events: 'satelliteChanged',
// getter: function(node){
// node.setSatellite('foo', satelliteNode);
// return node.satellite.foo
// ? node.satellite.foo.element
// : null;
// }
// }
}
});
Для наиболее частых типов биндингов используется специальная запись в виде строки (сокращение), которая позволяет сократить количество кода для описания биндинга. Такие строки имеют некоторый префикс вида "название:"
, а все что идет после него используется как значение.
В модуле basis.ui
определены два типа сокращения:
data – предназначен для упрощения прокидывания полей из свойства data
в шаблон;
var Node = basis.require('basis.ui').Node;
var node = new Node({
data: {
age: 123
},
binding: {
foo: 'data:age', // эквивалентно
// foo: {
// events: 'update',
// getter: basis.getter('data.age')
// }
age: 'data:' // если имя биндинга совпадает с именем
// поля в data, то название поля можно опустить
}
});
satellite – предназначен для упрощения прокидывания корневого элемента сателлита в шаблон;
var Node = basis.require('basis.ui').Node;
var node = new Node({
binding: {
foo: 'satellite:name', // эквивалентно
// foo: {
// events: 'satelliteChanged',
// getter: function(node){
// return node.satellite['name']
// ? node.satellite['name'].element
// : null;
// }
// }
bar: 'satellite:' // если имя биндинга совпадает с именем сателлита,
// то его название в описании биндинга можно опустить
}
});
Управляет сокращениями объект basis.ui.BINDING_PRESET
, который позволяет добавлять новые сокращения методом add
при необходимости. Новые сокращения должны быть добавлены до первого объявления биндинга такого типа.
Для basis.ui.Node
и basis.ui.PartitionNode
определен ряд биндигов, которые доступны по умолчанию (в скобках указаны события):
state (stateChanged) – возвращает строковое значение свойства state
;
childNodesState (childNodesStateChanged) – возвращает строковое значение свойства childNodesState
;
childCount (childNodesModified) – возвращает число дочерних узлов;
hasChildren (childNodesModified) – возвращает true
если есть дочерние узлы и false
в ином случае;
empty (childNodesModified) – возвращает true
если нет дочерних узлов и false
в ином случае;
Для basis.ui.Node
так же определены дополнительные биндинги:
selected (select, unselect) – возвращает true
, если узел выбран (selected
== true
), иначе false
;
unselected (select, unselect) – возвращает true
, если узел не выбран, иначе false
;
disabled (disable, enable) – возвращает true
, если узел заблокирован (node.isDisabled()
== true
), иначе false
;
enabled (disable, enable) – возвращает true
, если узел не заблокирован, иначе false
;
В будущем планируется изменить цепочку наследования для
basis.ui.PartitionNode
и набор биндингов будет одинаковым.