0

I have a page that contains a whole bunch of input boxes of type number. These can be individually changed, or a set of them can be changed by a selector.

I would like to show the user which input boxes have values greater than 0 in them by changing the class of the input box.

I cannot use JQuery. It has to be done with pure Javascript.

I understand I will need to use an event listener to attach a function to it?

Anyway... here's a piece of html as an example:

<input name="qty1" type="number" min="0" value="0">
<input name="qty2" type="number" min="0" value="0">
<input name="qty3" type="number" min="0" value="0">
<input name="qty4" type="number" min="0" value="0">
<input name="qty5" type="number" min="0" value="0">

Here's some Javascript I think should go with this:

function changeInputClass(element){
  if(element.value > 0){
    //add class 'bold-text' to this element
  }
  else {
    //remove class 'bold-text' from this element
  }
}

var myElements = document.getElementsByTagName('input');
for(var i=0; i<myElements.length; i++){
  if(myElements[i].type == 'number') {
    // add event listener here to call function changeInputClass()
  }
}

Appreciate the help.

Update of more realistic representation of the html:

<div id="selections" class="selections">
  <div class="images-container">
    <div>
      <div class="image-options">
        <div class="product-option">
          <div class="qty"><input name="qty1" type="number" min="0" value="0"></div>
          <div>Product Description 1</div>
        </div>
        <div class="product-option">
          <div class="qty"><input name="qty2" type="number" min="0" value="0"></div>
          <div >Product Description 2</div>
        </div>
        <div class="product-option">
          <div class="qty"><input name="qty3" type="number" min="0" value="0"></div>
          <div >Product Description 3</div>
        </div>
      </div>
      <div class="image-options">
        <div class="product-option">
          <div class="qty"><input name="qty4" type="number" min="0" value="0"></div>
          <div >Product Description 4</div>
        </div>
        <div class="product-option">
          <div class="qty"><input name="qty5" type="number" min="0" value="0"></div>
          <div >Product Description 5</div>
        </div>
        <div class="product-option">
          <div class="qty"><input name="qty6" type="number" min="0" value="0"></div>
          <div >Product Description 6</div>
        </div>
      </div>
    </div>
  </div>
</div>

Created a fiddle http://jsfiddle.net/narfie/g3gbqaxz/14/

narfie
  • 493
  • 1
  • 7
  • 16

4 Answers4

1

Now I made an array of all the input elements by going through the first child of the element with class qty. Made a single function to check changes to that element array. Added the onchange to any higher ancestor of the input element.

var inputs = new Array();
window.onload = function () {
    var qtys = document.getElementsByClassName("qty");
    for (var i = qtys.length - 1; i >= 0; i--) {
        inputs[i] = qtys[i].children[0];
    };
}
function check() {
    for (var i = inputs.length - 1; i >= 0; i--) {
        if(inputs[i].value>0){
            inputs[i].classList.add("has-value");
        }
        else{
            inputs[i].classList.remove("has-value");
        }
    };
}

Rest at fiddle : http://jsfiddle.net/1jcyhpyL/8/

bluefog
  • 1,894
  • 24
  • 28
  • Note that the change event doesn't bubble in all browsers. Also, programmatically changing the value (what I understand from "*… or a set of them can be changed by a selector*") doesn't necessarily dispatch a change event. – RobG Jan 09 '15 at 08:57
  • On programmatically changing the value, the function `checkVal()` can be called. – bluefog Jan 09 '15 at 09:08
  • I am testing in IE 6.0.2800 right now and the change event on input elements does not bubble. And yes, if the value is changed programmatically, then the change event must be manually dispatched or triggered. – RobG Jan 09 '15 at 09:30
  • See a [jQuery workaround](http://stackoverflow.com/a/4722246/227299) on old IE versions. I won't bother actually, as "As of Jan 2015, IE6 is being used by just <=1% users in most countries. Only exception being China(2.3%) and Venezuela(1.2%)". – bluefog Jan 09 '15 at 09:33
  • The point is that Quirksmode claims the change event bubbles in IE 5.5 and 6. How reliable is the rest of the table? – RobG Jan 09 '15 at 11:12
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/68477/discussion-between-shikhar-bhardwaj-and-robg). – bluefog Jan 09 '15 at 11:13
  • I like this answer, it seems pretty straight forward. I just have a small problem in that the input boxes are inside divs. I'll updated my question with a more realistic representation of my form. – narfie Jan 09 '15 at 12:09
