vue-the-mask
vue-the-mask copied to clipboard
caret jumps backwards
I tried to create a mask for numbers with dots as thousands-separator. My mask is in the array-format, and I figured out that each mask entry needs be exactly one character longer:
[
'###',
'####', // workaround to prevent '1.11'
'#.###',
'##.###',
'###.###',
'####.###', // workaround to prevent '1.000.00'
'#.###.###',
'##.###.###',
]
The mask itself works fine so far, but if the same character is entered repeatedly, the caret will not end up at the end but move one or two spaces backwards. This seems to happen when the two workaround mask entries are jumped over. If different numbers are entered, the caret stays at the end as intended.
Here is where the caret ends up:
1.0|0 10.000.0|00
I might have an idea, but not time to code/test it right now.
My analyse and reasoning:
As I understand the code in src/directive.js, when we input, we store the last known position of the caret in the input field, then we apply a new masked value, and then, we recursively try to find our inputted character from where the last known caret position is.
This loop is found at src/directive.js:50
My conclusion:
The result is, if you are using a single dot (.) as you are, and enter triple zeroes for example, you wind up one zero off. If you were to try with double dots (making the mask offset the character by another step) you would wind up two zeroes off.
My suggestion for a solution:
If we, when storing the last known caret position, also store the last known value length, call it val_len. When we are to relocate where the caret is supposed to be after masking the new value, all we need to do is compare the new value length to the old, that is how many steps "off" we are with the caret.
Problem illustration (| being the caret):
I'll be using dashes instead of dots or spaces, for visiblity
mask = [####, ##-###]
inputval = 50000|
caretpos = 5 // looking for the last entered 0 from position-1, found one directly
masked = 50-00|0
Double char-mask (double offset issue)
mask = [####, ##--###] // double space
inputval = 50000|
caretpos = 5 // looking for the last entered 0, again, found one directly
masked = 50--0|00
Solution illustration
I'll be using dashes instead of dots or spaces, for visiblity My solution would be to compare value lengths before/after masking, the difference would always make up for the 'masking chars' applied. Examples:
mask = [####, ##-###]
inputval = 50000|
caretpos = 5
valuelengthdiff = 1 // new length - old length
newcaretpos = 5 + valuelengthdiff
masked = 50-000|
Double char-mask
mask = [####, ##--###] // double space
inputval = 50000|
caretpos = 5
valuelengthdiff = 2 // new length(7) - old length(5)
masked = 50--0|00
Example of negative careting (user shortening the masked input value, which might be re-masked too)
mask = [####, ##--###] // double space
inputval = 50--0|00
// user deletes, it becomes to 50--|00 -> triggers new masking due to 4 number mask
// new masked value is:5000, caret should be at 50|00
caretpos = 5
valuelengthdiff = -3 // new length(4) - old length(7)
newcaretpos = caretpos+valuelengthdiff // 2
masked = 50|00
Sounds reasonble?
Edit: Anybody watching this - downloading repo, running npm install
and I cant runt npm run build
because of vue-cli deprecated build and some other stuff.. if anyone has solution please link or comment!
Note: This solution might not work for edge-cases like this
111|222 // something like this
###|### // masked with this
111333|222 // user inputs '333'
###-#|##-### // applying an alternative mask like for example this
This case would offset the caret 2 steps with my method, so maybe we're just moving the problem then.. but it would work for continuous input, which is perhaps more common
Thanks for your input @pjaer! I have created a fix based on your thoughts. I have already verified that the approach works by directly editing the minified version. Hopefully someone knows what to do about the broken build task, then I will create a pull request. I'll try to look into it myself if I find the time.
https://github.com/vuejs-tips/vue-the-mask/compare/master...wirk:bugfix/49-caret-jumps-backwards
@wirk When the bugfix will be available?
The problem occurs when typing the same number 2 times. I have same problem in phone mask.
I have the same problem. Would you have any solution?