live

Live-updating templates driven by MQTT topics.

Note

This scomp is provided by module#mod_mqtt, which must be enabled.

This tag renders templates that are automatically re-rendered after a publication to an MQTT topic.

Example

An example of a template showing the newest content of a resource:

{% live template="_detail.tpl" topic=id id=id %}

This renders the template _detail.tpl. If the resource with id id is updated then the template will be replaced with a freshly rendered template.

The tag can subscribe to multiple topics at once.

Add the argument catinclude to do a tag#catinclude instead of a normal tag#include. For a catinclude the argument id must be present:

{% live template="_detail.tpl" topic=id catinclude id=id %}

Arguments

Use either template to render a template or, without template, supply postback, delegate, and target to call an event handler.

ArgumentDefaultDescription
topicNoneMQTT topic to subscribe to. Repeat this argument for multiple topics. Accepts a topic string, a list of topic segments, a resource id, or an edge-topic tuple; see Live topics below.
templateNoneTemplate to render on notifications. When present, selects template mode.
catincludefalseSelect a category-specific version of template, using the resource passed as id.
idNoneTemplate variable identifying the resource. Required when using catinclude; does not automatically subscribe to that resource's topic.
targetGenerated element id in template modeDOM element id to update, without #. When supplied, no wrapper is generated: the caller must provide the target element. Required in postback mode.
elementdivHTML tag for the generated wrapper in template mode. Ignored when target is supplied. An empty string suppresses the wrapper; the template must then provide an element with the generated target id.
methodupdate in template modeHow to insert or update rendered HTML; see Update methods below. In postback mode the delegate handles rendering.
postbackNoneMessage delivered in #postback{message = Message, target = Target} to the delegate. Required when template is omitted.
delegateNoneModule implementing event/2 for the postback. Required when template is omitted.
throttle0Non-negative integer interval in milliseconds between refreshes during a burst. 0 disables throttling; see Throttling updates below.

In template mode, arguments other than topic, template, catinclude, element, method, and throttle are passed as template variables. Pass any required variables explicitly: the surrounding template's variables are not automatically inherited. The scomp also supplies target and is_live_update. The latter is false for the initial render and true for notification-driven renders.

Update methods

MethodInitial renderOn notification
updateRender the template at the tag's location.Replace the target's contents.
updateonlyNo template render.Replace the target's contents.
topNo template render.Prepend rendered HTML inside the target.
bottomNo template render.Append rendered HTML inside the target.
beforeNo template render.Insert rendered HTML before the target.
afterNo template render.Insert rendered HTML after the target.
patchNo template render.Update the target through Cotonic's UI model.

Without an explicit target, a wrapper is generated even for methods that do not render the template initially. With an explicit target, place the live tag inside that element if using update and its initial render is wanted there.

For example, append a rendered item to an existing list on each notification:

<ul id="{{ #items }}"></ul>
{% live topic="bridge/origin/public/items"
        template="_item.tpl" target=#items method="bottom"
%}

In notification-driven template renders, a map or proplist MQTT payload is available as query arguments (q). Other payload values are available as q.payload. These values are untrusted input: escape them when outputting HTML.

To handle notifications in Erlang instead of rendering a template:

<div id="{{ #status }}"></div>
{% live topic="bridge/origin/public/status"
        postback={refresh_status id=id}
        delegate="mod_example" target=#status throttle=3000
%}

The delegate receives the configured message and target, and can read the notification's topic and MQTT message using z_context:get_q/2 with the binary keys topic and message. Extra live-tag arguments are not automatically added to the postback message; include them in postback={...} explicitly. The target must remain in the DOM for the subscription to stay active.

Throttling updates

Use throttle=3000 to limit refreshes during a burst to once every three seconds. The first notification refreshes after a short delay (at most 100 milliseconds), then the full interval starts from that refresh. After no notifications for a full interval, the next notification refreshes quickly again. Notifications are combined using the latest topic and message. Continuous events do not postpone the refresh, and the last event is included even if events stop. Initial rendering is unchanged. The default is 0 (no throttling).

The interval is shared by all topics on one live tag. Separate live tags have independent intervals. The argument applies to both template rendering and the postback/delegate form of the live tag; it is not passed to the rendered template as a variable. Throttling combines browser refresh requests, not the MQTT publications themselves.

Use this for templates showing current state, not event-by-event inserts:

{% live template="_detail.tpl" topic=id id=id throttle=3000 %}

Live topics

Any MQTT topic can be used. The topics are interpreted as local to the page. There are three special topics:

  • Use any integer to map to the resource’s update topic. For example if id is 1234 then the topic will be bridge/origin/model/rsc/event/1234
  • Use the tuple {object id=...} to listen to changes of outgoing connections from a page. An example of a mapped topic is bridge/origin/model/edge/event/1234/o/+`. Use the tuple {object id=... predicate=...} to listen to changes of a specific predicate of a page. An example of a mapped topic is bridge/origin/model/edge/event/1234/o/author
  • Use the tuple {subject id=... } to listen to changes of incoming connections to a page. An example of a mapped topic is bridge/origin/model/edge/event/1234/s/author

Note that the topics refer to client side topics, that is why the bridge is used to subscribe to server side model events.

It is possible to subscribe to client topics like "my/local/topic" and have the actions triggered by publish to cotonic.broker.publish("my/local/topic", {}); (with any payload).

Live actions

It is possible to wire actions or postbacks to a MQTT topic.

Use the scomp#wire with argument type={mqtt topic=... topic=...} to connect to one or more MQTT topics. Add throttle inside type={mqtt ...} to combine rapid notifications before executing the wire's actions and postback. It uses the same millisecond interval, quick first event, and idle reset as the live tag. All topics of one wire share an interval; separate wires are independent. The latest notification supplies the event arguments. Omit throttle or use 0 for immediate execution of every notification:

{% wire type={mqtt topic="bridge/origin/public/hello" throttle=3000}
        action={growl text="hello"}
%}

And in Erlang this will trigger the above growl:

z_mqtt:publish(<<"public/hello">>, <<>>, z:c(mysite)).

Edit on GitHub

Referred by

Release notes

0.11.0

Note

Scomp

wire

Connect actions and events to a HTML element.

Developer guide

Browser/server interaction

There are multiple ways to set up interaction between server-side Zotonic code and client-side JavaScript.