Widgets are dynamic UI controls that can be integrated within any application. They can be tailored to the application, yet provide reusable, stylistically consistent UI functions. The term “widgets” is widely used within web development, but Mojo widgets are different than other widgets. Mojo widgets have a defined behavior and have many options; they generate complex HTML and are easily styled with CSS.
It helps to understand the HTML that the widget generates. This is especially true for widgets like List and Dialog, for which the application specifies HTML templates that largely define the widget’s appearance.
Widgets are declared in HTML as empty div tags:
<div id="my-toggle" x-mojo-element="ToggleButton"></div>
The x-mojo-element
attribute
specifies the widget type used to fill out the div when the HTML is
added to the page. This can happen in either of the following
circumstances:
When a scene is pushed and the scene’s view HTML includes widgets.
When a widget is specified in an HTML template used by another widget.
When the application inserts HTML which includes widgets, and makes a call to explicitly instantiate them.
In the second case, for example, if your scene includes a List widget whose list items include other widgets, a new set of the list item’s widgets are instantiated each time a new item is added to the list.
Before a widget is inserted into the scene, it must be set up.
You should do this in the scene assistant’s
setup
method by calling the scene
controller method, setupWidget()
.You need to
provide three arguments to this call (shown in Table 3-1).
Table 3-1. setupWidget arguments
Argument | Description |
---|---|
Widget ID | The ID or |
Attributes | Object containing the widget’s static properties, normally options or attributes of the widget |
Model | Object containing the widget’s dynamic properties, usually data associated with the widget, but occasionally including dynamic attributes |
For example, a Toggle Button would be set up this way:
var toggleAttr = {trueValue: "on", trueLabel: "On", falseValue: "off", falseLabel: "Off"}; this.toggleModel = { value: "on", disabled: false }; this.controller.setupWidget("my-toggle", toggleAttr, this.toggleModel);
The my-toggle
argument
specifies the widget being set up. The argument can be either the
id
or name
of the widget’s div element. It’s usually
fine to use id
, but it won’t be
unique if your widget is instantiated more than once. This can happen if
the widget is declared in a template for a list item, or if your scene
might be pushed multiple times (without being popped). In these cases,
use the name
attribute
instead.
The second argument specifies the attributes for the widget. These are properties that
affect the behavior and display of the widget, but are not tied to the
actual data being displayed or edited. Widget attributes cannot be
changed after the widget is instantiated. A toggle button is a simple
binary selector; its attributes include trueValue
, trueLabel
, falseValue
, and falseLabel
, among others. The values allow you
to toggle between on/off, left/right, up/down, in/out, and so on, while
the labels can either track those values or offer different terms for
the user.
The last argument specifies the widget’s data model object. This is the actual user data displayed
by the widget. The contents of the model object will often change, each
time requiring the widget to be updated. In our example, the model
includes the toggle’s value and a disabled property, set to false
.
The split between attributes and model objects was designed to allow you to use widgets within list entries. The attributes represent the setup shared between list items, and the model provides the per-item data. This will make more sense when you get to the section Lists.
When a widget model is changed outside of the widget, the widget
will not automatically update and reflect those changes. The application (usually the scene assistant) is required
to call the modelChanged()
method
on the widget’s scene controller, passing the model object that changed.
The scene controller will then notify all widgets using that model, so
they can properly display the current model data. For example, suppose
you disabled the toggle button in our example:
this.toggleModel.disabled = true; this.controller.modelChanged(this.toggleModel, this);
The first argument to the modelChanged()
method is the model object that
has changed. Model change notification uses the identity of the model
object to determine which widgets are using that model object and then
notify them to update.
The second argument identifies which object has changed the model. This ensures that objects are not notified of their own changes to the model.
Scene assistants (and widget assistants, where applicable) will
usually simply pass the keyword this
. The argument is
optional if called from something other than a widget controller.
The modelChanged()
method
notifies widgets of changes to a model object; if you need to directly change the
model, you should use setWidgetModel()
instead. While setupWidget()
applies
to all widgets with the given HTML name attribute, setWidgetModel()
only ever
applies to a single widget instance. So you must pass the widget’s ID or
the actual widget DOM element.
Calling modelChanged()
with
an entirely new model object will not update the model. Instead, there
will be no change, since the specified model will not be used by any
existing widget; no notifications will be generated or received. A
common bug occurs when assigning a model to another object then
calling modelChanged()
using that
new object. This will not work; you need to use the original model
object for modelChanged()
or use
setWidgetModel()
with the new
object.
The following will change the model in our toggle button example:
// Use a new model object in place of the old one: this.newToggleModel = {value: "off"}; // Set the widget to use the new model: this.controller.setWidgetModel("my-toggle", this.newToggleModel);
Each widget is supported by events. Where possible, the widget will use common events, such as
Mojo.Event.tap
or Mojo.Event.propertyChange
. Where that’s not
possible, widget-specific events
are defined, such as Mojo.Event.listDelete
or Mojo.Event.listReorder
for List widgets, or
Mojo.Event.scrollStarting
for the
Scroller widget.
You should set up event listeners in the scene assistant’s setup method when
you set up the widget, by adding the listeners to the div element that
declares the widget. For example, the toggle button sends a Mojo.Event.propertyChange
when the widget is
toggled, meaning that the toggle button’s model changes value.
Using the example toggle button that we’ve been building on, you would set up a listener with code like this:
This.controller.listen("my-toggle", Mojo.Event.propertyChange this.handleSelectorChange.bindAsEventListener(this));
For more details on this, look at the section Events, which covers the entire event model for more information, or consult the Mojo.Event API reference in the Palm SDK.
18.118.1.25