UPDATE: I am leaving this answer here as an example of how to use mouse events to use range/slider interactions in desktop (but not mobile) browsers. However, I have now also written a completely different and, I believe, better answer elsewhere on this page that uses a different approach to providing a cross-browser desktop-and-mobile solution to this problem.
Original answer:
Summary: A cross-browser, plain JavaScript (i.e. no-jQuery) solution to allow reading range input values without using on('input'...
and/or on('change'...
which work inconsistently between browsers.
As of today (late Feb, 2016), there is still browser inconsistency so I'm providing a new work-around here.
The problem: When using a range input, i.e. a slider, on('input'...
provides continuously updated range values in Mac and Windows Firefox, Chrome and Opera as well as Mac Safari, while on('change'...
only reports the range value upon mouse-up. In contrast, in Internet Explorer (v11), on('input'...
does not work at all, and on('change'...
is continuously updated.
I report here 2 strategies to get identical continuous range value reporting in all browsers using vanilla JavaScript (i.e. no jQuery) by using the mousedown, mousemove and (possibly) mouseup events.
Strategy 1: Shorter but less efficient
If you prefer shorter code over more efficient code, you can use this 1st solution which uses mousesdown and mousemove but not mouseup. This reads the slider as needed, but continues firing unnecessarily during any mouse-over events, even when the user has not clicked and is thus not dragging the slider. It essentially reads the range value both after 'mousedown' and during 'mousemove' events, slightly delaying each using requestAnimationFrame
.
var rng = document.querySelector("input");_x000D_
_x000D_
read("mousedown");_x000D_
read("mousemove");_x000D_
read("keydown"); // include this to also allow keyboard control_x000D_
_x000D_
function read(evtType) {_x000D_
rng.addEventListener(evtType, function() {_x000D_
window.requestAnimationFrame(function () {_x000D_
document.querySelector("div").innerHTML = rng.value;_x000D_
rng.setAttribute("aria-valuenow", rng.value); // include for accessibility_x000D_
});_x000D_
});_x000D_
}
_x000D_
<div>50</div><input type="range"/>
_x000D_
Strategy 2: Longer but more efficient
If you need more efficient code and can tolerate longer code length, then you can use the following solution which uses mousedown, mousemove and mouseup. This also reads the slider as needed, but appropriately stops reading it as soon as the mouse button is released. The essential difference is that is only starts listening for 'mousemove' after 'mousedown', and it stops listening for 'mousemove' after 'mouseup'.
var rng = document.querySelector("input");_x000D_
_x000D_
var listener = function() {_x000D_
window.requestAnimationFrame(function() {_x000D_
document.querySelector("div").innerHTML = rng.value;_x000D_
});_x000D_
};_x000D_
_x000D_
rng.addEventListener("mousedown", function() {_x000D_
listener();_x000D_
rng.addEventListener("mousemove", listener);_x000D_
});_x000D_
rng.addEventListener("mouseup", function() {_x000D_
rng.removeEventListener("mousemove", listener);_x000D_
});_x000D_
_x000D_
// include the following line to maintain accessibility_x000D_
// by allowing the listener to also be fired for_x000D_
// appropriate keyboard events_x000D_
rng.addEventListener("keydown", listener);
_x000D_
<div>50</div><input type="range"/>
_x000D_
Demo: Fuller explanation of the need for, and implementation of, the above work-arounds
The following code more fully demonstrates numerous aspects of this strategy. Explanations are embedded in the demonstration:
var select, inp, listen, unlisten, anim, show, onInp, onChg, onDn1, onDn2, onMv1, onMv2, onUp, onMvCombo1, onDnCombo1, onUpCombo2, onMvCombo2, onDnCombo2;_x000D_
_x000D_
select = function(selctr) { return document.querySelector(selctr); };_x000D_
inp = select("input");_x000D_
listen = function(evtTyp, cb) { return inp. addEventListener(evtTyp, cb); };_x000D_
unlisten = function(evtTyp, cb) { return inp.removeEventListener(evtTyp, cb); };_x000D_
anim = function(cb) { return window.requestAnimationFrame(cb); };_x000D_
show = function(id) {_x000D_
return function() {_x000D_
select("#" + id + " td~td~td" ).innerHTML = inp.value;_x000D_
select("#" + id + " td~td~td~td").innerHTML = (Math.random() * 1e20).toString(36); // random text_x000D_
};_x000D_
};_x000D_
_x000D_
onInp = show("inp" ) ;_x000D_
onChg = show("chg" ) ;_x000D_
onDn1 = show("mdn1") ;_x000D_
onDn2 = function() {anim(show("mdn2")); };_x000D_
onMv1 = show("mmv1") ;_x000D_
onMv2 = function() {anim(show("mmv2")); };_x000D_
onUp = show("mup" ) ;_x000D_
onMvCombo1 = function() {anim(show("cmb1")); };_x000D_
onDnCombo1 = function() {anim(show("cmb1")); listen("mousemove", onMvCombo1);};_x000D_
onUpCombo2 = function() { unlisten("mousemove", onMvCombo2);};_x000D_
onMvCombo2 = function() {anim(show("cmb2")); };_x000D_
onDnCombo2 = function() {anim(show("cmb2")); listen("mousemove", onMvCombo2);};_x000D_
_x000D_
listen("input" , onInp );_x000D_
listen("change" , onChg );_x000D_
listen("mousedown", onDn1 );_x000D_
listen("mousedown", onDn2 );_x000D_
listen("mousemove", onMv1 );_x000D_
listen("mousemove", onMv2 );_x000D_
listen("mouseup" , onUp );_x000D_
listen("mousedown", onDnCombo1);_x000D_
listen("mousedown", onDnCombo2);_x000D_
listen("mouseup" , onUpCombo2);
_x000D_
table {border-collapse: collapse; font: 10pt Courier;}_x000D_
th, td {border: solid black 1px; padding: 0 0.5em;}_x000D_
input {margin: 2em;}_x000D_
li {padding-bottom: 1em;}
_x000D_
<p>Click on 'Full page' to see the demonstration properly.</p>_x000D_
<table>_x000D_
<tr><th></th><th>event</th><th>range value</th><th>random update indicator</th></tr>_x000D_
<tr id="inp" ><td>A</td><td>input </td><td>100</td><td>-</td></tr>_x000D_
<tr id="chg" ><td>B</td><td>change </td><td>100</td><td>-</td></tr>_x000D_
<tr id="mdn1"><td>C</td><td>mousedown </td><td>100</td><td>-</td></tr>_x000D_
<tr id="mdn2"><td>D</td><td>mousedown using requestAnimationFrame</td><td>100</td><td>-</td></tr>_x000D_
<tr id="mmv1"><td>E</td><td>mousemove </td><td>100</td><td>-</td></tr>_x000D_
<tr id="mmv2"><td>F</td><td>mousemove using requestAnimationFrame</td><td>100</td><td>-</td></tr>_x000D_
<tr id="mup" ><td>G</td><td>mouseup </td><td>100</td><td>-</td></tr>_x000D_
<tr id="cmb1"><td>H</td><td>mousedown/move combo </td><td>100</td><td>-</td></tr>_x000D_
<tr id="cmb2"><td>I</td><td>mousedown/move/up combo </td><td>100</td><td>-</td></tr>_x000D_
</table>_x000D_
<input type="range" min="100" max="999" value="100"/>_x000D_
<ol>_x000D_
<li>The 'range value' column shows the value of the 'value' attribute of the range-type input, i.e. the slider. The 'random update indicator' column shows random text as an indicator of whether events are being actively fired and handled.</li>_x000D_
<li>To see browser differences between input and change event implementations, use the slider in different browsers and compare A and B.</li>_x000D_
<li>To see the importance of 'requestAnimationFrame' on 'mousedown', click a new location on the slider and compare C (incorrect) and D (correct).</li>_x000D_
<li>To see the importance of 'requestAnimationFrame' on 'mousemove', click and drag but do not release the slider, and compare E (often 1 pixel behind) and F (correct).</li>_x000D_
<li>To see why an initial mousedown is required (i.e. to see why mousemove alone is insufficient), click and hold but do not drag the slider and compare E (incorrect), F (incorrect) and H (correct).</li>_x000D_
<li>To see how the mouse event combinations can provide a work-around for continuous update of a range-type input, use the slider in any manner and note whichever of A or B continuously updates the range value in your current browser. Then, while still using the slider, note that H and I provide the same continuously updated range value readings as A or B.</li>_x000D_
<li>To see how the mouseup event reduces unnecessary calculations in the work-around, use the slider in any manner and compare H and I. They both provide correct range value readings. However, then ensure the mouse is released (i.e. not clicked) and move it over the slider without clicking and notice the ongoing updates in the third table column for H but not I.</li>_x000D_
</ol>
_x000D_