Widgets¶
Widgets are the building blocks of Jibe applications. Widgets are objects that describe code and data that live simultaneously in the server and in the browser, and are automatically synchronized. You only write their code once, on the server side and in Python.
A Jibe application is composed of a tree of widgets. Since some widgets can have “children” widgets, we can build an application starting with one widget and adding widgets to it as its children. Its children can also have children, so we can indefinitely nest widgets within widgets. Some widgets serve only the purpuse of grouping widgets together and laying them out in a desired fashion (for example side by side, or top to bottom).
Jibe provides a rich collection of basic widgets that can be used to build more complex widgets. However, it is possible to build your own low-level widgets from scratch, allowing you to control every little detail.
In Example #1 we create an application by defining
our own class ExampleApp
, which inherits from MainApp
and,
MainApp
inherits from Widget
. So, an application is nothing
but a widget, except for some additional code in MainApp
that
allows this widget to be an application. We see as well
that its member children
is assigned in the constructor
and it is populated with two other widgets, a Button
and
an Input
. Finally, we call the register()
method of
the button to be able to respond to “click” events with
a call to on_button_click()
.
There is very little going on under the hood, except for the behavior of two special variables as we’ll see next.
Widget Children¶
The children
variable of a widget is aware when it is
assigned to or changed. When this happens, the widget immediately
notifies the browser and triggers the necessary updates.
This means that the list of children can be updated at any
time, not just in the constructor of the widget, allowing
for dynamic updates to the client.
Widget Properties¶
The properties
dictionary of a widget is also aware of changes
and keeps the client automatically synchronized.
When a property changes it triggers a reaction on both
the server and the client. By default, the client will
re-render the widget such that it always properly reflects
the state of properties
in the user interface. On the
server side we can react to the event by overriding the
on_change()
method of Widget
. For example:
class MyWidget(Widget):
def __init__(self, connection):
super().__init__(connection)
self.properties['open'] = False
def on_change(propname, newval, oldval):
super().on_change(propname, newval, oldval)
# Do something else here
print("Properties changed!")
It is important to call the parent’s on_change()
since it
takes care of updating the widget in the browser about the change.
Properties can alse be read and written as members of the widget without the need to reference the properties variable:
print(self.open) # False
self.open = True # This triggers on_change()