1

I am planning to have an input textbox with leading string and zeros with maximum length of 6 leading zeros. When user type in the input box, the leading zero will be erase until it reach max 6 letters. The initial string is fixed and cannot be erase.

For example,

JS000000 //a fixed string (which is the letter 'JS') followed by 6 leading zeros
JS000010 //user has typed the letter '10'
JS123456 //user has typed the letter '123456' and cannot be type further

HTML

<input type="text" name="js" class="form-control" id="js_leading_zero">

JS/JQUERY

$('#js_leading_zero').on('keyup', function() {
    console.log('i really have no ideas what to do here')
});
LearnProgramming
  • 814
  • 1
  • 12
  • 37
  • Use `"blur"`, not keyup - it will mess with the caret position forcing you to write many lines of JS unnecessarily. Changing an input content while typing.... can you imagine the issues here? – Roko C. Buljan Apr 28 '21 at 15:19
  • @RokoC.Buljan okay i will take note on that – LearnProgramming Apr 28 '21 at 15:21
  • FYI there's a `pattern=` [property on inputs](https://stackoverflow.com/a/22437383/2181514), but it's probably not ideal / of use. TBH you're better off using a pre-written "masked input" for this. – freedomn-m Apr 28 '21 at 15:26
  • So you're saying the input has value: `JS000000` What if a user places his caret in between J and S and starts typing? Your task seems not well thought out :| – Roko C. Buljan Apr 28 '21 at 15:26
  • @freedomn-m oh nice i will look into it – LearnProgramming Apr 28 '21 at 15:27
  • @RokoC.Buljan i guess the caret will automatically be placed after the fixed letter? maybe is there a way to disable the user from clicking it? – LearnProgramming Apr 28 '21 at 15:29
  • *The initial string is fixed* - you mean "the string prefix is fixed" - the *initial* string would be "JS000000" so makes no sense for this whole string to be fixed – freedomn-m Apr 28 '21 at 15:29
  • @freedomn-m what i mean is, the default value that displayed inside the textbox, only the letter JS is fixed, the other leading 6 zeros can be overwrite by typing in – LearnProgramming Apr 28 '21 at 15:31
  • @LearnProgramming no, as you know already, whatever is inside an input there's no way to disable careting on certain portions of that value. What you could do instead is, use a i.e: `JS – Roko C. Buljan Apr 28 '21 at 15:31
  • Also, what should happen if a user wants to erase a specific number? See how this is becoming way too complex? – Roko C. Buljan Apr 28 '21 at 15:32
  • @RokoC.Buljan oh yeah that could work too, that should be easy to implement, thanks for that, but on the other hand, i have no ideas about the leading zero – LearnProgramming Apr 28 '21 at 15:33
  • @RokoC.Buljan i would not allowed the user to erase a specific number, it will automatically keyed in on the last letter, besides it is only 6 letters that they are allowed to typed – LearnProgramming Apr 28 '21 at 15:36
  • @LearnProgramming well, that's not the best UX I've ever seen, forcing a user to reset the entire thing just to fix a typo.... – Roko C. Buljan Apr 28 '21 at 15:40
  • @RokoC.Buljan thats the best that i could think of...do you have any suggestion? – LearnProgramming Apr 28 '21 at 15:41
  • 2
    @LearnProgramming Sure I do, but I don't like it: https://jsfiddle.net/RokoCB/80pe1qtx/ - I would feel bad to just propose it as an answer. I don't say it's not doable to work exactly with all the features and everything - it's just too much code and involves tracking the caret position etc etc - and than expect it to fail on mobile devices and so on .... fix hack fix. – Roko C. Buljan Apr 28 '21 at 15:49
  • @RokoC.Buljan oh wow, that was advanced level codes, i may need a bit of time to learn it...this is exactly what i wanted but i cant backspace/erase the numbers though – LearnProgramming Apr 28 '21 at 16:06
  • 1
    @LearnProgramming exactly :D you cannot with that solution - that's why I said it's a bad one. – Roko C. Buljan Apr 28 '21 at 16:10

5 Answers5

1

An alternative to managing the caret of an input would be to use a focus-able div with some css to "fake" the "JS" part*.

Then you can handle the keyup on the input with relatively minimal code - this is just for concept, you'd probably want it a bit neater with some decent variable names and storing the val on the input itself so its reusable:

var val = 0;
$("#inp").on("keyup", function(e) {
  var c = String.fromCharCode(e.which);
  if (c >= '0' && c <= '9' && (val + "").length < 6) {
    val = (val * 10) + (c * 1);
  }
  if (e.which == 8) {
    val = Math.floor(val / 10);
  }
  $(this).text(("000000" + val).slice(-6))
})
div:focus { 
/* stupid chrome currently puts an ugly black border, so need something else border:1px solid red; */
background-color: aqua;
}

