3

After setting the max attribute of input type="range" range thumb do not redraw.

Is there a correct way to update thumb position after changing the max value?

I found the following way:

<input type="range" min="0" max="100" value="50" />

var $i = $('input[type="range"]');
$i.attr('max', 200);
// hack to redraw thumb position
$i.val(0);$i.val(50);

example: http://jsfiddle.net/mJQx9/

dk547
  • 33
  • 3

2 Answers2

4

I believe you may have stumbled across a bug in WebKit-based browsers (or at the very least, in Chrome).

If we start by taking into account the fact that WebKit will not dispatch the 'DOMAttrModified' event and therefore fall back upon the DOMSubtreeModified event which works cross-browser, it's easy to see that no DOM events are fired when updating the max attribute in Chrome/WebKit. Here's a fiddle:

http://jsfiddle.net/mJQx9/5/

Run the same example in a different browser (such as IE11), and you'll find that the DOMSubtreeModified event fires as expected (and more importantly, that the element automatically redraws as expected).

Furthermore, you can also find that changing the value of other attributes, such as name, will cause the DOMSubtreeModified event to fire in WebKit/Chrome. And that if you completely remove the max attribute before assigning the new value you will get two DOMSubtreeModified events from WebKit/Chrome; one for the removal of the attribute, and one for the assignment of the new value. To further muddy the waters, even when the DOMSubtreeModified event fires, the element still does not redraw (in WebKit/Chrome). So it appears as if there are a couple of bugs here:

  1. WebKit/Chrome does not properly detect and report changes to the value of the max attribute.
  2. WebKit/Chrome does not redraw elements in all cases where it should.

That seems like a problem, as one would intuitively expect the browser to detect such changes and automatically redraw an element whenever any state is changed that would affect its current appearance. However, it's possible that either the HTML5 spec is moot on these points or that WebKit/Chrome is in fact following some rigid interpretation of the spec. In which case there's an army of pedants coming to explain how WebKit/Chrome's confusing behavior is actually "correct" and to crucify me for suggesting that a browser should do an intuitive thing that's not technically in-spec.

In any case, in terms of a practical solution to this issue I think you are stuck with hacks for now. What you've got isn't terrible, although you could take PushOk's suggestion, and add a redraw() function to jQuery. Something like:

$.fn.redraw = function(){
    $(this).each(function(){
        if (this.value && ! isNaN(parseInt(this.value, 10))) {
            this.value++;
            this.value--;
        }
    });
};


$i.attr('max', 200);                

// hack to redraw thumb position
$i.redraw();

...or if you really don't like having to remember to call redraw() every time you change something, you can jump through some extra hoops and do what's discussed in the accepted answer here to set up an event listener that will detect the attribute change. Which would allow you to have a single redraw() call in your event listener, rather than one in each place where you modify the max attribute.

Community
  • 1
  • 1
aroth
  • 54,026
  • 20
  • 135
  • 176
  • Thanks for your great answer :-) I don't know why I get Webkit bugs for Chrome or Safari these days! Last time I got a bug in Safari WebKit for z-index issue in 3D transformation and now this one! – Qorbani May 01 '15 at 06:46
0
var $i = $('input[type="range"]');
$i.attr('max', 200);

$.fn.redraw = function(){
  $(this).each(function(){
    var redraw = this.offsetHeight;
  });
};

// hack to redraw thumb position
$i.redraw();

http://jsfiddle.net/mJQx9/

PushOk
  • 1
  • 1