One of the most common tasks when developing an application with a GUI is keeping the user interface and the data in sync. For example, suppose you use conventional development tools to create a web application for browsing and editing customer records. Without App Maker, you'd have to develop a way keep the application UI and the database records in sync in the following ways:
Update every UI element that displays data when the next record in the database is requested.
Add change listeners to all UI elements to ensure that the user's changes are reflected in the customer record.
Update the current customer record to receive the new data.
This is a lot of boilerplate to write and maintain, which is cumbersome if you're already a programmer and might be a major roadblock if you're not.
With App Maker, instead of having to write all that boilerplate, you use bindings to indicate that a property on the customer record and a property of a widget must be kept in sync. And you do all of this in an easy-to-use visual interface. That's it: App Maker does all the rest of the work for you.
Beyond this common scenario, App Maker bindings do more than just keep UI elements in sync with underlying values. You can use an App Maker binding to keep any two App Maker properties in sync, such as the email of the current logged in user, and a datasource query parameter. In fact, because almost anything in App Maker has bindings — models, datasources, widgets, and scripts — you can use bindings across a variety of App Maker properties.
Very simply, a property is a named value of an App Maker object. You can get and set the values of properties in App Maker, and most App Maker objects have properties that you can access from parts of your application.
You can set properties in many ways:
- in the App Maker UI—when you set the name of a widget
- via a binding—when one property changes to reflect updates from another property
You can access a variety of properties:
- fields in database records
- the email address for the currently logged-in user
- widget attributes such as position, name, or value
In fact, properties are found all over App Maker, with the most common place being the Property Editor:
and the binding chooser:
Let's dig deeper into our exploration of properties with a discussion of objects. Objects are the "things" that make up App Maker and App Maker applications, and just about everything in App Maker is an object. What are these things? They are the widgets that make up your UI, the records that represent your data, the data source objects that read and write your data for you, and much more. Even your application itself is an object.
For example, a Text Area widget is an App Maker object with several properties, including name and label. A data record is an application object which has properties that you define, such as a customer record with a name property.
All App Maker properties have a data type, which means that they only accept specific kinds of values, like numbers or strings. Many properties have simple types like string, number, or boolean, but some properties have complex types. For example, the parent property of a widget is also a widget and so is typed as Widget.
App Maker uses a path notation to refer to properties when referencing
them in bindings, or in scripts. For example, a data model object named
Person with a property named
Name, would be referenced as
Path and property values can be undefined.
This is different from being
An example of an undefined property is a record relation property that has not been loaded yet.
A path such as
datasource.item.Name is undefined if its last property (
Name) is undefined, or if
any of its parts such as
item are undefined or
In general, App Maker treats undefined values like
However, input widgets will disable themselves if their values are set to undefined.
For example, you can use the following script to clear the value of a text box and disable it:
textBox.value = undefined;
This example illustrates two complex properties —
Address. Each of these are special Types that you might define in a
model you create. They are not built-in App Maker types.
Address property of Person is of type Address, you could
use path notation to reference the location of a person with
A binding is a mechanism for keeping two properties in sync. As an App Maker author, you will often declare that you want two properties—like the value of a text input and a field of a record—bound, and App Maker will automatically keep them in sync: when one property changes, the other will be set.
All properties in App Maker are observable, meaning that it's possible to listen for changes to a property. When a binding is made between two properties, the binding listens to, or observes, changes in each property, and when one changes, the other is updated.
A common binding example in App Maker is to bind a text input's value to the item property of a datasource. This binding is done using the App Maker property editor, but if we wrote the binding out, if would look like this:
@widget.text <-> @datasource.item.MyField
Type converter for bound values
A property has a type and a value. The value itself also has a type,
which must match its property's value. For example, the
property for a widget is a string type, so values for names are
strings and cannot be treated as integers.
If you want to bind two properties together, they must either have the same type, or their values must be convertible from one type to the other. This is called type conversion.
For example, if you give a value of
"6" to the
Name property of a
widget, this value of
"6" is treated as a string, not a number. You
could bind this property to another property that is of type integer,
and the App Maker built-in type converter attempts to convert the
value types between these two properties.
App Maker includes many built-in type conversions, so that most bindings will work. The converters work in both directions, and make their best attempt to convert a value from one type to the other.
|string||number||Only if from can be parsed as a number.|
|string||boolean||Only if from is "true" or "false" (Case insensitive).|
|string||date||Only if from is a date in YYYY-MM-DD format.|
|number||boolean||Zero is converted to false and any other value to true|
|Array<A>||Array<B>||As long as A and B are compatible.|
Sometimes, you would like to bind two properties with some custom data conversion between them.
For example, you might want to bind a field in a record to a text field in the UI, but you want
the user input to be trimmed of whitespace before being saved in the database.
Or you might want to convert a date to a string using a different date pattern than the one used by
the default App Maker type conversion.
Transformers allow you specify transformations on property paths.
Each transformer takes an input value and produces an output value and most transformers can
also take output values and convert them back to input values.
These transformations can be chained together.
For example, to trim whitespace from inputs and outputs for a string path, you might bind the
value property of a text field to the
Name field of a datasource record:
@value <-> @datasource.item.Name#trim()
Or you can specify custom date to string formatting when binding a text field
value property to
a date field
timestamp in the database:
@value <--> @datasource.item.TimeStamp#formatDate('yyyy/MM/dd HH:mm:ss');
Transformers can be chained together:
@value <-> @datasource.item.Name#nullToEmpty()#trim()
You can find a list of all the built-in transformers here.
Transformers can also be applied to elements of an array rather than the array
itself. For example, if you are populating a Dropdown widget's
with items from a projection. The syntax
is the same, but use two hash marks instead of one.
@names <-> @datasources.items..TimeStamp##formatDate('yyyy/MM/dd HH:mm:ss')
Top-level properties in bindings
When you bind the property of an object (such as a widget name), you'll
use the binding picker to navigate through the available properties.
App Maker automatically adjusts the available properties depending on
the object that you are binding from. This simplifies the process of
binding to certain common properties. For example, if you bind a
value for a Button widget, the binding picker automatically defaults
to the widget's
datasource.item property, which usually
contains fields of a model.
However, you might want to bind a widget or other object to something other than the automatically provided suggestions in the binding picker. For that, it's helpful to understand the two general categories of properties that you can navigate through when binding objects in your application.
Globally available properties
You can bind to any property of your application. These properties are generally accessed through
app object. When binding, all properties of the
app objects are categorized, and exposed
for bindings. See the app object API documentation
for detailed documentation of all properties.
Properties available to widgets
A widget can be bound to all the properties of the
app object, and to two additional
widget—the widget itself.
datasource—the datasource for the widget, which is the most common object to bind to a widget. This is also available as
@widget.datasource, but for convenience,
datasourceis shown in the binding picker in the UI editor.
For example, suppose you have a Delete button named
and you want to create a binding so that the button is disabled if
there is no record in the database to delete. However, there's no
property to directly represent that concept. We do have the
property and the property
@datasource.item, and we know that
if there is no item, the value of item is
with those pieces of information, we can make this binding:
@widget.enabled <-> @datasource.item != null
and the button will only be enabled when there's a record.
For more information on creating binding expressions, see Binding Expressions and Client-side Scripting. For information on all the properties and methods available for widgets and client objects, see Widgets API and Client API.