Observables

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).

Simple Listener

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. When 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.

{% raw %} {% endraw %}

Using an Observable and a Data Source

This example does the same thing as the one above but uses a data source to load values for the team field. After rendering, it sets up an event listener for the change event. When the city 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.

{% raw %} {% endraw %}

Using Observables Programmatically

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.getObservableScope().

  • field.unsubscribe([scope], id, fn)

    Unsubscribes a function as an event handler for an observable identified by it's ID.

  • field.observable([scope], id)

    Retrieves an observable. The observable has methods get() (which can return null), set(value) and clear(). Note that setting or changing the value of an observable will cause any observable subscribers to trigger.

  • field.clearObservable([scope], id)

    Clears the value of an observable. This is equivalent to observable(id).clear(). Note that setting or changing the value of an observable will cause any observable subscribers to trigger.

Observable Scope

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 $.alpaca() 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 field.getObservableScope().