Alpaca maintains observables that can be subscribed to by listeners that want to listen for changes to values in the form. An observable exists for every field and registration can be either programmatic or driven from configuration.
In general, if you're sticking to straight JSON-schema, you won't find much use for observables. JSON schema is fairly fixed in terms of its interdependency of fields (see dependencies).
Rather, observables are most useful when you really want to take full control of how fields refresh, update or change their state based on one or more values elsewhere in the form (at any level).
Here's an example that lets you pick a city and then lets you pick your favorite sports team. The sports teams that are available for selection change depending on what city you select.
After the form renders, the
team field subscribes to the
city field's value changes, the
team listener fires.
This gives it a chance to update it's schema and refresh.
Incidentally, this example also defines a form and a button that, when clicked, submits the form in a background
Ajax post. You can use the
submit method to submit directly (which will redirect your browser) or the
ajaxSubmit to run the submit in the background and get a promise.
This example does the same thing as the one above but uses a data source to load values for the
field. After rendering, it sets up an event listener for the
change event. When the
field changes it's value, the
team field is refreshed.
The data source is reloaded. In doing so, the data source uses the
observable method to look up the
value of the
city field by path.
This example also uses a key/value object instead of an array to specify both the schema.enum and options.optionLabels.
Each field control has a set of methods that you can use to set and retrieval observable state. These methods are:
field.subscribe([scope], id, fn)
Subscribes a function as an event handler for an observable identified by it's ID. The scope variable
is optional and identifies a namespace for the observable. If not provided, the namespace is one that
is global to the form being rendered and can be acquired using
field.unsubscribe([scope], id, fn)
Unsubscribes a function as an event handler for an observable identified by it's ID.
Retrieves an observable. The observable has methods
get() (which can return null),
clear(). Note that setting or changing the value of an
observable will cause any observable subscribers to trigger.
Clears the value of an observable. This is equivalent to
Note that setting or changing the value of an observable will cause any observable subscribers to trigger.
By default, each field is rendered with the notion of an observable scope (or namespace) into which the observables
are written and read from. If you have two forms rendering on the same page, using two separate
calls, you will have two separate observable namespaces by default. If you set an observable value in form1, it won't
be accessible by form2.
If you have a nested form, each field in the nested structure will use the same observable scope.
The observable scope can be gotten from a field using