docs
Loading...
Searching...
No Matches
Binding< T >

#include <Ultralight/dom/data/Binding.h>

Overview

template<typename T>
class ultralight::dom::data::Binding< T >

A handle that keeps an instance bound to pages and registers its input handlers.

A Binding keeps a native instance bound under the name page markup uses for as long as you keep the handle. It's where you register the handlers for that instance's edits and actions from the page.

Store the handle alongside your data to keep the binding active for the lifetime of your component.

This HUD component stores its binding as a member variable and routes an action to a member function:

class Hud {
public:
explicit Hud(dd::Context& ctx)
: binding_(ctx.Bind("player", player_)
.OnAction<"usePotion">(&Player::UsePotion)) {}
private:
Player player_;
dd::Binding<Player> binding_; // unbinds when the Hud is destroyed
};
Binding & OnAction(Fn &&fn) &
Register the handler for an action (replacing any earlier one).
Definition Binding.h:506

Handling Input

Call OnChange() to handle edits to an Editable field from a ul-value form control on the page. The handler receives the new value, but the library never writes directly to your data. Store the value in your instance to accept the edit, or leave the field unchanged to decline it and let the control snap back at the end of the sync.

This handler accepts volume edits by writing the new value back to the settings struct:

dd::Binding settings_binding = ctx.Bind("settings", settings);
settings_binding.OnChange<"volume">([&](double volume) {
settings.volume = volume; // storing the value accepts the edit
});

Call OnAction() to receive actions triggered by ul-on markup on the page or posted through PostAction(). A dotted name like "items.drop" routes actions from list rows. Handlers run during Context::Sync() on the context's home thread, delivering all value edits before running any actions. Registering a handler for a field or action that already has one replaces the previous handler.

Handler Forms

Both OnChange() and OnAction() route events to any of these targets:

  • A callable receives the event directly. Pass a lambda or function object that accepts the field value, the action payload, or no arguments.
  • A borrowed receiver calls a member function on an existing object. The library doesn't copy the object, so you must keep it alive while the binding exists.
  • A smart pointer manages receiver lifetime. An owning pointer like std::shared_ptr keeps the target alive, while a std::weak_ptr skips deliveries once its object is gone.
  • A member function of the bound type runs on the bound instance. It does nothing if you bound a const instance.

Posting Actions from Native Code

Call PostAction() to send an action from native code as if page markup triggered it. The action enters the context's action queue and reaches its handler during the next Context::Sync(). PostAction() is safe to call from any thread, which lets background threads hand work to the thread that owns the data. It returns false if the queue is full or if the binding stopped working.

This queues an action for delivery at the next sync:

// From any thread (eg, the input thread's potion hotkey):
binding.PostAction<"usePotion">();

Binding Lifetime

Destroying a Binding unbinds the instance and releases its handlers.

The unbind timing depends on which thread destroys the handle:

  • On the home thread, unbinding happens immediately. The context stops reading the instance right away.
  • From any other thread, unbinding takes effect at the start of the next Context::Sync(). The binding receives no further input during that synchronization cycle.

Binding the same name again replaces the earlier binding, and destroying the Context ends all its bindings. A replaced binding or one whose Context was destroyed remains safe to hold, but its handlers are dropped and PostAction() returns false.

Inspect the state of a handle using these methods:

  • IsAlive() checks whether the binding is active. It returns false when the binding was replaced or its Context was destroyed, even though the bool test stays true.
  • IsEmpty() checks whether the handle holds nothing. It returns true after a move or when Context::Bind() fails.

This checks whether a binding remains active after another component bound the same name:

dd::Binding hud = ctx.Bind("player", player);
dd::Binding menu = ctx.Bind("player", player); // replaces hud's binding
if (!hud.IsAlive())
Log("hud's binding was replaced");
Note
Actions are requests that can arrive after the state that prompted them changed, so your handler should verify that prerequisites still hold before applying the request.
Warning
Calling ulDOMDataBindingSetChangeCallback() or ulDOMDataBindingSetActionCallback() on raw() replaces this Binding's typed handlers, and registering typed handlers replaces any C callbacks.
See also
dom::data::Context::Bind(), dom::data::Context::PostAction(), dom::data::ActionInfo, dom::data::Value, dom::data::Editable

Public Types

using described_type = T
 The bound type.

Static Public Member Functions

static Binding Adopt (ULDOMDataBinding handle)
 Wrap a C handle you own, taking ownership of it.
