Appearance
@xproperty Decorator
The @xproperty decorator is used to make properties in widget classes reactive. When properties marked with this decorator change, the DOM is automatically updated and template bindings are refreshed.
Basic Usage
typescript
import { Widget, xproperty } from '@xcons/widget';
@Widget({
selector: '.my-widget',
template: '<span x:text="message">Default message</span>'
})
export class MyWidget {
@xproperty()
message: string = 'Hello World!';
}Syntax
Simple Property
typescript
@xproperty()
propertyName: type = defaultValue;Configured Property
typescript
@xproperty({
reflect: true,
attribute: 'custom-attribute',
hasChanged: (newVal, oldVal) => newVal !== oldVal
})
propertyName: type = defaultValue;Property Options
typescript
interface PropertyOptions {
reflect?: boolean; // Reflect to HTML attribute
attribute?: string; // Custom attribute name
hasChanged?: (value: any, oldValue: any) => boolean; // Change detection
}Usage Examples
Simple Reactive Properties
Different Data Types
Property Options Usage
Usage with @xcomputed
Property Change Tracking
onWidgetPropertyChanged Lifecycle Hook
typescript
@Widget({
selector: '.tracked-widget',
template: `
<div>
<input type="text" x:attr:value="message">
<p x:text="message">-</p>
</div>
`
})
export class TrackedWidget {
@xproperty()
message: string = 'Hello';
onWidgetPropertyChanged(propertyKey?: string, oldValue?: any, newValue?: any): void {
this.safeLog('info', `Property changed: ${propertyKey}`, {
from: oldValue,
to: newValue
});
// Custom operations
if (propertyKey === 'message' && newValue.length > 50) {
this.safeLog('warn', 'Message too long!');
}
}
}Manual Update Triggering
typescript
import { triggerUpdate } from '@xcons/widget';
@Widget({
selector: '.manual-update-widget',
template: '<p x:text="data">-</p>'
})
export class ManualUpdateWidget {
@xproperty()
data: any[] = [];
addItem(item: any): void {
// Update data
this.data.push(item);
// Manually trigger reactive update
triggerUpdate(this);
}
}Performance Tips
Effective Change Detection
typescript
// ✅ Good - Reference comparison for simple values
@xproperty({
hasChanged: (newVal, oldVal) => newVal !== oldVal
})
simpleValue: string = '';
// ✅ Good - Deep comparison for complex objects
@xproperty({
hasChanged: (newVal, oldVal) =>
JSON.stringify(newVal) !== JSON.stringify(oldVal)
})
complexObject: any = {};
// ✅ Good - Threshold value check
@xproperty({
hasChanged: (newVal: number, oldVal: number) =>
Math.abs(newVal - oldVal) >= 0.01
})
preciseNumber: number = 0;Batch Updates
Multiple property changes result in a single DOM update:
typescript
updateMultiple(): void {
// All changes are made at once
this.prop1 = 'value1';
this.prop2 = 'value2';
this.prop3 = 'value3';
// DOM is updated only once
}Nested Reactive Objects
Important Notes
✅ Do's
- Use
@xpropertyto automatically reflect property changes to the DOM - Add
@xpropertyfor all properties used in the template - Use
@xcomputedfor computed values - Use custom
hasChangedfunction for performance
❌ Don'ts
- Don't directly change properties and call
triggerUpdate(unless necessary) - Don't write overly complex
hasChangedfunctions - Don't make unnecessary properties reactive
Summary
With the @xproperty decorator:
- ✅ Automatic reactivity - Automatic DOM updates on property changes
- ✅ Template integration - Seamless work with template bindings
- ✅ HTML attribute reflection - With
reflectoption - ✅ Customizable change detection -
hasChangedfunction - ✅ Performance optimization - Batch updates and smart change detection
- ✅ Type safety - TypeScript support
This decorator automates your widget's state management and UI updates.