Field Value Casting
As was discussed earlier, field values live in both Components (in JavaScript) and in the DOM and can by synced both ways. The DOM only stores strings (attributes and text), but components often want numbers, booleans, and arrays.
Qite handles this by keeping a typed value in
this.fields
and converting it
when crossing the DOM boundary. In other words:
- When Qite reads field values from the DOM, it casts strings into typed values.
- When Qite writes field values back into the DOM, it casts typed values into strings.
Strings in DOM, typed values in JavaScript
Consider:
<div data-component="Counter" data-count="0"></div>
data-count="0"
is a string in HTML. When Qite reads it into fields, it applies
casting and stores
count
as a number in
this.fields. Example:
this.fields.get("count"); // => 0
this.fields.get("count", { as_string: true }); // => "0"
In other words,
get()
returns the typed value by default, while
as_string
returns the raw string representation used in the DOM.
Writing values and DOM serialization
When you set a field from JavaScript:
this.fields.set("count", 10);
Qite keeps the typed value
10
in the component state. But when it writes that
value into DOM (which happens immediately) it converts it to a string using
the configured casting rules.
Most of the time you don't have to think about the string form, but it's important to remember that DOM bindings always end up writing strings.
Customizing casting
Casting is configurable.
Fields
accepts two dictionaries:
-
cast_from_stringdetermines how to convert values read from DOM into typed values -
cast_to_stringdetermines how to convert typed values into strings written to DOM
Each dictionary supports:
-
defaultfunction used for all fields - per-field overrides
A component may provide custom rules like this:
import BaseComponent from "/assets/vendor/qite/src/components/base_component.js";
export default class ProductComponent extends BaseComponent {
constructor(tree_node) {
super(tree_node);
this.fields.cast_from_string.price = (name, v) => Number.parseFloat(v);
this.fields.cast_to_string.price = (name, v) => v.toFixed(2);
}
}
This lets you keep the DOM representation predictable while making the typed value convenient for code. But the built-in default caster already handles common cases:
- integers and floats
-
trueandfalse -
empty strings as
null -
simple array syntax like
[1,2,3] -
special handling for the
disabled="disabled"HTML-attribute.
You only need custom casting when the defaults do not match your needs. The rule of thumb here is that this should probably be very rare and defaults should work for you most of the time.
Why Qite casts instead of leaving strings
Qite could treat everything as strings and force you to parse values manually, but that tends to spread conversion logic across the codebase.
Instead, fields apply casting in one place and keep the typed value stable.
Your component code reads
this.fields.get("count")
and gets a number.
The DOM still shows something readable, and the conversion rules stay explicit.
Methods you will commonly use
-
this.fields.get(name, { as_string: true })returns the raw string value. -
this.fields.cast_from_string[name] = fnoverrides parsing for a field. -
this.fields.cast_to_string[name] = fnoverrides serialization for a field.