Slider with dynamic ticks and labels

Hello,

Here is a slider custom component that accepts an arbitrary numbers of labels (as well as the other expected properties). Some of the code is adapted from the slider component in the Anvil library.

Special thanks to @stucork for the killer CSS assistance (original post is here).

Clone:
https://anvil.works/build#clone:O7FJIMTCQLAEJ6KF=N66BOAMM42CDIENGLTZNPEKO

HTML:

<div class="range">
  <input type="range" id="range">
  <div class="ticks" id="ticks">
    <!-- JS generates the spans here -->
  </div>
</div>

JS for dynamically setting labels and ticks:

function set_tick_labels(comp, array, minval, maxval, step, value) {

  // set attributes of range slider
  //var range = document.getElementById("range")
  var range = comp.v._anvil.element[0]
  range.setAttribute('min', minval);
  range.setAttribute('maxval', maxval);
  range.setAttribute('step', step);
  range.setAttribute('value', value);
  
  // get the inner "ticks" div 
  //var ticks = document.getElementById("ticks");
  var ticks = $(range).find("div").find("div");
  
  // for item in label array:
  array.forEach(function (item, index) {
    
      	// create a span
  		var span = document.createElement("SPAN");
  
  		// set text to label, set class, append
  		span.textContent = item;
  		span.setAttribute('class', 'tick');
  		ticks[0].appendChild(span)
        
	});
}
5 Likes

Hmm, I just realized that when I put more than one of my slider component on the screen at once, I run into the problem of not being able to distinguish between components in JS.

I believe I’ve been down this road before according to these posts:

Thanks again to @stucork, I was able to pass the components themselves to JS and select them using some methods that are still quite mysterious to me.

For example (and you can see this in the above JS too),
I wanted to use:

var range = document.getElementById("range")

But that selected both slider (i.e., range) components on the screen, so I used the following techniques from the linked post above (I admit that I don’t fully understand how this works):

// select the anvil component that is passed to JS
var range = comp.v._anvil.element[0]
.
.
.
// get the inner "ticks" div 
var ticks = $(range).find("div").find("div");
.
.
.
ticks[0].appendChild(span)

I just want to point this out in case I’m doing something horribly wrong. Some of it is not pretty but somehow it all works.

This looks good to me. Worth noting that the [0] gets the dom element and without the [0] you get the jquery element so you could change it to

// select the component as jquery
var range = comp.v._anvil.element
.
.
.
// get the inner "ticks" div 
var ticks = range.find(".ticks");
.
.
.

Also worth noting that this is a total hack.
I believe it’s in the pipeline for anvil to add a JavaScript method getElement that will be a documented/supported way to do the first line.

Now that it’s open source maybe I’ll get round to making that change and submitting a pull request :upside_down_face:

1 Like

Pseudo-pull request:
I moved the code initializing the slider’s min/max values etc. to the slider’s form_show (rather than the Main form’s form_show in the demo) so that the behavior is as (I) expected when using the slider component elsewhere.
https://anvil.works/build#clone:Y5LUOEM5XWUSFREF=JMXUOTMM47I5ZPIPFLQFQYEK

The other issues I had trying to use this today are to do with the formatting of the tick labels (using “label” loosely here–they’re not Anvil labels but rather something set with JavaScript in the Custom HTML).

  1. When a label is too long so that it wraps to multiple lines (like “strongly agree” in the demo), I’d like those lines to be center- rather than left-aligned.
  2. I’d also like to be able to increase the width allowed before a label wraps to another line. (I figured out how to move the first and last ticks away from the edge of the HTML form so that there is room for a wider label there, but I couldn’t see how to increase the width of the labels themselves.)

Are these things easy to do for someone who understands JS and CSS better than me?

Another update: https://anvil.works/build#clone:LJXTMBLFQIHI4C2C=D4YN6Q7GBPBHNVK5HPFCX2BK

  • Added ‘enabled’ and ‘is_visible’ properties
  • Now omitting labels shows no ticks or labels (fixing a “bug” that previously showed a single ‘min’ tick)
  • Some code cleanup
1 Like