.inpwrapper {
  border:1px solid #CCC;
  padding:2px;
}
.inpwrapper span { float:left; margin: 2px 0 2px 0; }
.inpwrapper div { margin:2px 6px 2px 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='inpwrapper'>
  <span>JS</span>
  <div id="inp" tabindex="0">000000</div>
</div>

<hr /> another input to demonstrate tab-focus
<input type='text'>

(*) actually, no need for the "fake" css part, can use: .text("JS" + ("000000" + val).slice(-6))

freedomn-m
  • 27,664
  • 8
  • 35
  • 57
  • The caret is missing out – Roko C. Buljan Apr 28 '21 at 15:57
  • Yes, there's no caret, that's the point - no cursor actions either - you type the number, backspace to remove last character. It's not emulating or hacking an `input`, it's creating a new type of input that matches OPs requirements - without 100s of lines of code to manage the input. – freedomn-m Apr 28 '21 at 15:59
  • @freedomn-m If we are following this approach one easiest solution is to simulate the UI where we enter our credit card details. We can have 6 Inputs. entering in one input will move the focus to the next input. I feel that will be a bit more elegant. – Ashish Apr 28 '21 at 16:06
  • @Ashish and how annoying do you find those when you mistype one character and you can't just backspace? Also, entering credit card goes left-to-right while OPs requirement is to pad right to left. 6 inputs for this wouldn't work well IMO, but you're welcome to provide an answer to prove me wrong – freedomn-m Apr 28 '21 at 16:17
  • 1
    @freedomn-m I had no intention to prove you wrong, in fact, the solution for credit card input came to my mind after looking at your approach only. IMO there is no such right or wrong solution. Your solution is working. It all depends on the problem statement :) – Ashish Apr 28 '21 at 16:25
  • 1
    @Ashish meant to put a `:)` at the end of my last comment - on re-reading it sounds more confrontational than I intended :) – freedomn-m Apr 28 '21 at 16:28
1

With my suggestion from comments to use the "JS" portion as a separate entity, and the blur and focus Events - but also to allow for resetting the input to a new value.

The trick is to store the current value into the Elements placeholder. If on blur no value was entered, use again the placeholder value as the Element actual value:

const updateVal = (ev) => {
  const EL = ev.currentTarget;
  EL.value = EL.value.length ? EL.value.padStart(6, '0') : EL.placeholder;
  EL.placeholder = EL.value;
};

const clearVal = (ev) => {
  const EL = ev.currentTarget;
  EL.value = "";
};

const inputField = document.querySelectorAll('.js_leading_zero');
inputField.forEach(EL => EL.addEventListener("blur", updateVal));
inputField.forEach(EL => EL.addEventListener("focus", clearVal));
* {box-sizing: border-box;}

.js_leading_zero_label {
  border: 1px solid #000;
  font: 1em sans-serif;
  padding: 4px;
}

.js_leading_zero {
  outline: none;
  border: none;
  background: transparent;
  font: 1em sans-serif;
}
<label class="js_leading_zero_label">
  JS<input type="text" class="js_leading_zero" placeholder="000000" maxlength="6">
</label>
<label class="js_leading_zero_label">
  JS<input type="text" class="js_leading_zero" placeholder="000000" maxlength="6">
</label>
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
0

As suggested by @RokoC.Buljan You can change the value on blur, otherwise, there are just too many things that you need to consider.

One such example:

const inputField = document.getElementById('js_leading_zero')

inputField.addEventListener('blur', updateInput);

function updateInput(e) {
  inputField.value = inputField.value.padStart(6, '0')
}
JS<input type="text" name="js" class="form-control" id="js_leading_zero" placeholder="000000" maxlength="6">

Update: @RokoC.Buljan's approach to update placeholder is one innovative way: https://jsfiddle.net/RokoCB/bdzyughs/2/

Ashish
  • 4,206
  • 16
  • 45
  • hmmm seems like i could key in more than 6 – LearnProgramming Apr 28 '21 at 15:43
  • @RokoC.Buljan I agree, this is not optimal, But again we are not here to write the complete solution. Obviously, there are multiple edge cases that we need to handle. But my solution was just to highlight the basic approach. Yes we can type more characters, in this case as suggested by you we can keep JS in div. and set fixed length for input – Ashish Apr 28 '21 at 15:45
  • @LearnProgramming I have updated the answer to allow max of 6 characters. – Ashish Apr 28 '21 at 15:48
  • @Ashish PS... https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart – Roko C. Buljan Apr 28 '21 at 15:55
  • 1
    @RokoC.Buljan Thanks for highlighting, Got to learn something new today. I have updated the answer with `padStart`. Just one small thing made the whole approach a lot elegant. – Ashish Apr 28 '21 at 16:00
  • oh this is nice, a simple way to do it – LearnProgramming Apr 28 '21 at 16:14
  • 2
    @LearnProgramming here's a better one (which allows for resetting) https://jsfiddle.net/RokoCB/bdzyughs/2/ – Roko C. Buljan Apr 28 '21 at 16:16
  • oh it retains the last typed numbers as a placeholder – LearnProgramming Apr 28 '21 at 16:22
0

As others have noted, what you're asking for would be quite complicated to implement. You could consider just setting max-length, making the initial value "JS", and do a regex check.

$('#js_leading_zero').on('change', function(ev) {
  if (!/^JS.{0,6}$/.test(ev.target.value)) {
    this.classList.add("invalid")
  } else {
    this.classList.remove("invalid")
  }
});
.invalid {
  outline:2px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" value="JS" maxlength="8" class="form-control" id="js_leading_zero" placeholder="JS000000">
Scott Weaver
  • 7,192
  • 2
  • 31
  • 43
0

Answered by @Roko C.Bujian in comment section referring to jsfiddle link from him

HTML

<input type="text" class="js_leading_zero" value="JS000000" maxlength=8>

JS

const prefix = "JS";

const modifyVal = (ev) => {
    const EL = ev.currentTarget;
    let str = EL.value.replace(/\D/g, "");
    str +=  EL.dataset.key;
    const int = parseInt(str);
    str = String(int).padStart(6, "0");
    if (str.length === 6)
    EL.value = prefix + str;
};

const rememberKey = (ev) => {
    ev.preventDefault();
    const EL = ev.currentTarget;
    EL.dataset.key = ev.key;
};

const ELs_inp = document.querySelectorAll(".js_leading_zero");
ELs_inp.forEach(EL => EL.addEventListener("keydown", rememberKey));
ELs_inp.forEach(EL => EL.addEventListener("keyup", modifyVal));
LearnProgramming
  • 814
  • 1
  • 12
  • 37