Introduction
I would like to make an input of a fixed length that you can only fill some of the characters, for instance let's say I have __llo w_rld!
and i want the user to fill in the gaps, but not allow to modify the prefilled characters.
Ideas
I thought of using an input tag for each character and mark as disabled the prefilled ones, here is an example:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Example</title>
</head>
<body>
<input size="1"></input>
<input size="1"></input>
<input size="1" value="l" disabled></input>
<input size="1" value="l" disabled></input>
<input size="1" value="o" disabled></input>
 
<input size="1" value="w" disabled></input>
<input size="1"></input>
<input size="1" value="r" disabled></input>
<input size="1" value="l" disabled></input>
<input size="1" value="d" disabled></input>
<input size="1" value="!" disabled></input>
</body>
</html>
However this approach doesn't allow the user to keep typing characters and jump from one input to the next one.
Is there any way of accomplishing this?
CodePudding user response:
Using required
and querySelector(':invalid')
seems to work pretty well.
By the way, it's not valid html to end <input>
tags.
const container = document.getElementById("container");
container.addEventListener("input", ev => {
container.querySelector("input:invalid")?.focus();
});
input {
width: 1em;
}
<div id="container">
<input required maxlength="1">
<input required maxlength="1">
<input value="l" disabled>
<input value="l" disabled>
<input value="o" disabled>
 
<input value="w" disabled>
<input required maxlength="1">
<input value="r" disabled>
<input value="l" disabled>
<input value="d" disabled>
<input value="!" disabled>
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
If I understand right, the one character long text boxes are a fallback not what you actually want? If so you can use a regex to reject anything that doesn't match. To do so you use a .
for every character you are leaving blank and the character for each one you want to be fixed. The regex for your hello world example is /..llo w.rld!/
and you revert the field value to the last version that passed this test every time it fails. Technically they can edit those characters, but the code will change them back immediately after:
let lastValue = '__llo w_rld!';
let currentValue = '__llo w_rld!';
const regex = new RegExp('..llo w.rld!');
testTextID.value = lastValue;
function overwriteTestText(e){
let caretpos = testTextID.selectionStart;
currentValue = removeCharacter(testTextID.value, caretpos);
testText(e, false);
//selecting 0 characters long puts the caret at that position.
testTextID.setSelectionRange(caretpos, caretpos);
}
function testText(e, readInput = true){
if(readInput) {
currentValue = testTextID.value;
}
if (regex.test(currentValue) && currentValue.length==12) {
lastValue = currentValue;
}
testTextID.value = lastValue;
}
function removeCharacter(str, pos) {
return str.slice(0,pos) str.slice(pos 1);
}
<input id="testTextID" onkeyup="overwriteTestText()" onblur="testText()" />
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>