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

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

Overview

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

Handle passed to a type's static Sync function to control which fields are read during synchronization.

When Context::Sync() runs, the library normally reads every field of every bound instance through its schema. You can customize this process for any described type by declaring a static Sync function that takes your instance alongside a Model.

It provides access to previously synchronized values and lets you choose which fields to read. This avoids reading large containers or calling expensive accessors on frames where the underlying data hasn't changed.

This leaderboard reads its row collection only when its revision counter changes:

struct Score {
int64_t player_id = 0;
int points = 0;
};
struct Leaderboard {
int rev = 1; // bump it whenever rows change
std::string heading;
std::vector<Score> rows;
static constexpr auto schema = dd::Schema(
dd::Field("rev", &Leaderboard::rev, dd::Internal),
dd::Field("heading", &Leaderboard::heading),
dd::List("rows", &Leaderboard::rows, &Score::player_id));
static void Sync(const Leaderboard& b, dd::Model<Leaderboard> m) {
if (b.rev != m.Get<"rev">()) // compare before syncing rev
m.Sync<"rows">();
m.SyncAllExcept<"rows">(); // syncs rev and heading
}
};

Writing a Sync Function

You declare a static Sync function beside the type's schema, either inside the type itself or within its dom::data::TypeTraits specialization.

The library never resends unchanged values to attached pages, with or without a static Sync function. Skipping a field saves only the work of reading it in native code.

When you skip syncing a field, the page keeps its last synchronized value. For collections gated on a revision counter, tag the counter with dom::data::Internal in the schema. Markup can't bind an Internal entry, and schema tools leave it out.

Note
Compare a revision counter before syncing it, and start the counter at 1 rather than 0. Calling Sync() on the counter updates the recorded value, so comparing afterwards always finds them equal. Before the first sync, Get() returns 0, so starting at 0 skips the initial sync and leaves the list blank.

Three Kinds of Sync

Each function plays a distinct role during synchronization:

  • Context::Sync() coordinates the overall update cycle. You call it once per frame on the home thread to deliver page events to handlers and broadcast changed values to attached Views.
  • A type's static Sync function customizes the read step for that type. The library invokes it while inspecting an instance, passing the instance alongside a Model.
  • Model::Sync() reads a specific field from the instance and sends it if it changed. You call it inside your type's static Sync function, alongside SyncAll() to read every field and SyncAllExcept() to read every field except the ones you list.
Warning
A Model is valid only during the call to your type's static Sync function. Never store a Model or use it after the function returns.
See also
dom::data::Snapshot, dom::data::TypeTraits, dom::data::Internal, dom::data::Context::Sync()
Inheritance diagram for Model< T >:
Snapshot< T >

Public Member Functions

template<ultralight::detail::FixedString Name>
void Sync ()
 Sync one field by name.
void SyncAll ()
 Sync every field (what Context::Sync() does for a type without a Sync function).
template<ultralight::detail::FixedString... Names>
void SyncAllExcept ()
 Sync every field except the ones you list (eg, m.SyncAllExcept<"rows", "log">()).
template<ultralight::detail::FixedString Name, typename Arg>
void Set (const Arg &value)
 Set a field's value by name.
Public Member Functions inherited from Snapshot< T >
template<ultralight::detail::FixedString Name>
auto Get () const
 Get the value of a field or Var by name.

Additional Inherited Members

Public Types inherited from Snapshot< T >
using described_type = T
Static Public Member Functions inherited from Snapshot< T >
static constexpr const auto & schema ()
 Get the type's schema.
Protected Member Functions inherited from Snapshot< T >
template<ValueKind K>
auto ReadSlot (uint32_t slot) const
Static Protected Member Functions inherited from Snapshot< T >
template<ultralight::detail::FixedString Name>
static consteval size_t IndexOfChecked ()
Protected Attributes inherited from Snapshot< T >
detail::RecordOps * ops_

Member Function Documentation

◆ Set()

template<typename T>
template<ultralight::detail::FixedString Name, typename Arg>
void Set ( const Arg & value)
inline

Set a field's value by name.

This is how you send a field declared without an accessor (eg, dd::Field<int>("score")). It also works on any other field or Var with a single value.

Parameters
valueThe value to send. It must convert to the field's declared type.

◆ Sync()

template<typename T>
template<ultralight::detail::FixedString Name>
void Sync ( )
inline

Sync one field by name.

Reads the field from your instance and sends it to the page if it changed. A nested object or a list syncs each object or row through its own type's Sync function.

Note
Sync() on an action or on a field without an accessor is a compile error. Send a field without an accessor with Set().

◆ SyncAll()

template<typename T>
void SyncAll ( )
inline

Sync every field (what Context::Sync() does for a type without a Sync function).

Actions and fields without an accessor are skipped.

◆ SyncAllExcept()

template<typename T>
template<ultralight::detail::FixedString... Names>
void SyncAllExcept ( )
inline

Sync every field except the ones you list (eg, m.SyncAllExcept<"rows", "log">()).

Actions and fields without an accessor are skipped. A name that isn't in the schema is a compile error.


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