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.prop2bind(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)) } }
ActionEvents pumped by the button.