static Binding FromBorrowed (ULDOMDataBinding handle)
 Wrap a C handle someone else owns (eg, another Binding's raw()), adding a reference.

Public Member Functions

 Binding ()=default
 Create an empty Binding.
 Binding (const Binding &)=delete
Binding & operator= (const Binding &)=delete
 Binding (Binding &&other) noexcept
 Move constructor (other becomes empty).
Binding & operator= (Binding &&other) noexcept
 Move assignment (releases the binding this one held, then takes over other's).
 ~Binding ()
 Destroy this Binding (see Binding Lifetime in the class description).
 operator bool () const
 Whether or not this Binding holds a binding (false for an empty Binding, eg, after a move or a failed Context::Bind()).
bool IsEmpty () const
 Whether or not this Binding holds nothing (eg, after a move or a failed Context::Bind()).
bool IsAlive () const
 Whether or not this Binding still works.
template<ultralight::detail::FixedString Field, typename Fn>
requires (!std::is_member_pointer_v<std::decay_t<Fn>>)
Binding & OnChange (Fn &&fn) &
 Register the handler for edits to an Editable field (replacing any earlier one).
template<ultralight::detail::FixedString Field, typename C, typename M>
requires (std::is_member_function_pointer_v<M> && !LockableHolder<C>)
Binding & OnChange (C &receiver, M method) &
 Register a member function of receiver as the handler for edits to an Editable field.
template<ultralight::detail::FixedString Field, typename H, typename M>
requires (LockableHolder<H> && std::is_member_function_pointer_v<M>)
Binding & OnChange (H holder, M method) &
 Register a member function as the handler for edits to an Editable field, called through a smart pointer.
template<ultralight::detail::FixedString Field, typename M>
requires std::is_member_function_pointer_v<M>
Binding & OnChange (M method) &
 Register a member function of the bound type as the handler for edits to an Editable field, called on the bound instance.
template<ultralight::detail::FixedString Field, typename... A>
Binding OnChange (A &&... args) &&
 Register the handler for edits to an Editable field on a Binding you just created.
template<ultralight::detail::FixedString Name, typename Fn>
requires (!std::is_member_pointer_v<std::decay_t<Fn>>)
Binding & OnAction (Fn &&fn) &
 Register the handler for an action (replacing any earlier one).
template<ultralight::detail::FixedString Name, typename C, typename M>
requires (std::is_member_function_pointer_v<M> && !LockableHolder<C>)
Binding & OnAction (C &receiver, M method) &
 Register a member function of receiver as the handler for an action.
template<ultralight::detail::FixedString Name, typename H, typename M>
requires (LockableHolder<H> && std::is_member_function_pointer_v<M>)
Binding & OnAction (H holder, M method) &
 Register a member function as the handler for an action, called through a smart pointer.
template<ultralight::detail::FixedString Name, typename M>
requires std::is_member_function_pointer_v<M>
Binding & OnAction (M method) &
 Register a member function of the bound type as the handler for an action, called on the bound instance.
template<ultralight::detail::FixedString Name, typename... A>
Binding OnAction (A &&... args) &&
 Register the handler for an action on a Binding you just created.
template<ultralight::detail::FixedString Field>
Binding & RemoveChangeHandler () &
 Remove the handler for edits to an Editable field (if there is one).
template<ultralight::detail::FixedString Field>
Binding RemoveChangeHandler () &&
 Remove the handler for edits to an Editable field on a Binding you just created.
template<ultralight::detail::FixedString Name>
Binding & RemoveActionHandler () &
 Remove the handler for an action (if there is one).
template<ultralight::detail::FixedString Name>
Binding RemoveActionHandler () &&
 Remove the handler for an action on a Binding you just created.
template<ultralight::detail::FixedString Name>
bool PostAction ()
 Send one of this binding's actions that has no payload, as if the page fired it.
template<ultralight::detail::FixedString Name>
bool PostAction (const detail::ActionPayloadArg< T, Name > &payload)
 Send one of this binding's actions with its payload, as if the page fired it.
std::string name () const
 Get the binding name.
ULDOMDataBinding raw () const
 Get the C handle, for passing to the <Ultralight/CAPI/CAPI_DOMData.h> functions.
ULDOMDataBinding LeakRef ()
 Give up ownership of the C handle and return it.

Friends

class Context

Member Typedef Documentation

◆ described_type

template<typename T>
using described_type = T

The bound type.

Constructor & Destructor Documentation

◆ Binding() [1/3]

template<typename T>
Binding ( )
default

Create an empty Binding.

◆ Binding() [2/3]

template<typename T>
Binding ( const Binding< T > & )
delete

◆ Binding() [3/3]

template<typename T>
Binding ( Binding< T > && other)
inlinenoexcept

Move constructor (other becomes empty).

Parameters
otherThe Binding to move from.

◆ ~Binding()

template<typename T>
~Binding ( )
inline

Destroy this Binding (see Binding Lifetime in the class description).

Member Function Documentation

◆ Adopt()

template<typename T>
Binding Adopt ( ULDOMDataBinding< T > handle)
inlinestatic

Wrap a C handle you own, taking ownership of it.

Parameters
handleA handle from the C API that you would otherwise destroy with ulDestroyDOMDataBinding() (NULL gives an empty Binding).
Returns
Returns a Binding that releases handle when it's done.

◆ FromBorrowed()

template<typename T>
Binding FromBorrowed ( ULDOMDataBinding< T > handle)
inlinestatic

Wrap a C handle someone else owns (eg, another Binding's raw()), adding a reference.

Parameters
handleThe borrowed handle (NULL gives an empty Binding).
Returns
Returns a Binding with its own reference.

◆ IsAlive()

template<typename T>
bool IsAlive ( ) const
inline

Whether or not this Binding still works.

Returns
Returns false for an empty Binding, or one that stopped working (its binding name was bound again, or its Context was destroyed).
Note
Safe to call from any thread.

◆ IsEmpty()

template<typename T>
bool IsEmpty ( ) const
inline

Whether or not this Binding holds nothing (eg, after a move or a failed Context::Bind()).

Returns
Returns true for an empty Binding.
Note
Safe to call from any thread.

◆ LeakRef()

template<typename T>
ULDOMDataBinding LeakRef ( )
inline

Give up ownership of the C handle and return it.

This Binding becomes empty.

Returns
Returns the handle. You must call ulDestroyDOMDataBinding() when finished.

◆ name()

template<typename T>
std::string name ( ) const
inline

Get the binding name.

Returns
Returns the binding name, or an empty string for an empty Binding or one whose name was bound again.
Note
Call this on the home thread (unlike PostAction(), which is safe from any thread).

◆ OnAction() [1/5]

template<typename T>
template<ultralight::detail::FixedString Name, typename... A>
Binding OnAction ( A &&... args) &&
inlinenodiscard

Register the handler for an action on a Binding you just created.

This lets a chain start at Context::Bind() and end in the variable you keep. It takes the same arguments as the other forms of OnAction().

Parameters
argsThe handler (a callable, an object or smart pointer and a member function, or a member function of the bound type).
Returns
Returns this Binding by value.

◆ OnAction() [2/5]

template<typename T>
template<ultralight::detail::FixedString Name, typename C, typename M>
requires (std::is_member_function_pointer_v<M> && !LockableHolder<C>)
Binding & OnAction ( C & receiver,
M method ) &
inline

Register a member function of receiver as the handler for an action.

Works like the callable form of OnAction().

Parameters
receiverThe object to call method on. It isn't copied, so keep it alive while the handler can run.
methodThe member function to call.
Returns
Returns this Binding (for chaining).

◆ OnAction() [3/5]

template<typename T>
template<ultralight::detail::FixedString Name, typename Fn>
requires (!std::is_member_pointer_v<std::decay_t<Fn>>)
Binding & OnAction ( Fn && fn) &
inline

Register the handler for an action (replacing any earlier one).

The handler runs during Context::Sync() after all changes, in the order the actions fired. Its parameter list decides what it receives:

b.OnAction<"voteSkip">([&] { match.VoteSkip(); }); // nothing
b.OnAction<"moveItem">([&](const MoveItem& move) { ... }); // the payload
b.OnAction<"roster.focusPlayer">([&](const ScoreRow& row) { ... }); // the row
b.OnAction<"roster.focusPlayer">([&](int64_t key) { ... }); // the row key
b.OnAction<"save">([&](dd::Value payload, dd::ActionInfo info) { ... });
ContainerSpec< Children... > row(ContainerOptions options, Children... children)
Describe a row container with child elements.
Definition Builder.h:125
  • No parameters works for every action (any payload is ignored).
  • The declared payload (a struct by const reference, or a scalar like double by value). An action whose payload doesn't match is dropped. Actions from ul-on:* markup have no payload, so this form never receives them.
  • dd::Value holds the payload. You can add a dd::ActionInfo parameter after it (the action name and row key).
  • The row type (by const reference, for a row action) holds the row's values as of the last Context::Sync(). The action is dropped if no row has that key anymore (or, in a list without keys, that position).
  • The row key (for a row action) is an int64_t (in a list without keys, the row's position when the page fired the action) or a std::string_view for string keys (valid only during the call).

A row action on a list without keys addresses the row by its position when the page fired it, so rows added or removed before the next Sync() make it reach another row (the page warns when it compiles one). Declare a key for a list whose rows can move.

The row type form rebuilds the row, so the row type must be default-constructible and every field in its schema must read a data member (a member pointer or a Reflect() field) of a bool, number, enum (only when ULTRALIGHT_REFLECTION is 1), StyleValue, or Color type, or of a string type constructible from a const char* and a length (eg, std::string). A row with a list, a nested object, a Var(), a getter or lambda accessor, or a std::string_view member doesn't compile in this form, so take the row key instead.

A dotted name (list.action) addresses an action of a list's row type. Only one level is supported, so actions of a nested object or of a list inside a row can't be registered. The name and the handler are checked at compile time, and a parameter must have one of these types exactly (eg, a bool parameter for a double payload doesn't compile).

Parameters
fnThe handler.
Returns
Returns this Binding (for chaining).

◆ OnAction() [4/5]

template<typename T>
template<ultralight::detail::FixedString Name, typename H, typename M>
requires (LockableHolder<H> && std::is_member_function_pointer_v<M>)
Binding & OnAction ( H holder,
M method ) &
inline

Register a member function as the handler for an action, called through a smart pointer.

Works like the callable form of OnAction().

Parameters
holderThe smart pointer to the object (copied). A std::shared_ptr keeps its object alive while the handler is registered. A std::weak_ptr skips deliveries once its object is gone.
methodThe member function to call.
Returns
Returns this Binding (for chaining).

◆ OnAction() [5/5]

template<typename T>
template<ultralight::detail::FixedString Name, typename M>
requires std::is_member_function_pointer_v<M>
Binding & OnAction ( M method) &
inline

Register a member function of the bound type as the handler for an action, called on the bound instance.

Works like the callable form of OnAction(). The handler runs only when Context::Bind() got an instance it can change (see Handler Forms in the class description).

Parameters
methodThe member function to call.
Returns
Returns this Binding (for chaining).

◆ OnChange() [1/5]

template<typename T>
template<ultralight::detail::FixedString Field, typename... A>
Binding OnChange ( A &&... args) &&
inlinenodiscard

Register the handler for edits to an Editable field on a Binding you just created.

This lets a chain start at Context::Bind() and end in the variable you keep. It takes the same arguments as the other forms of OnChange().

Parameters
argsThe handler (a callable, an object or smart pointer and a member function, or a member function of the bound type).
Returns
Returns this Binding by value.

◆ OnChange() [2/5]

template<typename T>
template<ultralight::detail::FixedString Field, typename C, typename M>
requires (std::is_member_function_pointer_v<M> && !LockableHolder<C>)
Binding & OnChange ( C & receiver,
M method ) &
inline

Register a member function of receiver as the handler for edits to an Editable field.

Works like the callable form of OnChange().

Parameters
receiverThe object to call method on. It isn't copied, so keep it alive while the handler can run.
methodThe member function to call.
Returns
Returns this Binding (for chaining).

◆ OnChange() [3/5]

template<typename T>
template<ultralight::detail::FixedString Field, typename Fn>
requires (!std::is_member_pointer_v<std::decay_t<Fn>>)
Binding & OnChange ( Fn && fn) &
inline

Register the handler for edits to an Editable field (replacing any earlier one).

The handler runs during Context::Sync() after the user edits a ul-value control bound to the field. It runs at most once per field per Sync (with the latest value) and before any action. Store the value in your instance to accept it:

b.OnChange<"volume">([&](float v) { settings.volume = v; audio.SetVolume(v); });

The handler takes the value as one of these:

  • The field's type (or int64_t or double for a number field).
  • const String& for a string field, or std::string_view for a std::string field (valid only during the call).
  • ultralight::Color for a color field (its only form).
  • dd::Value for any field except a color.

A parameter of another type doesn't compile, even one the value converts to (eg, bool for a number field).

If the field has a validator (see Validate()), the handler gets the value it accepted.

Parameters
fnThe handler.
Returns
Returns this Binding (for chaining).
Note
The field name and the handler are checked at compile time. The field must be an Editable bool, number, string, enum, or color field of the bound type itself (not a row or a nested object).
Warning
For a field whose type has your own ValueTraits specialization, a handler that takes that type still compiles when the type can be constructed from the kind's C++ type (eg, double). The handler then receives the raw value converted by that constructor rather than your ValueTraits specialization. Take the kind's C++ type or a dd::Value instead (see ValueTraits).

◆ OnChange() [4/5]

template<typename T>
template<ultralight::detail::FixedString Field, typename H, typename M>
requires (LockableHolder<H> && std::is_member_function_pointer_v<M>)
Binding & OnChange ( H holder,
M method ) &
inline

Register a member function as the handler for edits to an Editable field, called through a smart pointer.

Works like the callable form of OnChange().

Parameters
holderThe smart pointer to the object (copied). A std::shared_ptr keeps its object alive while the handler is registered. A std::weak_ptr skips deliveries once its object is gone.
methodThe member function to call.
Returns
Returns this Binding (for chaining).

◆ OnChange() [5/5]

template<typename T>
template<ultralight::detail::FixedString Field, typename M>
requires std::is_member_function_pointer_v<M>
Binding & OnChange ( M method) &
inline

Register a member function of the bound type as the handler for edits to an Editable field, called on the bound instance.

Works like the callable form of OnChange(). The handler runs only when Context::Bind() got an instance it can change (see Handler Forms in the class description).

Parameters
methodThe member function to call.
Returns
Returns this Binding (for chaining).

◆ operator bool()

template<typename T>
operator bool ( ) const
inlineexplicit

Whether or not this Binding holds a binding (false for an empty Binding, eg, after a move or a failed Context::Bind()).

Note
It stays true after the binding name is bound again (see Binding Lifetime in the class description). Use IsAlive() to check whether the binding still works.

◆ operator=() [1/2]

template<typename T>
Binding & operator= ( Binding< T > && other)
inlinenoexcept

Move assignment (releases the binding this one held, then takes over other's).

Parameters
otherThe Binding to move from.
Returns
Returns this Binding.

◆ operator=() [2/2]

template<typename T>
Binding & operator= ( const Binding< T > & )
delete

◆ PostAction() [1/2]

template<typename T>
template<ultralight::detail::FixedString Name>
bool PostAction ( )
inline

Send one of this binding's actions that has no payload, as if the page fired it.

b.PostAction<"voteSkip">();

The action reaches its handler at the next Context::Sync(), like an action from the page. The name is checked at compile time and must be an action of the bound type itself (not a list.action name).

Returns
Returns true if the action was queued. Returns false for an empty Binding, one that stopped working (see IsAlive()), or a full action queue.
Note
Safe to call from any thread.
See also
Context::PostAction()

◆ PostAction() [2/2]

template<typename T>
template<ultralight::detail::FixedString Name>
bool PostAction ( const detail::ActionPayloadArg< T, Name > & payload)
inline

Send one of this binding's actions with its payload, as if the page fired it.

b.PostAction<"moveItem">({ .from = a, .to = b }); // dd::Action<MoveItem>
b.PostAction<"seek">(0.5f); // dd::Action<double>

Works like the form without a payload.

Parameters
payloadThe payload (of the action's declared type).
Returns
Returns true if the action was queued. Returns false for an empty Binding, one that stopped working (see IsAlive()), or a full action queue.
Note
Safe to call from any thread.

◆ raw()

template<typename T>
ULDOMDataBinding raw ( ) const
inline

Get the C handle, for passing to the <Ultralight/CAPI/CAPI_DOMData.h> functions.

Returns
Returns the handle (NULL for an empty Binding). This Binding still owns it, so don't destroy it.

◆ RemoveActionHandler() [1/2]

template<typename T>
template<ultralight::detail::FixedString Name>
Binding & RemoveActionHandler ( ) &
inline

Remove the handler for an action (if there is one).

The action name is checked at compile time like OnAction() (a dotted list.action name works too).

Returns
Returns this Binding (for chaining).

◆ RemoveActionHandler() [2/2]

template<typename T>
template<ultralight::detail::FixedString Name>
Binding RemoveActionHandler ( ) &&
inlinenodiscard

Remove the handler for an action on a Binding you just created.

Returns
Returns this Binding by value.

◆ RemoveChangeHandler() [1/2]

template<typename T>
template<ultralight::detail::FixedString Field>
Binding & RemoveChangeHandler ( ) &
inline

Remove the handler for edits to an Editable field (if there is one).

The field name is checked at compile time like OnChange().

Returns
Returns this Binding (for chaining).

◆ RemoveChangeHandler() [2/2]

template<typename T>
template<ultralight::detail::FixedString Field>
Binding RemoveChangeHandler ( ) &&
inlinenodiscard

Remove the handler for edits to an Editable field on a Binding you just created.

Returns
Returns this Binding by value.

◆ Context

template<typename T>
friend class Context
friend

The documentation for this class was generated from the following file: