From Documentation

Jump to: navigation, search

  • Author
    Simon Pai, Engineer, Potix Corporation
  • Date
    January 27, 2011
  • Version
    ZK 6


The Story

Think of an extremely ordinary scenario, where you want to clear all the texts in a form by clicking a button.

SmallTalk Selector Demo Form.png

While you see the screen shot, you may have already come up with an implementation in mind. For example:

public class SomeFormController extends GenericForwardComposer {
	Textbox usenameTb;
	Textbox passwordTb;
	Textbox retypepwTb;
	// ...
	// ...
	Textbox memoTb;
	public void onClick$clearBtn(Event event) {
		// ...
		// ...

But wait, no.

The unordinary part of the story is here: this feature is actually implemented by just 9 lines of code.

public class FormController extends SelectorComposer {
	@Wire("textbox, intbox, decimalbox, datebox")
	List<InputElement> inputs;

	@Listen("onClick = button[label='Clear']")
	public void onClear(MouseEvent event) {
		for(InputElement i : inputs) i.setText("");

These are what we foresee in ZK 6: leveraging Annotation power from Java 1.5, and introduction to some new techniques.

In this Small Talk we are going to reveal two new weapons: Selector and SelectorComposer.


The jQuery/CSS3-like Component Selector

In the previous example, Selector is shown as a part of the parameters in Annotation @Wire and @Listen.

	@Wire("textbox, intbox, decimalbox, datebox")
	@Listen("onClick = button[label='Clear']")

The concept is simple: Selector is a pattern string that matches nodes in a Component tree.

In other words, by giving a Selector string, you can specify a collection of Components from a ZUL file.

	// Collects all the textboxes, intboxes, decimalboxes, and dateboxes as a List and wire to inputs
	@Wire("textbox, intbox, decimalbox, datebox")
	List<InputElement> inputs;
	// Collects all the buttons whose label is "Clear", and adds EventListeners for them
	@Listen("onClick = button[label='Clear']")
	public void onClear(MouseEvent event) {
		// ...

If you know jQuery or CSS selector, this is exactly their counterpart on server side.


The syntax of Selector is closely analogous to CSS3 selector.

Component type, class, attribute, pseudo class are used to describe properties of a component. For example:

// Matches any Button component

// Matches any Component with ID "btn"

// Matches any Button with ID "btn"

// Matches any Button whose label is "Submit"

Combinators are used to describe relations between components. For example:

// Matches any Button who has a Window ancestor
"window button"

// Matches any Button whose parent is a Window
"window > button"

// Matches any Button whose previous sibling is a Window
"window + button"

// Matches any Button who has a Window as a senior sibling
"window ~ button"

// Matches any Button whose parent is a Div and grandparent is a Window
"window > div > button"



SelectorComposer is analogous to GenericForwardComposer. But instead of wiring variables by naming convention, the new composer wires them by annotation and specifies the Components by Selector.

public class MyComposer extends SelectorComposer {
	// If the field is a Collection, the composer will wire all Components matched by the selector
	private List<Label> labelList;
	// Same for Array
	private Label[] labelArray;
	// If the field is not a Collection or Array, the first matched Component is wired to the field
	private Label label1;
	// If selector string is not given, it will attempt to wire implicit objects by name or fellows by ID.
	private Desktop desktop;
	private Button clearBtn;

Event listening is handled in a similar way. However, instead of forwarding the events, it adds the method to the EventListener of the target Components directly.

public class MyComposer extends SelectorComposer {
	// Like auto-forwarding, methods annotated with @Listen will be added to the event listeners of the components described by selector.
	@Listen("onClick = button#btn")
	public void onPressButton(Event event) {
		// The event here will be the original event, not ForwardEvent!
	// The event listener will be added to ALL the components that match the selector, not just the first match
	@Listen("onClick = #myGrid > rows > row")
	public void onClickAnyRow(MouseEvent event) {
		// ...
	// You can specify multiple event types
	@Listen("onClick = button[label='Submit']; onOK = textbox#password")
	public void onSubmit(Event event) {
		// ...


More about Selector

You can also use Selector independently.

For example:

Window win;

// returns a list of components, containing all labels in the page
Selectors.find(page, "label");

// returns all components with id "myId" under the Window win. (including itself)
Selectors.find(win, "#myId");

// returns all components whose .getLabel() value is "zk" (if applicable)
Selectors.find(page, "[label='zk']");

// returns all captions whose parent is a window
Selectors.find(win, "window > caption");

// returns all buttons and toolbarbuttons
Selectors.find(page, "button, toolbarbutton");

// you can assemble the criteria:
// returns all labels, whose parent is a window of id "win", and whose value is "zk"
Selectors.find(page, "window#win > label[value='zk']");

Comparison with CSS3 Selector

Syntax In CSS 3 Selector In Component Selector Comment
tagname DOM element type Component type  
#id DOM ID Component ID  
.class CSS class SClass / ZClass  
[attr='value'] DOM attribute getAttr() or dynamic attribute If getAttr() is not a method on such component, it is skipped
:pseudo-class Pseudo class Pseudo class :root, :empty, :first-child, :last-child, :only-child, :nth-child(), :nth-last-child()
::pseudo-element Pseudo element N/A  
> + ~ Combinator Combinator Identical to CSS 3 combinators



Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.