ui_elements_numericInput.mjs
/**
### mapp.ui.elements.numericInput()
Exports the numericInput elements method.
@module /ui/elements/numericInput
*/
/**
@function numericInput
@description
Creates a type=text input element with validation checks oninput.
@param {Object} params Parameter for the creation of the input element.
@property {string} [params.placeholder=''] The placeholder for the text input.
@property {string} [params.data_id='numeric-input'] The data id attribute for the input element.
@returns {Object} HTML input element
*/
export default function numericInput(params) {
params.placeholder ??= '';
params.data_id ??= 'numeric-input';
params.numericChecks ??= numericChecks;
const value = mapp.utils.formatNumericValue(params);
const width = params.dynamicWidth ? value.length + 1.3 + 'ch' : '100%';
const style = `text-align: center; width: ${width}`;
const numericInput = mapp.utils.html.node`<input
data-id=${params.data_id}
type="text"
style=${style}
placeholder=${params.placeholder}
value=${value}
onchange=${(e) => oninput(e, params)}
oninput=${(e) => oninput(e, params)}>`;
return numericInput;
}
/**
@function oninput
@description
Creates a type=text input element with validation checks for numeric values.
The value of an associated sliderElement will be updated if validated.
@param {Object} e The event object from input element.
@param {Object} params The config object argument.
@property {Object} e.target The input element.
@property {Object} params.callback A callback method is required.
*/
function oninput(e, params) {
// Assign stringValue from input target.
params.stringValue = e.target.value;
// Assign numeric newValue.
params.newValue = params.onRangeInput
? params.stringValue
: mapp.utils.unformatStringValue(params);
if (params.numericChecks(params.newValue, params)) {
// The numericCheck passes.
delete params.invalid;
e.target.classList.remove('invalid');
// Updated sliderElement value only if validated.
if (params.sliderElement) {
// Set styling param for the track.
params.sliderElement.style.setProperty(
`--${e.target.dataset.id}`,
params.newValue,
);
// Set value for the range input.
params.sliderElement.querySelector(`[name=${params.rangeInput}]`).value =
params.newValue;
}
} else {
// The numericCheck fails.
params.invalid = true;
e.target.classList.add('invalid');
}
// The invalid input should not be formatted.
if (params.invalid) return params.callback();
// Pass valid newValue to callback method.
params.callback(params.newValue);
// Re-format the params numeric value (newValue || value) and set as input string value.
e.target.value = mapp.utils.formatNumericValue(params);
if (params.dynamicWidth) {
e.target.style.width = e.target.value.length + 1.3 + 'ch';
}
//Mark the onRangeInput to false is the origin of the input call could come from either a slider or input
params.onRangeInput = false;
}
/**
@function numericChecks
@description
The numericChecks method checks whether a provided numeric value is a number, larger than params.min, and smaller than params.max.
@param {Object} value The numeric value to check.
@param {Object} params The config object argument.
@property {numeric} params.min Value must be larger than min.
@property {numeric} params.max Value must be smaller than max.
@returns {Boolean} true if checks are passed.
*/
function numericChecks(value, params) {
// Check whether value is a null.
if (params.onRangeInput && value === null) return false;
// Check whether value is a number.
if (isNaN(value)) return false;
if (params.min && value < params.min) {
// The value is smaller than min.
return false;
}
if (params.max) {
return value <= params.max;
}
return true;
}