UI-Databinding

As you have learned in the last sections, layout and logic of a RemoteUI App are separate concerns. UI databinding is the "magic glue" that ties together your UI and logic. To realize this, you write short expressions in your layout file to trigger actions (Action Bindings) or realize one-way or two-way property synchronization (Property Bindings). These expressions are formulated in MVEL 2.0, which is a mighty Java-like expression language with high performance.

Action Bindings

If you have worked with JavaScript and HTML or maybe Java Server Faces before, you are familiar with action bindings: They allow defining methods that are called when the user performs certain actions on a UI element. The following binding shows one of the most important action bindings, an OnClickBinding. If you like, copy the Button element and add it in your main.layout.xml as last child of the LinearLayout.

Action-Binding
<Button text="Do Magic" onClick="#{performMagic()}" />

In this example, the method performMagic() is called, when the user clicks the button. In RuiML, expressions are surrounded by the hashed mustache #{…​}.

Binding expressions are always evaluated against the currently active WebActivity. In this case, your MainActivity needs a corresonding function as given in the following listing (try it!):

Java
Groovy
Kotlin
public void performMagic() {
	System.out.println("Abracadabra");
}
void performMagic() {
	System.out.println "Abracadabra" 
}
fun performMagic() {
	println("Abracadabra")
}

Action bindings are small MVEL scripts. Therefore, you are allowed to code everything that can be evaluated against your current context. MVEL uses coercion to find the best matching method. For you this means, that you can pass parameters without much hassle as shown in the following listing:

Action-Bindings with Parameters
<Button text="Do Magic 1" onClick="#{performMagic('Abracadabra')}" />
<Button text="Do Magic 2" onClick="#{performMagic('Hocus Pocus')}" />
<Button text="Do Magic 3" onClick="#{System.out.println('Sim Sala Bim')}" />

Then you extend the existing method with a parameter and you have greatly avoided repeating yourself:

Java
Groovy
Kotlin
public void performMagic(String spell) {
	System.out.println(spell);
}
void performMagic(String spell) {
	System.out.println spell 
}
fun performMagic(spell: String) {
	println(spell)
}

Have you noticed the button in the listing above that executes its "magic" directly?

Although it seems tempting, we recommend minimizing the amount of code you embed in your layout. Three reasons why you should prefer implementing methods in your activity instead: better performance, compile-time checks and better testability.

Property Bindings

Property Bindings allow you to dynamically bind a value at runtime to an attribute of your layout. In the following example, the lastSpell String property of the given activity is bound to a TextView’s `text attribute.

Layout XML
<TextView text="#{lastSpell}" />

Java
Groovy
Kotlin
@Activity
public class MainActivity extends WebActivity {
	public String lastSpell = "";
}
@Activity
class MainActivity extends WebActivity {
	String lastSpell = "";
}
@Activity
class MainActivity : WebActivity(){
	var lastSpell = ""
}

This kind of binding is called output binding, as it is a one-way connection from the business logic to the UI. The text will be displayed, but as of the nature of the TextView, is not editable. You can control many attributes via output bindings. Typical examples are text and colors.

It is possible to use the same approach with a different UI element to realize an input/output binding enabling text input. By applying an EditTextView to the same property, it is now possible to change the String by entering a new text in the displayed input field.

Layout XML
<EditTextView text="#{nextSpell}" />

Java
Groovy
Kotlin
@Activity
public class MainActivity extends WebActivity {
	public String nextSpell = "";
	
	//Optional
	public void setNextSpell(String newSpell) {
		nextSpell = newSpell;
		//Process input here, if needed				
	}
}
@Activity
class MainActivity extends WebActivity {
	public String nextSpell = ""
	
	//Optional
	void setNextSpell(String newSpell){
		nextSpell = newSpell
		//Process input here, if needed
	}
}
@Activity
class MainActivity : WebActivity(){
	var nextSpell = ""
	
	//Optional
	fun setNextSpell(newSpell:String){
		nextSpell = newSpell;
		//Process input here, if needed
	}
}

There are many different UI elements that support input/output bindings. Examples: EditTextViews, Checkboxes, RadioButtons and many more.

Sometimes, you need to process or react on user input that is bound to a property. In the above example, a setter is used to further process the input. If a setter is present, it will always be preferred over the direct field access by the MVEL engine.

Firing property changes

All output bindings are executed by the framework after an Activity has been started. If you want to manipulate the values of the bound properties before they are transferred to the client, you need to override the Activity’s onStart() method as shown in the following example:

Java
Groovy
Kotlin
@Activity
public class MainActivity extends WebActivity {
	public String lastSpell;
	
	@Override
	public void onStart(){
		lastSpell = "Booyaka";
	}
}
@Activity
class MainActivity extends WebActivity {
	String lastSpell
	
	@Override
	void onStart(){
		lastSpell = "Booyaka"
	}
}
@Activity
class MainActivity : WebActivity(){
	var lastSpell = ""
	
	@Override
	fun onStart(){
		lastSpell = "Booyaka"
	}
}

In contrast to this example, you may use some advanced technique to load properties, e.g. from a database or a given parameter.

If you change a value during an Activity’s active state, you need to tell the framework, that the value has changed to trigger the re-execution of a binding. This is done with the firePropertyChanged method as shown in the following example.

Layout XML
<TextView text="#{lastSpell}"/>
<Button text="Trigger Change" onClick="#{onButtonClicked()}" />

Java
Groovy
Kotlin
@Activity
public class MainActivity extends WebActivity {
	public String lastSpell = "";
	
	public void onButtonClicked(){
		lastSpell = "Booyaka";
		firePropertyChanged("lastSpell");
	}
}
@Activity
class MainActivity extends WebActivity {
	String lastSpell = ""
	
	void onButtonClicked(){
		lastSpell = "Booyaka";
		firePropertyChanged("lastSpell")
	}
}
@Activity
class MainActivity : WebActivity(){
	var lastSpell = ""
	
	fun onButtonClicked(){
		lastSpell = "Booyaka"
		firePropertyChanged("lastSpell")
	}
}

The firePropertyChanged method takes an arbitrary list of Strings that correspond to the bound properties. Currently, the framework determines the necessity for firing a binding by checking, whether its expression contains the given String. In the above example, all bindings containing the word lastSpell would be fired.

results matching ""

    No results matching ""