Rename Checkbox_Multiselect to Checkbox_Multiselect_Input
Implement template method pattern for Form_Input_Abstract 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
437
app/RSpade/upstream_changes/form_input_abstract_12_29.txt
Executable file
437
app/RSpade/upstream_changes/form_input_abstract_12_29.txt
Executable file
@@ -0,0 +1,437 @@
|
||||
FORM INPUT ABSTRACT - MIGRATION GUIDE
|
||||
Date: 2025-12-29
|
||||
|
||||
SUMMARY
|
||||
|
||||
This update standardizes form input component identification and establishes
|
||||
a formal event contract for value changes. The manual `.Widget` CSS class
|
||||
marker is replaced by the automatic `.Form_Input_Abstract` class that jqhtml
|
||||
adds to all components extending that base class.
|
||||
|
||||
Additionally, this update moves common boilerplate into the base class using
|
||||
a template method pattern. Concrete input classes now implement simple
|
||||
_get_value() and _set_value() methods instead of the full val() logic.
|
||||
|
||||
Key changes:
|
||||
- Remove class="Widget" from templates (automatic via inheritance)
|
||||
- Base class handles val() logic, buffering, and event triggers
|
||||
- Concrete classes implement _get_value(), _set_value(), _transform_value()
|
||||
- Call _mark_ready() in on_ready() to apply buffered values
|
||||
|
||||
Reference implementations are provided alongside this document:
|
||||
- form_input_abstract_12_29_reference.js - Complete base class
|
||||
- text_input_12_29_reference.js - Simple input example
|
||||
|
||||
AFFECTED FILES
|
||||
|
||||
Input component templates (remove class="Widget"):
|
||||
- rsx/theme/components/inputs/text/text_input.jqhtml
|
||||
- rsx/theme/components/inputs/select/select_input.jqhtml
|
||||
- rsx/theme/components/inputs/select/Select_Ajax_Input.jqhtml
|
||||
- rsx/theme/components/inputs/select/Select_Country_Input.jqhtml
|
||||
- rsx/theme/components/inputs/select/Select_State_Input.jqhtml
|
||||
- rsx/theme/components/inputs/select/select_with_description_input.jqhtml
|
||||
- rsx/theme/components/inputs/checkbox/checkbox_input.jqhtml
|
||||
- rsx/theme/components/inputs/checkbox_multiselect/checkbox_multiselect.jqhtml
|
||||
- rsx/theme/components/inputs/wysiwyg/wysiwyg_input.jqhtml
|
||||
- rsx/theme/components/inputs/photo/profile_photo_input.jqhtml
|
||||
- rsx/theme/components/inputs/repeater/repeater_simple_input.jqhtml
|
||||
- rsx/theme/components/inputs/select_user_role/select_user_role_input.jqhtml
|
||||
- Any custom input components in your application
|
||||
|
||||
Base class (implement template method pattern):
|
||||
- rsx/theme/components/inputs/form_input_abstract.js
|
||||
|
||||
Input component JavaScript (convert to template method):
|
||||
- All input component .js files that implement val()
|
||||
|
||||
Code that searches for .Widget:
|
||||
- rsx/theme/components/forms/rsx_form.js (vals() method)
|
||||
- Any custom code using .shallowFind('.Widget') or similar
|
||||
|
||||
CHANGES REQUIRED
|
||||
|
||||
1. Remove class="Widget" from Input Component Templates
|
||||
|
||||
All input components currently add class="Widget" manually. This is now
|
||||
redundant because jqhtml automatically adds the class name of any extended
|
||||
class. Components extending Form_Input_Abstract will automatically have
|
||||
the .Form_Input_Abstract class.
|
||||
|
||||
BEFORE:
|
||||
<Define:Text_Input class="Widget">
|
||||
|
||||
AFTER:
|
||||
<Define:Text_Input>
|
||||
|
||||
Search pattern to find affected files:
|
||||
grep -r 'class="Widget"' --include="*.jqhtml" rsx/
|
||||
|
||||
2. Update Code Searching for .Widget to Use .Form_Input_Abstract
|
||||
|
||||
Any code that finds input components via .Widget selector must be updated.
|
||||
|
||||
BEFORE:
|
||||
this.$.shallowFind('.Widget').each(function () {
|
||||
let component = $(this).component();
|
||||
if (component && 'val' in component) {
|
||||
// ...
|
||||
}
|
||||
});
|
||||
|
||||
AFTER:
|
||||
this.$.shallowFind('.Form_Input_Abstract').each(function () {
|
||||
let component = $(this).component();
|
||||
// val() is guaranteed by Form_Input_Abstract
|
||||
// ...
|
||||
});
|
||||
|
||||
Note: The 'val' in component check is no longer needed since all
|
||||
Form_Input_Abstract subclasses are required to implement _get_value()
|
||||
and _set_value(), and the base class provides val().
|
||||
|
||||
3. Update Form_Input_Abstract Base Class
|
||||
|
||||
The base class now implements the template method pattern, handling all
|
||||
common logic for buffering, events, and val() getter/setter.
|
||||
|
||||
See: form_input_abstract_12_29_reference.js
|
||||
|
||||
Key methods provided by base class:
|
||||
- on_create() - Initializes _pending_value and _is_ready
|
||||
- val() - Full getter/setter with buffering and event triggers
|
||||
- _mark_ready() - Apply buffered value, call from concrete on_ready()
|
||||
|
||||
Methods to override in concrete classes:
|
||||
- _get_value() - Return current DOM/component value (REQUIRED)
|
||||
- _set_value(value) - Set DOM/component value (REQUIRED)
|
||||
- _transform_value(value) - Transform pending value for getter (OPTIONAL)
|
||||
|
||||
4. Convert Concrete Input Classes to Template Method
|
||||
|
||||
Replace full val() implementation with simple _get_value() and _set_value().
|
||||
|
||||
BEFORE (full boilerplate in each class):
|
||||
class Text_Input extends Form_Input_Abstract {
|
||||
on_create() {
|
||||
this._pending_value = null;
|
||||
this._is_ready = false;
|
||||
}
|
||||
|
||||
val(value) {
|
||||
if (arguments.length === 0) {
|
||||
if (this._pending_value !== null) {
|
||||
return this._pending_value;
|
||||
}
|
||||
return this.$sid('input').val();
|
||||
}
|
||||
if (this._is_ready) {
|
||||
this.$sid('input').val(value || '');
|
||||
this._pending_value = null;
|
||||
} else {
|
||||
this._pending_value = value || '';
|
||||
}
|
||||
this.trigger('val', value);
|
||||
}
|
||||
|
||||
on_ready() {
|
||||
this._is_ready = true;
|
||||
if (this._pending_value !== null) {
|
||||
this.$sid('input').val(this._pending_value);
|
||||
this._pending_value = null;
|
||||
}
|
||||
|
||||
const that = this;
|
||||
this.$sid('input').on('input', function() {
|
||||
const value = that.val();
|
||||
that.trigger('input', value);
|
||||
that.trigger('val', value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
AFTER (template method pattern):
|
||||
class Text_Input extends Form_Input_Abstract {
|
||||
_get_value() {
|
||||
return this.$sid('input').val();
|
||||
}
|
||||
|
||||
_set_value(value) {
|
||||
this.$sid('input').val(value || '');
|
||||
}
|
||||
|
||||
on_ready() {
|
||||
this._mark_ready();
|
||||
|
||||
const that = this;
|
||||
this.$sid('input').on('input', function() {
|
||||
const value = that.val();
|
||||
that.trigger('input', value);
|
||||
that.trigger('val', value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Note: The concrete class no longer needs:
|
||||
- on_create() for _pending_value/_is_ready (handled by base)
|
||||
- val() method (handled by base)
|
||||
- Buffering logic (handled by base)
|
||||
- trigger('val') calls (handled by base)
|
||||
|
||||
The concrete class ONLY needs:
|
||||
- _get_value() - How to read the current value
|
||||
- _set_value() - How to write a value
|
||||
- on_ready() - Call _mark_ready() and setup user interaction events
|
||||
|
||||
5. Handle Value Transformation (Optional)
|
||||
|
||||
Some inputs need to transform the buffered value when returning it.
|
||||
For example, Checkbox_Input needs to convert boolean/string to
|
||||
checked_value/unchecked_value.
|
||||
|
||||
Override _transform_value() for this:
|
||||
|
||||
class Checkbox_Input extends Form_Input_Abstract {
|
||||
on_create() {
|
||||
super.on_create();
|
||||
this.checked_value = this.args.checked_value || '1';
|
||||
this.unchecked_value = this.args.unchecked_value || '0';
|
||||
}
|
||||
|
||||
_get_value() {
|
||||
const is_checked = this.$sid('input').prop('checked');
|
||||
return is_checked ? this.checked_value : this.unchecked_value;
|
||||
}
|
||||
|
||||
_set_value(value) {
|
||||
let should_check = false;
|
||||
if (typeof value === 'boolean') {
|
||||
should_check = value;
|
||||
} else if (value === this.checked_value || value === '1' || value === 1) {
|
||||
should_check = true;
|
||||
}
|
||||
this.$sid('input').prop('checked', should_check);
|
||||
}
|
||||
|
||||
_transform_value(value) {
|
||||
// Convert pending value to return format
|
||||
let should_check = false;
|
||||
if (typeof value === 'boolean') {
|
||||
should_check = value;
|
||||
} else if (value === this.checked_value || value === '1' || value === 1) {
|
||||
should_check = true;
|
||||
}
|
||||
return should_check ? this.checked_value : this.unchecked_value;
|
||||
}
|
||||
|
||||
on_ready() {
|
||||
this._mark_ready();
|
||||
|
||||
const that = this;
|
||||
this.$sid('input').on('change', function() {
|
||||
const value = that.val();
|
||||
that.trigger('input', value);
|
||||
that.trigger('val', value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
6. Handle Async Initialization
|
||||
|
||||
Some components initialize asynchronously (e.g., Wysiwyg_Input waits
|
||||
for Quill library). Call _mark_ready() when actually ready, not at
|
||||
the start of on_ready().
|
||||
|
||||
class Wysiwyg_Input extends Form_Input_Abstract {
|
||||
_get_value() {
|
||||
if (!this.quill) return '';
|
||||
return safe_html(this.quill.root.innerHTML);
|
||||
}
|
||||
|
||||
_set_value(value) {
|
||||
if (value) {
|
||||
this.quill.root.innerHTML = value;
|
||||
this.$sid('hidden_input').val(value);
|
||||
}
|
||||
}
|
||||
|
||||
_transform_value(value) {
|
||||
return safe_html(value);
|
||||
}
|
||||
|
||||
on_ready() {
|
||||
const that = this;
|
||||
|
||||
// Quill loads asynchronously
|
||||
quill_ready(function() {
|
||||
that._initialize_quill();
|
||||
that._mark_ready(); // Called AFTER quill is ready
|
||||
});
|
||||
}
|
||||
|
||||
_initialize_quill() {
|
||||
this.quill = new Quill(this.$sid('editor')[0], { ... });
|
||||
|
||||
this.quill.on('text-change', () => {
|
||||
this.$sid('hidden_input').val(this.quill.root.innerHTML);
|
||||
const value = this.val();
|
||||
this.trigger('input', value);
|
||||
this.trigger('val', value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
7. Components with Complex State
|
||||
|
||||
Some components (like Profile_Photo_Input) use this.state for internal
|
||||
tracking. These work fine with the template method pattern:
|
||||
|
||||
class Profile_Photo_Input extends Form_Input_Abstract {
|
||||
on_create() {
|
||||
super.on_create();
|
||||
this.state = {
|
||||
attachment_key: '',
|
||||
thumbnail_url: ''
|
||||
};
|
||||
}
|
||||
|
||||
_get_value() {
|
||||
return this.state.attachment_key || '';
|
||||
}
|
||||
|
||||
_set_value(value) {
|
||||
this.state.attachment_key = value || '';
|
||||
// Update thumbnail URL, trigger re-render, etc.
|
||||
this.render();
|
||||
}
|
||||
|
||||
on_ready() {
|
||||
this._mark_ready();
|
||||
// Setup upload handlers...
|
||||
}
|
||||
}
|
||||
|
||||
8. Components that Extend Other Inputs
|
||||
|
||||
Components that extend other inputs (like Select_Ajax_Input extends
|
||||
Select_Input) should call super methods appropriately:
|
||||
|
||||
class Select_Ajax_Input extends Select_Input {
|
||||
async on_load() {
|
||||
// Load options from Ajax
|
||||
this.data.select_values = await Controller.get_options();
|
||||
}
|
||||
|
||||
on_ready() {
|
||||
// Parent sets up TomSelect and calls _mark_ready()
|
||||
super.on_ready();
|
||||
}
|
||||
|
||||
// _get_value() and _set_value() inherited from Select_Input
|
||||
}
|
||||
|
||||
EVENT CONTRACT
|
||||
|
||||
Two events for different use cases:
|
||||
|
||||
'input' Event:
|
||||
- Fires ONLY on user interaction (typing, clicking, selecting)
|
||||
- Does NOT fire when val() setter is called programmatically
|
||||
- Use for: Reacting to user changes, live search, dependent dropdowns
|
||||
|
||||
'val' Event:
|
||||
- Fires on ALL value changes (user interaction AND val() setter)
|
||||
- Because jqhtml triggers already-fired events on late .on() registration,
|
||||
calling component.on('val', callback) immediately invokes callback with
|
||||
the current value
|
||||
- Use for: Always knowing the current value, initialization patterns
|
||||
|
||||
The base class automatically triggers 'val' in the val() setter. Concrete
|
||||
classes must still trigger both 'input' and 'val' on user interaction:
|
||||
|
||||
this.$sid('input').on('input', function() {
|
||||
const value = that.val();
|
||||
that.trigger('input', value); // User interaction
|
||||
that.trigger('val', value); // All changes (user fired, setter is in base)
|
||||
});
|
||||
|
||||
Example Usage:
|
||||
// React only to user changes
|
||||
this.sid('my_input').on('input', (component, value) => {
|
||||
console.log('User changed value to:', value);
|
||||
});
|
||||
|
||||
// Get immediate callback with current value, plus all future changes
|
||||
this.sid('my_input').on('val', (component, value) => {
|
||||
console.log('Value is:', value); // Fires immediately with current value
|
||||
});
|
||||
|
||||
TEMPLATE METHOD BENEFITS
|
||||
|
||||
The template method pattern provides:
|
||||
|
||||
1. Reduced Boilerplate
|
||||
Before: ~30-40 lines of val() logic per component
|
||||
After: ~5-10 lines implementing _get_value() and _set_value()
|
||||
|
||||
2. Enforced Contract
|
||||
- Cannot forget trigger('val') - base class handles it
|
||||
- Cannot forget buffering - base class handles it
|
||||
- Cannot mess up the getter/setter pattern
|
||||
|
||||
3. Consistent Behavior
|
||||
All inputs behave identically for buffering and events because
|
||||
the logic is centralized in one place.
|
||||
|
||||
4. Easier Maintenance
|
||||
Bug fixes or enhancements to buffering/events only need to change
|
||||
the base class, not every input component.
|
||||
|
||||
CONFIGURATION
|
||||
|
||||
No configuration required. These are code changes.
|
||||
|
||||
VERIFICATION
|
||||
|
||||
1. Search for remaining .Widget references:
|
||||
grep -r '\.Widget' --include="*.js" --include="*.jqhtml" rsx/
|
||||
|
||||
2. Verify input components extend Form_Input_Abstract:
|
||||
grep -r "extends Form_Input_Abstract" --include="*.js" rsx/
|
||||
|
||||
3. Verify base class methods are implemented:
|
||||
grep -r "_get_value\|_set_value" --include="*.js" rsx/theme/components/inputs/
|
||||
|
||||
4. Test form value population:
|
||||
- Load a form with data
|
||||
- Verify all fields populate correctly
|
||||
- Check console for errors
|
||||
|
||||
5. Test event triggers:
|
||||
- In console: component.on('val', (c, v) => console.log('val:', v))
|
||||
- Should immediately log current value
|
||||
- Change input, should log new value
|
||||
|
||||
6. Test pre-initialization:
|
||||
- Call val('test') on a Select_Ajax_Input before options load
|
||||
- Verify value is selected after options load
|
||||
|
||||
REFERENCE IMPLEMENTATIONS
|
||||
|
||||
Complete reference implementations are provided alongside this document:
|
||||
|
||||
form_input_abstract_12_29_reference.js
|
||||
The complete base class with template method pattern.
|
||||
Copy this to: rsx/theme/components/inputs/form_input_abstract.js
|
||||
|
||||
text_input_12_29_reference.js
|
||||
Example of a simple input using the new pattern.
|
||||
Shows minimal implementation with _get_value(), _set_value(), on_ready().
|
||||
|
||||
Use these as reference when converting existing input components.
|
||||
|
||||
SEE ALSO
|
||||
|
||||
php artisan rsx:man form_input
|
||||
rsx/theme/components/inputs/CLAUDE.md
|
||||
rsx/theme/components/inputs/form_input_abstract.js
|
||||
153
app/RSpade/upstream_changes/form_input_abstract_12_29_reference.js
Executable file
153
app/RSpade/upstream_changes/form_input_abstract_12_29_reference.js
Executable file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* Form_Input_Abstract - Base class for all form input widgets
|
||||
*
|
||||
* Reference implementation for form_input_abstract_12_29.txt migration guide.
|
||||
* Copy this to: rsx/theme/components/inputs/form_input_abstract.js
|
||||
*
|
||||
* This class implements the template method pattern, handling:
|
||||
* - Pre-initialization value buffering
|
||||
* - val() getter/setter logic
|
||||
* - Event triggers (trigger('val') on all changes)
|
||||
*
|
||||
* CONCRETE CLASS CONTRACT:
|
||||
*
|
||||
* REQUIRED - Implement these methods:
|
||||
* - _get_value() Return the current DOM/component value
|
||||
* - _set_value(value) Set the DOM/component value
|
||||
*
|
||||
* OPTIONAL - Override if needed:
|
||||
* - _transform_value(value) Transform buffered value for getter return
|
||||
*
|
||||
* REQUIRED - In on_ready():
|
||||
* - Call this._mark_ready() when component is fully initialized
|
||||
* - Setup user interaction event handlers that trigger both 'input' and 'val'
|
||||
*
|
||||
* Example Minimal Implementation:
|
||||
*
|
||||
* class My_Input extends Form_Input_Abstract {
|
||||
* _get_value() {
|
||||
* return this.$sid('input').val();
|
||||
* }
|
||||
*
|
||||
* _set_value(value) {
|
||||
* this.$sid('input').val(value || '');
|
||||
* }
|
||||
*
|
||||
* on_ready() {
|
||||
* this._mark_ready();
|
||||
*
|
||||
* const that = this;
|
||||
* this.$sid('input').on('input', function() {
|
||||
* const value = that.val();
|
||||
* that.trigger('input', value);
|
||||
* that.trigger('val', value);
|
||||
* });
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* EVENT CONTRACT:
|
||||
* - 'val' event fires on ALL value changes (handled by base val() setter)
|
||||
* - 'input' event fires on user interaction ONLY (handled by concrete class)
|
||||
* - Concrete classes trigger BOTH 'input' and 'val' on user interaction
|
||||
*
|
||||
* All widgets automatically have .Form_Input_Abstract class via jqhtml.
|
||||
* Form_Field sets data-name attribute for form integration.
|
||||
*
|
||||
* See: rsx/theme/components/inputs/CLAUDE.md for implementation details
|
||||
*/
|
||||
class Form_Input_Abstract extends Component {
|
||||
/**
|
||||
* Initialize buffering state.
|
||||
* Concrete classes should call super.on_create() if they override this.
|
||||
*/
|
||||
on_create() {
|
||||
this._pending_value = null;
|
||||
this._is_ready = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* val() - Get or set the current value
|
||||
*
|
||||
* This method handles all buffering and event logic. Concrete classes
|
||||
* should NOT override this method. Instead, implement _get_value(),
|
||||
* _set_value(), and optionally _transform_value().
|
||||
*
|
||||
* @param {*} [value] - If provided, sets the value. If omitted, returns the value.
|
||||
* @returns {*} The current value when called as getter
|
||||
*/
|
||||
val(value) {
|
||||
if (arguments.length === 0) {
|
||||
// Getter
|
||||
if (this._pending_value !== null) {
|
||||
return this._transform_value(this._pending_value);
|
||||
}
|
||||
return this._get_value();
|
||||
}
|
||||
|
||||
// Setter
|
||||
if (this._is_ready) {
|
||||
this._set_value(value);
|
||||
this._pending_value = null;
|
||||
} else {
|
||||
this._pending_value = value;
|
||||
}
|
||||
this.trigger('val', value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the component as ready and apply any buffered value.
|
||||
* Call this in on_ready() when the component is fully initialized.
|
||||
*
|
||||
* For components with async initialization (e.g., waiting for external
|
||||
* libraries like Quill or TomSelect), call this AFTER initialization
|
||||
* completes, not at the start of on_ready().
|
||||
*/
|
||||
_mark_ready() {
|
||||
this._is_ready = true;
|
||||
if (this._pending_value !== null) {
|
||||
this._set_value(this._pending_value);
|
||||
this._pending_value = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current value from DOM/component.
|
||||
* Concrete classes MUST implement this method.
|
||||
*
|
||||
* @returns {*} The current value
|
||||
*/
|
||||
_get_value() {
|
||||
throw new Error(`${this.constructor.name} must implement _get_value()`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value on DOM/component.
|
||||
* Concrete classes MUST implement this method.
|
||||
*
|
||||
* @param {*} value - The value to set
|
||||
*/
|
||||
_set_value(value) {
|
||||
throw new Error(`${this.constructor.name} must implement _set_value()`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a pending value for getter return.
|
||||
* Override this if the value needs transformation when returned.
|
||||
*
|
||||
* Example: Checkbox_Input transforms boolean/string to checked_value/unchecked_value
|
||||
*
|
||||
* @param {*} value - The pending value to transform
|
||||
* @returns {*} The transformed value
|
||||
*/
|
||||
_transform_value(value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed - Fill with random test data (optional)
|
||||
* Subclasses MAY implement this method
|
||||
*/
|
||||
async seed() {
|
||||
// Optional - widgets can override if they support seeding
|
||||
}
|
||||
}
|
||||
59
app/RSpade/upstream_changes/text_input_12_29_reference.js
Executable file
59
app/RSpade/upstream_changes/text_input_12_29_reference.js
Executable file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Text_Input - Reference implementation using template method pattern
|
||||
*
|
||||
* Reference implementation for form_input_abstract_12_29.txt migration guide.
|
||||
* Shows the minimal implementation required for a simple input component.
|
||||
*
|
||||
* Key points:
|
||||
* - No on_create() needed (base class handles _pending_value/_is_ready)
|
||||
* - No val() needed (base class handles it)
|
||||
* - Just implement _get_value(), _set_value(), and on_ready()
|
||||
* - Call _mark_ready() in on_ready() to apply buffered values
|
||||
* - Trigger both 'input' and 'val' on user interaction
|
||||
*/
|
||||
class Text_Input extends Form_Input_Abstract {
|
||||
/**
|
||||
* Return the current input value.
|
||||
* Called by base class val() getter.
|
||||
*/
|
||||
_get_value() {
|
||||
return this.$sid('input').val();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the input value.
|
||||
* Called by base class val() setter and _mark_ready().
|
||||
*/
|
||||
_set_value(value) {
|
||||
this.$sid('input').val(value || '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize component after render.
|
||||
* - Call _mark_ready() to apply any buffered value
|
||||
* - Setup user interaction events
|
||||
*/
|
||||
on_ready() {
|
||||
// Apply any buffered value from pre-ready val() calls
|
||||
this._mark_ready();
|
||||
|
||||
// Trigger events on user interaction
|
||||
const that = this;
|
||||
this.$sid('input').on('input', function() {
|
||||
const value = that.val();
|
||||
that.trigger('input', value); // User interaction only
|
||||
that.trigger('val', value); // All changes
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed - Fill with random test data
|
||||
*/
|
||||
async seed() {
|
||||
if (this.args.seeder) {
|
||||
// TODO: Implement Rsx_Random_Values endpoint
|
||||
let value = 'Test ' + (this.args.seeder || 'Value');
|
||||
this.val(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user