Skip to content Skip to sidebar Skip to footer

Detecting Number Input Spinner Click

I've got a simple number input with a min='1' and max='12' value set, this is used as an hour selector. I'd like it to cycle through the hours, so when you get to 12 and press the

Solution 1:

You have to handle the input event, like this:

$('[type=number]').on('input',function(){
  this.value %= 12 ;
  if( this.value < 1 )
    this.value -= -12 ;
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type=number>

Solution 2:

I searched a lot and it seems there is no way to natively detect that. That makes this one a very important question because I think this should be added to new versions of HTML.

There are many possible workarouds. They all fail on the problem the it's impossible to know, in which direction is value going. I decided to use mouse position information to detect, whether is user increasing or decreasing a value. It works, but does not properly handle the situation, when user holds the button.

var inputTimer = null;

function cycle(event) {
  var value = this.value;
  // Value deep within bonds -> no action
  if(value>this.min && value<this.max) {
    return;  
  }
  // Check coordinate of the mouse
  var x,y;
  //This is the current screen rectangle of input
  var rect = this.getBoundingClientRect();
  var width = rect.right - rect.left;
  var height = rect.bottom-rect.top;
  //Recalculate mouse offsets to relative offsets
  x = event.clientX - rect.left;
  y = event.clientY - rect.top;
  // Now let's say that we expect the click only in the last 80%
  // of the input
  if(x/width<0.8) {
    console.log("Not click on arrows.", x, width);  
    return;
  }
  // Check "clicked button" by checking how high on input was clicked
  var percentHeight = y/height;
  // Top arrow was clicked
  if(percentHeight<0.5 && value==this.max) {
      this.value = this.min; 
      event.preventDefault();
      return false;
  }
  // Bottom arrow was clicked
  if(percentHeight>0.5 && value==this.min) {
      this.value = this.max; 
      event.preventDefault();
      return false;
  }
}
var input = document.getElementById("number");
input.addEventListener("mousedown", cycle);
<input id="number" type="number" min="1" max="12" value="12" />

Solution 3:

I think this is what you really want.

<input type="time" value="01:00" step="600"/>

There is currently no native way to capture the arrow input events separate from the input box events. Everything using number input seems to be kinda hacky for this purpose.

Next best option is something like http://jdewit.github.io/bootstrap-timepicker/


Solution 4:

This doesn't work for your specific situation where you have a maximum and want it to wrap, but it might be helpful for others who want to process the field value based on changes via arrows, such as for setting .toFixed(2) to a currency value like I needed:

document.getElementById('el').setAttribute('data-last',document.getElementById('el').value);
document.getElementById('el').addEventListener('keyup', function(){
    this.setAttribute('data-last',this.value);
});
document.getElementById('el').addEventListener('click', function(){
    if(this.value>this.getAttribute('data-last')) console.log('up clicked');
    if(this.value<this.getAttribute('data-last')) console.log('down clicked');
});

Solution 5:

This is my code written in JQuery , this one can implement auto-increment ( + & - ) long-press spin buttons .

$.fn.spinInput = function (options) {
    var settings = $.extend({
        maximum: 1000,
        minimum: 0,
        value: 1,
        onChange: null
    }, options);

    return this.each(function (index, item) {
        var min = $(item).find('>*:first-child').first();
        var max = $(item).find('>*:last-child').first();
        var v_span = $(item).find('>*:nth-child(2)').find('span');
        var v_input = $(item).find('>*:nth-child(2)').find('input');
        var value = settings.value;
        $(v_input).val(value);
        $(v_span).text(value);
        async function increment() {
            value = Number.parseInt($(v_input).val());
            if ((value - 1) > settings.maximum) return;
            value++;
            $(v_input).val(value);
            $(v_span).text(value);
            if (settings.onChange) settings.onChange(value);
        }
        async function desincrement() {
            value = Number.parseInt($(v_input).val());
            if ((value - 1) < settings.minimum) return;
            value--
            $(v_input).val(value);
            $(v_span).text(value);
            if (settings.onChange) settings.onChange(value);
        }
        var pressTimer;

        function actionHandler(btn, fct, time = 100, ...args) {
            function longHandler() {
                pressTimer = window.setTimeout(function () {
                    fct(...args);
                    clearTimeout(pressTimer);
                    longHandler()
                }, time);
            }
            $(btn).mouseup(function () {
                clearTimeout(pressTimer);
            }).mousedown(function () {
                longHandler();
            });

            $(btn).click(function () {
                fct(...args);
            });
        }

        actionHandler(min, desincrement, 100);
        actionHandler(max, increment, 100)
    })
}




$('body').ready(function () {
    $('.spin-input').spinInput({ value: 1, minimum: 1 });
});
:root {
    --primary-dark-color: #F3283C;
    --primary-light-color: #FF6978;
    --success-dark-color: #32A071;
    --sucess-light-color: #06E775;
    --alert-light-color: #a42a23;
    --alert-dark-color: #7a1f1a;
    --secondary-dark-color: #666666;
    --secondary-light-color: #A6A6A6;
    --gold-dark-color: #FFA500;
    --gold-light-color: #FFBD00;
    --default-dark-color: #1E2C31;
    --default-light-color: #E5E5E5;
}

.fx-row {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
}

.fx-colum {
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
}

.fx-colum.nowrap,
.fx-row.nowrap {
    flex-wrap: nowrap;
}

.fx-row.fx-fill>*,
.fx-colum.fx-fill>* {
    flex-grow: 1;
}

.spin-input {
    border: 1px solid var(--secondary-light-color);
}

.spin-input>div:first-child {
    cursor: pointer;
    border-right: 1px solid var(--secondary-light-color);
}

.spin-input>div:first-child:active {
    transform: translate3d(1px, 0px, 1px)
}

.spin-input>div:last-child {
    flex: none;
    border-left: 1px solid var(--secondary-light-color);
    cursor: pointer;
}

.spin-input>div:last-child:active {
    transform: translate3d(1px, 0px, 1px)
}

.icon {
    font-weight: bold;
    text-align: center;
    vertical-align: middle;
    padding: 12px;
    font-size: 28px;
}

.icon.primary,
.icon.primary .ci {
    color: var(--primary-dark-color);
}

.icon.reactive:hover .ci {
    color: var(--primary-light-color);
}

.hidden {
    display: none;
}
<script src="https://releases.jquery.com/git/jquery-3.x-git.min.js"></script>
<div class="spin-input nowrap fx-row fx-fill" >
                        <div class="icon reactive">
                            <span class="ci ci-minus">-</span>
                        </div>
                        <div class="icon">
                            <span>0</span>
                            <input type="text" class="hidden" value="0">
                        </div>
                        <div class="icon reactive">
                            <span class="ci ci-plus">+</span>
                        </div>
                    </div>

There is my jQuery plugin , I hope that can help you .


Post a Comment for "Detecting Number Input Spinner Click"