0
<html>
<body>

<input name="qty1" type="number" min="0" value="0" onchange="changeInputClass(this)">
<input name="qty2" type="number" min="0" value="0" onchange="changeInputClass(this)">
<input name="qty3" type="number" min="0" value="0" onchange="changeInputClass(this)">
<input name="qty4" type="number" min="0" value="0" onchange="changeInputClass(this)">
<input name="qty5" type="number" min="0" value="0" onchange="changeInputClass(this)">

<script>
function changeInputClass(element) {

 if (element.value > 0){
  element.style.fontWeight = 'bold';    
 }
 else {
  element.style.fontWeight = 'normal';  
 }
}
</script>


</body>
</html>
webtrick101
  • 214
  • 1
  • 6
0

Here is an example of using modern methods that handle most situations. You still have the problem where a value is changed programatically (even mutation observers do not handle this), as described by @RobG. But this should give a fair demonstration of the common situations.

function changeClass(e) {
    var target = e.target || e;

    if (target.nodeName === 'INPUT' && target.type === 'number') {
        if (target.valueAsNumber > 0) {
            target.classList.remove('noValue');
            target.classList.add('hasValue');
        } else {
            target.classList.add('noValue');
            target.classList.remove('hasValue');
        }
    }
}

[].forEach.call(document.querySelectorAll('input[type="number"]'), changeClass);

new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
        if (mutation.type === 'childList') {
            [].forEach.call(mutation.addedNodes, changeClass);
        }
    });
}).observe(document, {
    attributes: false,
    attributeOldValue: false,
    characterData: false,
    characterDataOldValue: false,
    childList: true,
    subtree: true
});

document.addEventListener('change', changeClass, false);

document.querySelector('[name="qty5"]').value = 1;

var newinput = document.createElement('input');

newinput.name = 'qty6';
newinput.type = 'number';
newinput.min = 0;
newinput.value = 1;

document.body.appendChild(newinput);

var qty4 = document.querySelector('[name="qty4"]');

qty4.value = 1;
changeClass(qty4);
.noValue {
    background: red;
}
.hasValue {
    background: yellow;
}
<input name="qty1" class="noValue" type="number" min="0" value="0">
<input name="qty2" class="noValue" type="number" min="0" value="0">
<input name="qty3" class="noValue" type="number" min="0" value="0">
<input name="qty4" class="noValue" type="number" min="0" value="0">
<input name="qty5" class="noValue" type="number" min="0" value="0">
Xotic750
  • 22,914
  • 8
  • 57
  • 79
0

I have a page that contains a whole bunch of input boxes of type number. These can be individually changed

For that you can use a change listener on each element. You could delegate to an ancestor, but the change event doesn't bubble in all browsers.

or a set of them can be changed by a selector.

If you change values by script, that will not cause a change event to be dispatched, so you can either manually call the listener, or dispatch your own change event (and make it bubble).

In modern browsers (probably IE 9+) you can do:

function changeInputClass(){
  [].forEach.call(document.querySelectorAll('input[name^=qty]'), function(element) {
    if (element.value > 0) {
      element.classList.add('bold-text');
    } else {
      element.classList.remove('bold-text');
    } 
  });
}

In less modern browsers (even IE 6) you can do:

function changeInputClass(){
  var node, nodes = document.getElementsByTagName('input');
  var nameRE = /^qty/;

  for (var i=0, iLen=nodes.length; i<iLen; i++) {
    node = nodes[i];

    if (nameRE.test(node.name)) {
      if (node.value > 0) {
        node.className = 'bold-text';
      } else {
        node.className = '';
      }
    }
  }
}
RobG
  • 142,382
  • 31
  • 172
  • 209