3

I have got the following code from another question on here on how to prevent users from entering negative numbers, however it covered all inputs. I have 2 number type input elements and 2 text type input elements. I obviously want to allow the user to add any character to the text fields but want to prevent users entering negative numbers/non number content to the number inputs.

My code below works for one input with the number type and not the other. How would I go about changing my code to allow it for the other number input? Any help would be greatly appreciated.

HTML

<div class="cpNewTemplateDetailsWrap">
    <div class="col-sm-3">
        <label>Course Id</label>
    </div>
    <div class="col-sm-9">
        <input id="courseIdInput" type="text" class="form-control input-lg" placeholder="e.g. CT001" />
    </div>
    <div class="col-sm-3">
        <label>Course Description</label>
    </div>
    <div class="col-sm-9">
        <input id="courseDescInput" type="text" class="form-control input-lg" placeholder="e.g. Cadet Training" />
    </div>
    <div class="col-sm-3">
        <label>Course Duration <small>(Days)</small>
        </label>
    </div>
    <div class="col-sm-9">
        <input id="courseDurationInput" type="number" min="0" class="form-control input-lg" placeholder="5" />
    </div>
    <div class="col-sm-3" id="courseDemandTitle">
        <label>Course Demand</label>
    </div>
    <div class="col-sm-9">
        <input id="courseDemandInput" type="number" min="0" class="form-control input-lg" placeholder="5" />
    </div>
</div>

Javascript

var myInput = document.querySelectorAll("input[type=number]")[0];
myInput.addEventListener('keypress', function(e) {
  var key = !isNaN(e.charCode) ? e.charCode : e.keyCode;
  function keyAllowed() {
    var keys = [8,9,13,16,17,18,19,20,27,46,48,49,50,
                51,52,53,54,55,56,57,91,92,93];
    if (key && keys.indexOf(key) === -1)
      return false;
    else
      return true;
  }
  if (!keyAllowed())
    e.preventDefault();
}, false);

// Disable pasting of non-numbers
myInput.addEventListener('paste', function(e) {
  var pasteData = e.clipboardData.getData('text/plain');
  if (pasteData.match(/[^0-9]/))
    e.preventDefault();
}, false);

JS Fiddle Here!

Edit

With some of the duplicate questions, they cover just one input or all inputs. I just want to prevent negative numbers of 2 inputs. And if I wanted to add more input elements with a number type, I don't want to repeat code for each iteration. For example if I had 12 more inputs, I don't want to use that code 12 more times.

