6.2 Binding - Reference Documentation
Authors: Andres Almiray
Version: 1.2.0
6.2 Binding
Binding in Griffon is achieved by leveraging Java Beans'PropertyChangeEvent
and their related classes, thus binding will work with any class that fires this type of event, regardless of its usage of @Bindable or not.
6.2.1 Syntax
These are the three options for writing a binding using thebind
node
- Long
bean1.prop1
to bean2.prop2
bind(source: bean1, sourceProperty: 'prop1', target: bean2, targetProperty: 'prop2')
- Contextual
bean1.prop1
to bean2.prop2
- Implicit source
bean(bean1, prop1: bind(target: bean2, targetProperty: 'prop2'))
- Implicit target
bean(bean2, prop2: bind(source: bean1, sourceProperty: 'prop1'))
sourceProperty:
or targetProperty:
can be omitted; the bind node's value will become the property name, in other wordsbean(bean1, prop1: bind('prop2', target: bean2))
- Short
bean(bean2, prop2: bind{ bean1.prop1 })
6.2.2 Additional Properties
The following properties can be used with either the long or contextual binding syntax- mutual:
true
then a bidirectional binding will be created instead.import groovy.beans.Bindable import groovy.swing.SwingBuilderclass MyModel { @Bindable String value }def model = new MyModel() def swing = new SwingBuilder() swing.edt { frame(title: 'Binding', pack: true, visible: true) { gridLayout(cols: 2, rows: 3) label 'Normal' textField(columns: 20, text: bind('value', target: model)) label 'Bidirectional' textField(columns: 20, text: bind('value', target: model, mutual: true)) label 'Model' textField(columns: 20, text: bind('value', source: model)) } }
- converter:
import groovy.beans.Bindable import groovy.swing.SwingBuilderclass MyModel { @Bindable String value }def convertValue = { val -> '*' * val?.size() }def model = new MyModel() def swing = new SwingBuilder() swing.edt { frame(title: 'Binding', pack: true, visible: true) { gridLayout(cols: 2, rows: 3) label 'Normal' textField(columns: 20, text: bind('value', target: model)) label 'Converter' textField(columns: 20, text: bind('value', target: model, converter: convertValue)) label 'Model' textField(columns: 20, text: bind('value', source: model)) } }
- reverseConverter:
- validator:
false
or null
.import groovy.beans.Bindable import groovy.swing.SwingBuilderclass MyModel { @Bindable String value }def isNumber = { val -> if(!val) return true try { Double.parseDouble(val) } catch(NumberFormatException e) { false } }def model = new MyModel() def swing = new SwingBuilder() swing.edt { frame(title: 'Binding', pack: true, visible: true) { gridLayout(cols: 2, rows: 3) label 'Normal' textField(columns: 20, text: bind('value', target: model)) label 'Converter' textField(columns: 20, text: bind('value', target: model, validator: isNumber)) label 'Model' textField(columns: 20, text: bind('value', source: model)) } }
This type of validation is not suitable for semantic validation (a.k.a. constraints in domain classes). You would want to have a look at the Validation plugin.
- sourceEvent:
PropertyChangeEvent
.
- sourceValue:
sourceevent
.import groovy.beans.Bindable import groovy.swing.SwingBuilderclass MyModel { @Bindable String value }def model = new MyModel() def swing = new SwingBuilder() swing.edt { frame(title: 'Binding', pack: true, visible: true) { gridLayout(cols: 2, rows: 3) label 'Text' textField(columns: 20, id: 'tf1') label 'Trigger' button('Copy Text', id: 'bt1') bind(source: bt1, sourceEvent: 'actionPerformed', sourceValue: {tf1.text}, target: model, targetProperty: 'value') label 'Model' textField(columns: 20, text: bind('value', source: model)) } }
ActionEvent
s pumped by the button.