Introduction to Properties¶
qooxdoo comes with its own convenient and sophisticated property management system. In order to understand its power we will first take a look at the ordinary property handling in plain JavaScript first.
Ordinary Property Handling¶
Let's say we have a property width for an object obj.
As is a good practice in regular high-level programming languages you should not access object properties directly:
// NOT RECOMMENDED: direct access to properties
obj.width = 200; // setting a value
var w = obj.width; // getting the current value
Instead you should work with properties only through so-called accessor methods ("getters") and mutator methods ("setters"):
// direct access is no good practice
obj.setWidth(200); // setting a value
var w = obj.getWidth(); // getting the current value
Of course, directly accessing properties may be faster because no indirection by a function call is needed. Nonetheless, in practice this does not outweigh the disadvantages. Direct access to properties does not hide internal implementation details and is a less maintainable solution (Well, you don't program web applications in assembler code, do you?).
A typical implementation of the accessor and mutator methods would look like the following, where those instance methods are declared in the members section of the class definition:
// ordinary example #1
members:
{
getWidth : function() {
return this._width;
},
setWidth : function(width)
{
this._width = width;
return width;
}
}
Something that is very familiar to the typical programmer of Java or any other comparable language. Still, it is not very convenient. Even this trivial implementation of only the basic feature requires a lot of keystrokes. More advanced features like type checks, performance optimizations, firing events for value changes, etc. need to be coded by hand. An improved version of the setter could read:
// ordinary example #2
members:
{
setWidth : function(width)
{
if (typeof width != "number") {
// Type check: Make sure it is a valid number
throw new Error("Invalid value: Need a valid integer value: " + width);
};
if (this._width != width)
{
// Optimization: Only set value, if different from the existing value
this._width = width;
// User code that should be run for the new value
this.setStyleProperty("width", width+ "px");
};
return width;
}
}
Large part of the code found here is for managing the validation and storage of the incoming data. The property-specific user code is rather short.
qooxdoo Property Handling¶
Let's see how the above example can be written using qooxdoo's property implementation. The property itself is declared in the properties section of the class definition. Only if some property-specific code needs to be run in the setter, an additional apply method has to be given:
// qooxdoo version of ordinary example #2
properties : {
width : { check : "Number", apply : "applyWidth" }
}
members :
{
applyWidth : function(value) {
this.setStyleProperty("width", value + "px");
}
}
Compare that to the lengthy code of the ordinary code example above! Much shorter and nicer, also by objective means. And it almost only contains the "real code".
The apply method may optionally be defined for each property you add to your class. As soon as you define a key "apply" in your property declaration map the method gets automatically called on each property modification (but not during initial initialization). If you do not define an apply method, the property just handles the fundamental storage of your data and its disposal.
Despite needing much less explicit code (keep in mind, for every property), it actually contains at least as many features as the hand-tuned code: The type of the property is checked automatically (Number in the example above). Moreover, new values are only stored (and the optional apply method called) if different from the existing values. A tiny but important optimization.
Change Events¶
qooxdoo supports full-featured event-based programming throughout the framework. So-called change events are a good example for this powerful concept.
Each property may optionally behave as an observable. This means it can send out an event at any time the property value changes. Such a change event (an instance of qx.event.type.Data) is declared by providing a custom name in the event key of the property definition. While you are free to choose any event name you like, the qooxdoo framework tries to consistently use the naming convention "change + Propertyname", e.g. "changeWidth" for a change of property width. In order to get notified of any value changes, you simply attach an event listener to the object instance containing the property in question.
For example, if you would like the element property of a Widget instance widget to fire an event named "changeElement" any time the value changes.
properties : {
element: { event: "changeElement" }
}
If this happens, you would like to set the DOM element's content:
widget.addEventListener("changeElement", function(e) {
e.getData().innerHTML = "Hello World";
});
The anonymous function acts as an event handler that receives the event object as variable e. Calling the predefined method getData() returns the new value of property element.
Available Methods¶
qooxdoo's dynamic properties not only make sure that all properties behave in a consistent way, but also guarantee that the API to access and manipulate properties are identical. The user is only confronted with a single interface, where the method names are easy to understand. Each property creates (at least) the following set of methods:
- setPropertyName(): Mutator method ("setter") to set a new property value.
- getPropertyName(): Accessor method ("getter") that returns the current value.
Additionally, all properties of boolean type (declared by check: "Boolean") provide the following convenience methods:
- isPropertyName(): Identical to getPropertyName().
- togglePropertyName(): Toggles between true and false.
Property Groups¶
Property groups is a layer above the property system explained in the last paragraphs. They make it possible to set multiple values in one step using one set call. qx.ui.core.Widget supports the property group padding. padding simply sets the paddingLeft, paddingRight, paddingTop and paddingBottom property.
widget.setPadding(10, 20, 30, 40);
The result is identical to:
widget.setPaddingTop(10);
widget.setPaddingRight(20);
widget.setPaddingBottom(30);
widget.setPaddingLeft(40);
As you can see the property groups are a nice really convenient feature.
Shorthand support¶
One more thing. The property group handling also supports some CSS like magic like the shorthand mode for example. This means that you can define only some edges in one call and the others get filled automatically:
// four arguments
widget.setPadding(top, right, bottom, left);
// three arguments
widget.setPadding(top, right+left, bottom);
// two arguments
widget.setPadding(top+bottom, right+left);
// one argument
widget.setPadding(top+right+bottom+left);
As you can see this can also reduce the code base and make it more user-friendly.
BTW: The values of a property group can also be given an array as first argument e.g. these two lines work identically:
// arguments list
widget.setPadding(10, 20, 30, 40);
// first argument as array
widget.setPadding([10, 20, 30, 40]);
Note
For more information regarding declaration, usage and internal functionality please see the the developer documentation.