Input mask with zerofill on a text column

Tags: #<Tag:0x00007efc648d1b68> #<Tag:0x00007efc648d1988>

Hi everyone

I have searched the forum for a solution to the problem I have and the only similar topic I have found is Mask for cell value but it doesn’t solve my problem

I have several text columns but one and only one of them must have an input mask in this format ‘00.00000.000.00’ (with zero fill; see the examples)

Only allowed characters in this column must be numbers, space and dot; all other characters should be ignored when typing

The goal is that as the user writes, he sees the text in the cell formatted in real-time

Here are two examples (the left side is the sequence of keys typed on the keyboard, the right side is what user should see in the cell while types; note that space and dot key are equivalent)

example 1:

2                             2
2DOT                          02.
2DOT1                         02.1
2DOT12                        02.12
2DOT123                       02.123
2DOT1234                      02.1234
2DOT12345                     02.12345
2DOT123456                    02.12345.6
2DOT1234567                   02.12345.67
2DOT1234567DOT                02.12345.067.
2DOT1234567DOT8               02.12345.067.8
2DOT1234567DOT89              02.12345.067.89
2DOT1234567DOT89ENTER         02.12345.067.89

example 2:

2                             2
22                            22
221                           22.1
2213                          22.13
22134                         22.134
22134SPACE                    22.00134.
22134SPACE2                   22.00134.2
22134SPACE2SPACE              22.00134.002.
22134SPACE2SPACE9             22.00134.002.9
22134SPACE2SPACE9ENTER        22.00134.002.09

I’ve read about how I could use the beforeKeyDown event, a custom render (but it seems that formatting only happens on cell exit), RegEx etc… but i have no idea how i can implement the logic

Any tip?

Thanks in advance to anyone who can contribute with an idea/solution

Hi @marcari

Basing on your requirements I think the best way to achieve that functionality would be to build a custom editor. It would also require to user regex to swap the characters. Using it instead of custom renderer would allow you to change the characters as you type in the cell. Here we have a tutorial on how to build the custom editor that might be useful for you:

due to the complexity of introducing a custom renderer into the code and also due to this note

I had to solve it by introducing ad-hoc code to get the exact functionality I wanted, using beforeKeyDown event.

I leave here my (certainly not optimized, but working) code, in case it might be useful somehow to someone.

1 Like

1/4

,beforeKeyDown: function(e) {
	fixCol = this.getActiveEditor().col;
	for (var i = 0; i < TableData.hiddenColumns.length; i++) {
		if (TableData.hiddenColumns[i] <= fixCol) {
			fixCol++;
		}
	}
	
	if (TableData.myTableColumns[fixCol].type == 'text') {
		switch(TableData.myTableColumns[fixCol].format) {
			case 'CNTR':
			if (e.key != 'Enter' && e.key != 'Delete' && e.key != 'Backspace') {
				let isSeparator = false;
				if (e.key == '.' || e.key == '-' || e.key == '_' || e.key == ' ') {
					isSeparator = true;
				}
				if (e.key.match(/[0-9]/g)) {
					this.getActiveEditor().TEXTAREA.value = txtFormatter(e.target.value+e.key,isSeparator);
				}
				else if (isSeparator) {
					this.getActiveEditor().TEXTAREA.value = txtFormatter(e.target.value,isSeparator);
				}
				e.preventDefault();
			}
			else if (e.key == 'Enter') {
				if (this.getActiveEditor().TEXTAREA.value != '') {
					this.getActiveEditor().TEXTAREA.value = txtCompleter(e.target.value);
				}
			}
			break;
			
			default:
			//free text
		}
	}
}

2/4

function txtFormatter(text,isSep) {
	let blocks = text.split('.');
	
	for (let i=0; i<blocks.length; i++) {
		let block = JSON.parse(JSON.stringify(blocks[i]));
		
		switch(i) {
			
			case 0:
			if (block.length > 2) {
				blocks.splice(0,1,block.slice(0,2));
				blocks.splice(1,0,block.slice(2));
			}
			break;
			
			case 1:
			if (block.length > 5) {
				blocks.splice(1,1,block.slice(0,5));
				blocks.splice(2,0,block.slice(5));
			}
			break;
			
			case 2:
			if (block.length > 3) {
				blocks.splice(2,1,block.slice(0,3));
				blocks.splice(3,0,block.slice(3));
			}
			break;
			
			case 3:
			if (block.length > 2) {
				blocks.splice(3,1,block.slice(0,2));
			}
			break;
			
			default:
		}
	}
	
	if (blocks[0] != null && isSep) {
		blocks[0] = txtFiller(blocks[0],2);
	}
	if (blocks[1] != null && isSep) {
		blocks[1] = txtFiller(blocks[1],5);
	}
	if (blocks[2] != null && isSep) {
		blocks[2] = txtFiller(blocks[2],3);
	}
	if (blocks[3] != null && isSep) {
		blocks[3] = txtFiller(blocks[3],2);
	}
	
	let strComplete = blocks.join('.');
	if (isSep && blocks.length < 4) {
		strComplete = strComplete + '.';
	}
	return strComplete;
}

3/4

function txtCompleter(text) {
	let blocks = text.split('.');
	
	switch(blocks.length) { //NO BREAKS into this SWITCH!
		
		case 1:
		blocks[0] = txtFiller(blocks[0],2);
		blocks.push('');
		
		case 2:
		blocks[1] = txtFiller(blocks[1],5);
		blocks.push('');
		
		case 3:
		blocks[2] = txtFiller(blocks[2],3);
		blocks.push('');
		
		case 4:
		blocks[3] = txtFiller(blocks[3],2);
		
		default:
	}
	
	return blocks.join('.');
}

4/4

function txtFiller(text,totLength) {
	while (text.length < totLength) {
		text = '0' + text;
	}
	return text;
}

This topic can be closed

Hi @marcari

Thank you very much for your solution. It surely will be helpful for other users.