Биндинги – это набор значений, которые доступны для использования в шаблоне. Они сохраняются в свойстве 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
и набор биндингов будет одинаковым.