Stateful widgets
CommonJS modules are stateful. They are loaded into memory once on their first use after which every next require()
will return the same instance. This makes them perfect to act as global configuration modules or event dispatchers.
NOTE: As pointed out by Timan in the comments, in Titanium this only works if you use the exact same path each time you require. Using require('/a')
and then require('a')
will give you two instances.
Alloy Controlers & Widgets instances
Alloy Controllers and Widgets both use CommonJS modules. If you look at the generated code, you’ll see them exporting a Controller()
function, which is then used to instanciate the controller using new
in alloy.js
:
exports.createWidget = function(id, name, args) {
if ("undefined" != typeof name && null !== name && _.isObject(name) && !_.isString(name)) {
args = name;
name = DEFAULT_WIDGET;
}
return new (require("alloy/widgets/" + id + "/controllers/" + (name || DEFAULT_WIDGET)))(args);
};
Because all your original controller-code is wrapped by this Controller()
function, you are notable to export other variables or use private stateful variables shared between differenced instances of the same controller/widget.
Widget libraries
The solution is to put any stateful variables your widget instances need access to in a seperate CommonJS module and require()
that in the widget’s Controller()
code. Widgets can have assets
and lib
folders just like Alloy apps can so the code would still be nicely contained in the widget.
Theoretical example
Let’s see how this works by looking at a simple widget that displays a label with an incrementing value; the hello world of statefulness. The first instance of the widget will be a label showing 1
, the next one will have 2
etc.
app/widgets/my.widget/views/widget.xml
<Alloy>
<Label id="count" />
</Alloy>
app/widgets/my.widget/controllers/widget.js
var stateful = require(WPATH('stateful'));
$.count.text = stateful.count.toString();
stateful.count++;
NOTE: The WPATH()
function will return a path relative to the widget folder.
app/widgets/my.widget/lib/stateful.js
module.exports = {
count: 1
};
Real-world example
A real-world example is the button widget I did a year ago. The Adding styles and setting the default section of the README explains how a seperate styles.js
CommonJS module can be used to set and change built-in and custom button-styles and set the default a new instance of the widget will use.
Comments
Timan Rebel
Please note that Commonjs modules are currently only stateful in Titanium if you always use the same url to require them. So require(‘generic/stateful’) and require(‘../stateful’) gives you 2 different modules instead of one.
Fokke Zandbergen Post author
Excellent note, will update.
Jong Eun Lee
Great guide!
Oscar Brito (@aetheon)
What alloy is doing when compiling the controller is really wrong. What you are doing is great but I would really want to see a more modern approach from alloy controller, like:
http://blog.divhide.com/2014/09/20/using-dependency-injection-on-titanium-alloy/
Fokke Zandbergen Post author
@Oscar I agree Alloy controllers should not be wrapper on compiled like they are now and Tony Lukasavage did announce in New York last year that Alloy 2.0 should fix that.