mcclosa
  • 943
  • 7
  • 29
  • 59
  • 4
    Keep in mind that preventing the user from this client-side is not a guarantee that they will not be entered. You'll also need server-side checks for this. (The users can mess with anything on their client, including your javascript) – Dylan Meeus Aug 09 '16 at 14:43
  • @DylanMeeus I do have server-side checks for this, would just also like to prevent it on the front end too – mcclosa Aug 09 '16 at 14:46
  • 1
    You've already set a `min` attribute. – gcampbell Aug 09 '16 at 14:47
  • Possible duplicate of [Is there any way to prevent input type="number" getting negative values?](http://stackoverflow.com/questions/7372067/is-there-any-way-to-prevent-input-type-number-getting-negative-values) – Pugazh Aug 09 '16 at 14:48
  • 2
    @gcampbell This only prevents a user from not selecting a negative number using the arrow keys, a user can still enter `-1` into the input – mcclosa Aug 09 '16 at 14:49
  • This question hav been answered here. http://stackoverflow.com/questions/31575496/prevent-negative-inputs-in-form-input-type-number – Manoj Aug 09 '16 at 14:49
  • If you want to have it attached to all inputs, than you need to attach the code to all the inputs. – epascarello Aug 09 '16 at 14:53
  • @ManojYadav I had looked at the question previously, however like most others, it covers all/just one input(s) and not a selected few which is what I am having problems with – mcclosa Aug 09 '16 at 14:59
  • @mcclosa I post another solution for you, see if its what you want. good luck! – DANIEL Aug 09 '16 at 15:32

7 Answers7

3

You were only adding the event listeners to the first number input.

https://jsfiddle.net/tpsbnp9q/5/

var myInput = document.querySelectorAll("input[type=number]");

function keyAllowed(key) {
  var keys = [8, 9, 13, 16, 17, 18, 19, 20, 27, 46, 48, 49, 50,
    51, 52, 53, 54, 55, 56, 57, 91, 92, 93
  ];
  if (key && keys.indexOf(key) === -1)
    return false;
  else
    return true;
}

myInput.forEach(function(element) {
  element.addEventListener('keypress', function(e) {
    var key = !isNaN(e.charCode) ? e.charCode : e.keyCode;
    if (!keyAllowed(key))
      e.preventDefault();
  }, false);

  // Disable pasting of non-numbers
  element.addEventListener('paste', function(e) {
    var pasteData = e.clipboardData.getData('text/plain');
    if (pasteData.match(/[^0-9]/))
      e.preventDefault();
  }, false);
})
imjosh
  • 4,734
  • 1
  • 19
  • 22
1

Usually just using the min="0" attribute on a type="number" field should be enough.

<input type="number" min="0" step="0.1" name="whatever" />

If you need to stick to <input type="text" /> or support very old browsers or want to make sure users dont enter negative numbers via keyboard (possible with min="0" on some browsers), with jQuery you can overwrite negative values on focusOut for all inputs having a specific class attribute with the following code:

$(document).ready(function(){
    $("body").on('focusout', '.my-input-number-positive', function(){
        if($(this).val() < 0){
            $(this).val('0'); // alternatively show a hint – or whatever
        }
    });
});

This does not replace server side validation!

Hafenkranich
  • 1,696
  • 18
  • 32
0

Your querySelectorAll method returns an array of all input elements of type number. You currently have the first element in the array selected, so that's the only input box that is checking for inputs.

Sam Siegel
  • 21
  • 3
0

The code that is causing only one input to be limited is the [0] at the end of this line

var myInput = document.querySelectorAll("input[type=number]")[0];

Now you could have a second variable, say myOtherInput, and add an event listener to that too:

var myOtherInput = document.querySelectorAll("input[type=number]")[1];
myOtherInput.addEventListener('keypress', function(e) {
  var key = !isNaN(e.charCode) ? e.charCode : e.keyCode;
  function keyAllowed() {
    var keys = [8,9,13,16,17,18,19,20,27,46,48,49,50,
                51,52,53,54,55,56,57,91,92,93];
    if (key && keys.indexOf(key) === -1)
      return false;
    else
      return true;
  }
  if (!keyAllowed())
    e.preventDefault();
}, false);

But it would add repeated code and might not help you if you wanted to limit loads of inputs.

ManFox
  • 71
  • 1
  • 5
  • Yeah, I was trying to avoid the repeated code, I did see this as the issue. Is there no method of selecting all of the inputs in my document with a type of number? – mcclosa Aug 09 '16 at 14:54
  • The first line does exactly that and then selects one of them, if you remove the [0] then it will return an array of all the number inputs on the page. – ManFox Aug 09 '16 at 14:58
  • When I do remove the `[0]` it allows me to enter `-1` into both inputs – mcclosa Aug 09 '16 at 15:01
  • 1
    Well yes it will, you would have to take the array and loop through it adding event listeners to each element. (I feel like there is certainly a better way to do that, but it is one way) – ManFox Aug 09 '16 at 15:04
  • Yeah, that's what I'm doing at the minute, but say if I had 4 more number type inputs, it will get a little messy, hopefully I will find a better resolution for this but adding event listeners to each statement will do for now – mcclosa Aug 09 '16 at 15:07
0

You can give class name to all selective input elements and use a loop to attach events on each input[type='number'].

Manoj
  • 1,175
  • 7
  • 11
0
  1. Get all your number fields.
  2. Add keypress listener to each element and if the key pressed is zero don't add it.

This doesn't cover the case for pasting negative numbers.

// get all number fields
var numInputs = document.querySelectorAll('input[type="number"]');

// Loop through the collection and call addListener on each element
Array.prototype.forEach.call(numInputs, addListener); 


function addListener(elm,index){
  elm.setAttribute('min', 0);  // set the min attribute on each field
  
  elm.addEventListener('keypress', function(e){  // add listener to each field 
     var key = !isNaN(e.charCode) ? e.charCode : e.keyCode;
     str = String.fromCharCode(key); 
    if (str.localeCompare('-') === 0){
       event.preventDefault();
    }
    
  });
  
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <lable>Number: <input type="number"></label>
  <br>
  <lable>Number: <input type="number"></label>
  <br>
  <lable>Text: <input type="text"></label>
    <br>
  <lable>Text: <input type="text"></label>

  
</body>
</html>
Yasin Yaqoobi
  • 1,888
  • 3
  • 27
  • 38
-1

You can use js directly on input - I think this is the simple and clean solution for your problem:

just put this on each input: onkeypress='return event.charCode >= 48 && event.charCode <= 57'

https://jsfiddle.net/tpsbnp9q/3/

DANIEL
  • 515
  • 7
  • 20