Skip to content

Instantly share code, notes, and snippets.

@smourier
Created July 1, 2023 07:24
Show Gist options
  • Save smourier/859d0e2448591e407adff0f7f8a4ba13 to your computer and use it in GitHub Desktop.
Save smourier/859d0e2448591e407adff0f7f8a4ba13 to your computer and use it in GitHub Desktop.
An AG-Grid numeric editor that supports comma or dot as decimal separator.
// backspace starts the editor on Windows
const KEY_BACKSPACE = 'Backspace';
// a numeric editor that supports comma or dot as decimal separator
class numericEditor {
init(params) {
// get separator, only used for initial input
this.decimalSeparator = params.decimalSeparator;
// create the cell
this.eInput = document.createElement('input');
this.eInput.classList.add('numeric-input');
if (params.eventKey === KEY_BACKSPACE) {
this.eInput.value = '';
}
else if (this.isCharNumeric(params.eventKey)) {
this.eInput.value = params.eventKey;
}
else if (params.value !== undefined && params.value !== null) {
this.eInput.value = params.value;
if (this.decimalSeparator && this.decimalSeparator !== '.') {
this.eInput.value = this.eInput.value.replace('.', this.decimalSeparator);
}
}
this.eInput.addEventListener('keydown', (event) => {
if (!event.key || event.key.length !== 1)
return;
if (!this.isNumericKey(event) && event.key != ',' && event.key != '.') {
this.eInput.focus();
if (event.preventDefault) event.preventDefault();
return;
}
if (this.isNavigationKey(event) || this.isBackspace(event)) {
event.stopPropagation();
return;
}
// compute the new value after keydown
// if it's incorrect don't let the key pass
let newValue = this.eInput.value;
newValue = newValue.slice(0, event.target.selectionStart) + event.key + newValue.slice(event.target.selectionStart);
const norm = this.normalizeValue(newValue);
if (norm == null) {
this.eInput.focus();
if (event.preventDefault) event.preventDefault();
return;
}
});
// only start edit if key pressed is a number, not a letter (not comma nor dot)
const isNotANumber =
params.eventKey &&
params.eventKey.length === 1 &&
'1234567890'.indexOf(params.eventKey) < 0;
this.cancelBeforeStart = !!isNotANumber;
}
isBackspace(event) {
return event.key === KEY_BACKSPACE;
}
isNavigationKey(event) {
return event.key === 'ArrowLeft' || event.key === 'ArrowRight';
}
getGui() {
return this.eInput;
}
afterGuiAttached() {
this.eInput.focus();
}
isCancelBeforeStart() {
return this.cancelBeforeStart;
}
isCancelAfterEnd() {
const value = this.getValue();
return value == null;
}
getValue() {
return this.normalizeValue(this.eInput.value);
}
isPopup() {
return false;
}
isCharNumeric(charStr) {
return charStr && !!/\d/.test(charStr);
}
isNumericKey(event) {
const charStr = event.key;
return this.isCharNumeric(charStr);
}
// transform a text with comma or dot into a numeric value
normalizeValue(value) {
if (!value)
return null;
const commas = (value.match(/,/g) || []).length;
const dots = (value.match(/\./g) || []).length;
if (commas > 0 && dots > 0) // can't mix both
return null;
if (commas > 1 || dots > 1) // too many
return null;
if (!commas) {
const number = Number.parseFloat(value);
if (!Number.isFinite(number))
return null;
return number;
}
const number = Number.parseFloat(value.replace(',', '.'));
if (!Number.isFinite(number))
return null;
return number;
}
// replace back commas if there were any in original text
normalizeValueToString(value) {
const number = this.normalizeValue(value);
if (number == null)
return value;
const hasComma = value.indexOf(',') >= 0;
if (!hasComma)
return number.toString();
return number.toString().replace('.', ',');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment