fast
fast copied to clipboard
feat(fast-html): allow granular observerMap configuration via TemplateElement options
🙋 Feature Request
The ObserverMap settings for the TemplateElement options currently only accepts "all", which forces all bindings present in the template to be observed. This currently doesn't account for attributes, and it doesn't account for decorated @observable properties defined in the class.
🤔 Expected Behavior
Developers should have fine-grained control over which properties are observed by the ObserverMap. This includes:
- Selective property observation: Ability to specify which root properties from template bindings should be observed
- Exclusion patterns: Ability to exclude specific properties (e.g., internal/cached properties)
- Attribute observation: Option to observe element attributes in addition to template bindings
-
Opt-out capability: Ability to disable observation entirely with
"none" -
Backward compatibility: Existing
"all"option continues to work as before
Use Cases
- Performance optimization: Observe only the properties that need deep reactivity, avoiding unnecessary proxy overhead for static or rarely-changing data
-
Attribute integration: Include element attributes (e.g.,
@attrdecorated properties) in the observation system -
Selective observation: Observe user-facing data (
users,items) while excluding internal state (_cache,_metadata)
😯 Current Behavior
Currently, the only option is "all":
TemplateElement.options({
"some-element": {
observerMap: "all",
}
}).define({ name: "f-template" });
This observes all root properties found in template bindings but provides no way to:
- Observe only specific properties
- Exclude certain properties
- Include attributes
- Disable observation
💁 Possible Solution
Extend the observerMap option to accept multiple configuration formats:
1. String literal (backward compatible)
TemplateElement.options({
"some-element": {
observerMap: "all", // Observe all template bindings (current behavior)
// or
observerMap: "none", // Disable observation
}
}).define({ name: "f-template" });
2. Array of property names
TemplateElement.options({
"some-element": {
observerMap: ["users", "items"], // Observe only these root properties
}
}).define({ name: "f-template" });
3. Object with granular control
TemplateElement.options({
"some-element": {
observerMap: {
include: ["users", "items"], // Root properties to observe
exclude: ["_cache", "_internal"], // Properties to exclude
attributes: true, // Also observe element attributes
// or
attributes: ["data-id", "role"], // Specific attributes to observe
},
}
}).define({ name: "f-template" });
Type Definition
export const ObserverMapOption = {
all: "all",
none: "none",
} as const;
export interface ObserverMapConfig {
include?: string[]; // Root properties to observe
exclude?: string[]; // Root properties to exclude
attributes?: boolean | string[]; // Observe attributes (all or specific)
}
export type ObserverMapOption =
| (typeof ObserverMapOption)[keyof typeof ObserverMapOption] // "all" | "none"
| string[] // Array of property names
| ObserverMapConfig; // Object configuration
Implementation Notes
- The
Schemaclass already tracks all binding paths viaaddPath()and can provide root properties viagetRootProperties() - The
ObserverMapoperates at the root property level, defining observables on the class prototype - Filtering logic would be applied during
ObserverMapconstruction before callingdefineProperties() - Attribute observation would require integration with the
@attrdecorator system from@microsoft/fast-element