13

I have a text input, which has three dynamically-generated characters On when page-load; what I want is that when a user enters data in that fieLd the user should be unable to remove that first three characters from the input.

The text input can contain 10 characters in total, three which we generate and 7 entered by the user.

Currently if the user presses backspace he can delete all characters, but I don't want to allow them to delete the first three characters.

On page-load the script sets three characters in the Lab text input:

<input id="Lab" maxlength="10" name="LabWareId" type="text" value="" class="valid">

$('#Lab').keyup(function () {
  if ($(this).val().length == $(this).attr('maxlength'))
    $('#DateReceived').focus();
});
David Thomas
  • 249,100
  • 51
  • 377
  • 410
ZCoder
  • 2,155
  • 5
  • 25
  • 62

6 Answers6

16

Option 1 : Put the 3 character prefix outside of the input. This is the best from a user experience perspective.

<p>abc <input id="Lab" maxlength="10" name="LabWareId" type="text" class="valid"></p>

Option 2 : Check for backspace keypress and prevent the delete accordingly.

$(document).on('keydown', function (e) {
  if (e.keyCode == 8 && $('#Lab').is(":focus") && $('#Lab').val().length < 4) {
      e.preventDefault();
  }
});
Ryan Dantzler
  • 1,124
  • 1
  • 8
  • 18
  • 1
    I've up voted, but want to point out some limitations. Option 2 doesn't prevent the user from pasting text into the input and overwriting the prefix. And Option 1 (like other answers here) doesn't append the prefix to the actual value sent to the server. Regardless, it's still a good answer. – Yogi Mar 30 '16 at 21:43
8

Try this (it's not the best solution but it works):

Fiddle

$(document).ready(function() {
  $("#tb").on("keyup", function() {
    var value = $(this).val();
    $(this).val($(this).data("initial") + value.substring(3));
  });
});

Mind you that if I use my mouse to highlight the first 3 characters and move them at the end of the other texts, it won't complain and allow it which is not what you want.

dokgu
  • 4,957
  • 3
  • 39
  • 77
  • 1
    Up voted. The selected answer also has the same limitation and this solution is actually coded better. – Yogi Mar 30 '16 at 21:56
6

I would probably put the 3 generated characters to the left of the input, so the user doesn't think those are editable. You can make this look kinda nice using bootstrap like so.

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<label for="basic-url">Enter thingy:</label>
<div class="input-group">
  <span class="input-group-addon" id="basic-addon3">ABC</span>
  <input type="text" class="form-control" id="basic-url" aria-describedby="basic-addon3" maxlength="7" placeholder="Enter 7 characters">
</div>
goodface87
  • 236
  • 1
  • 7
2

Putting the 3 characters outside the editable area is the simplest/best approach.

However, my vanilla pure JavaScript approach for the case that the 3 characters must be in the input tag also handles the case that a user presses the delete key or tries to delete the first characters. In case pressing the delete key with the current selection means that less than 4 characters would remain or characters at the beginning would be deleted (removing the selection or pressing backspace), this user action is suppressed.

The script adds to all input tags of class=="valid" an keydown event handler calling function keepLeadingChars(e), which first ensures that pressing backspaces leaves 3 characters at the beginning and then ensures that deleting a selection leaves at least 3 characters at the beginning (or any other number specfied in the function call).

// add keydown event to input tags
var inputs = document.getElementsByTagName("input");
for (var i=0;i<inputs.length;i++) {
  var ClassAttr = inputs[i].getAttribute("class");
  if (ClassAttr=="valid") {
    inputs[i].addEventListener("keydown", function(e) { keepLeadingChars(e,3); } );
  }
}

function keepLeadingChars(e,count) {

  // if backspace key (8) pressed and ...
  if (e.keyCode==8) {
    // ... content length < 4 then prevent user action
    if (e.target.value.length<count+1) {
    e.preventDefault();
    }
    // ... cursor is within first characters at beginning then prevent user action
    var start = e.target.selectionStart;
    if (start<count+1) {
      e.preventDefault();
    }
  }

  // if delete key (46) pressed and ...
  if (e.keyCode==46) {
    var start = e.target.selectionStart;
    var end = e.target.selectionEnd;
    var selLength = end-start; // length of selection
    var totalLength = e.target.value.length;
    //console.log(totalLength-selLength);
    // ... remaining length < 3 then prevent user action
    if (totalLength-selLength<count) {
      e.preventDefault();
    }
    // ... selection is within first characters at beginning then prevent user action
    if (start<count) {
      e.preventDefault();
    }
  } 
}
intput 1: <input id="Lab1" maxlength="10" name="LabWareId" type="text" value="1234567" class="valid"><br />
intput 2: <input id="Lab2" maxlength="10" name="LabWareId" type="text" value="1234567" class="valid">
Andrew Tibbetts
  • 2,874
  • 3
  • 23
  • 28
LoonyNoob
  • 39
  • 2
1

I'm adding this solution as another alternative that might be useful to someone.

It uses the jQuery before() method. It works similar to CSS before, but also with input elements. However, you have to add some extra styling to make the prefix appear to be inside the input.

Also see: Can I use the :after pseudo-element on an input field?

Run the code snippet to try

$('#Lab').before('<span class="prefix">' + $('#Lab').data('prefix') + '</span>');
form {
  background-color: lightgray;
  padding: 2em;
}
#Lab {
  border: 1px solid gray;
  border-left: none;
  width: 10em;
}
.prefix {
  color: dimgray;
  background-color: white;
  border: 1px solid gray;
  border-right: none;
  font-family: monospace;
  font-size: 16px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<form>
  <input id="Lab" maxlength="10" name="LabWareId" type="text" data-prefix="123">
</form>
Community
  • 1
  • 1
Yogi
  • 6,241
  • 3
  • 24
  • 30
1

Add inputs and make them look like single input.

 <span>
    <input type="text" value="abc" readonly style="border-right: none;outline: none;width:25px"/>
  </span>
  <input type="text" style="border-left: none;outline: none;"/>
PaperinFlames
  • 642
  • 5
  • 6