Kendo Slider With Text Labels

0 Answers 6 Views
Slider
Lee
Top achievements
Rank 2
Bronze
Bronze
Bronze
Lee asked on 24 Sep 2025, 09:38 PM

I have a need for a slider switch with text labels instead of numbers. Instead of 1,2,3 I need Small, Medium, Large. It does not appear that Kendo UI has a built in way to do this so here is the function I came up with: 

/*
    This helper is designed to allow you to substitute a datasource for values in a kendo slider to do things like:
    "small", "medium", "large". 
    
    It includes 4 functions that should be used instead of the ones included with Kendo UI:

    initializeKendoSlider(options);
    getKendoSliderSelection(elementId);
    resizeKendoSlider(elementId);
    setKendoSliderValue(elementId, newValue);
*/

function initializeKendoSlider(options) {
    /*
        options = {
            elementId: string - required,
            dataSource: [{ label: string, value: any}],
            value: any - the value prop of any dataSource item
            orientation: string - defaults to "horizontal",
            tickPlacement: string - defaults to "bottomRight",
            change: custom change function. Available parameters are: selectedDataItem, e
        };

        Include this in your html to start: 
        <input id="mySlider" name="mySlider" type="text" />

        NOTE: If a proper dataSource is not passed, the slider will build as a numeric Kendo Slider.
        NOTE: The value returned by the .value() function is the index, not the actual value. You must use
              the included getKendoSliderSelection and setKendoSliderValue functions.
        NOTE: The change function will return the selected item as the second parameter which can be used in your custom change function.
        NOTE: Kendo's built in max and min methods will not work properly when using a dataSource.
        NOTE: Small steps are not supported.
    */

    if (!options.elementId || typeof options.elementId !== "string") {
        console.error("No Element ID Passed");
        return false;
    }

    let elementId = options.elementId;

    if (Array.isArray(options.dataSource)) {
        // Destroy the existing slider
        if ($(`#${elementId}`).data("kendoSlider")) {
            $(`#${elementId}`).data("kendoSlider").destroy();
            if ($(`#${elementId}`).closest(".custom-form-slider").length > 0) {
                $(`#${elementId}`).closest(".custom-form-slider").replaceWith($(`#${elementId}`));
            } else if ($(`#${elementId}`).closest(".k-slider").length > 0) {
                $(`#${elementId}`).closest(".k-slider").replaceWith($(`#${elementId}`));
            }
        }

        // Prep options for slider
        let defaultValue = options.value ? options.dataSource.findIndex(x => x.value === options.value) : 0;
        let tickPlacement = options.tickPlacement;
        if (tickPlacement !== "topLeft" && tickPlacement !== "both") {
            tickPlacement = "bottomRight";
        }
        options.tickPlacement = tickPlacement;

        // Build the slider
        let objectSlider = $(`#${elementId}`).kendoSlider({
            showButtons: false,
            dataSource: options.dataSource,
            min: 0,
            max: options.dataSource.length - 1,
            orientation: options.orientation === "vertical" ? options.orientation : "horizontal",
            tickPlacement: tickPlacement,
            value: defaultValue,
            largeStep: 1,
            change: function (e) {
                let selectedDataItem = getKendoSliderSelection(options.elementId);
                if (typeof options.change === "function") {
                    options.change(selectedDataItem, e);
                }
            },
            tooltip: {
                enabled: false
            }
        }).data("kendoSlider");

        // Changes the numbers to text labels
        var sliderItems = $(`#${elementId}`).siblings(".k-slider-items");
        $.each(options.dataSource, function (index, step) {
            var item = sliderItems.find("li:eq(" + (index) + ")");
            item.attr("title", step.label);
            item.find("span").text(step.label);
        });

        // Fixes the alignment due to absulutely positioned labels
        if (sliderItems.length > 0) {
            if (options.orientation !== "vertical" && (tickPlacement === "bottomRight" || tickPlacement === "both")) {
                let left = sliderItems.find("li:eq(0) span")[0].getBoundingClientRect().width;
                let right = sliderItems.find(`li:eq(${options.dataSource.length - 1}) span`)[0].getBoundingClientRect().width;
                $(`#${elementId}`).closest(".k-slider").wrap(`<div class="custom-form-slider" style="padding-left: ${left / 2}px; padding-right: ${right / 2}px; padding-bottom: 1.2em"></div>`);
            } else if (options.orientation === "vertical" && (tickPlacement === "bottomRight" || tickPlacement === "both")) {
                let maxLabelWidth = 0;
                $.each(options.dataSource, function (index) {
                    var item = sliderItems.find("li:eq(" + (index) + ") span");
                    let thisWidth = item[0].getBoundingClientRect().width;
                    if (thisWidth > maxLabelWidth) {
                        maxLabelWidth = thisWidth;
                    }
                });
                $(`#${elementId}`).closest(".k-slider").wrap(`<div class="custom-form-slider" style="display: inline-block; padding-right: ${maxLabelWidth + 10}px; padding-bottom: 14px"></div>`);
            } else if (options.orientation === "horizontal" && (tickPlacement === "topLeft")) {
                let left = sliderItems.find("li:eq(0) span")[0].getBoundingClientRect().width;
                let right = sliderItems.find(`li:eq(${options.dataSource.length - 1}) span`)[0].getBoundingClientRect().width;
                $(`#${elementId}`).closest(".k-slider").wrap(`<div class="custom-form-slider" style="padding-left: ${left / 2}px; padding-right: ${right / 2}px; padding-top: 1.2em"></div>`);
            } else if (options.orientation === "vertical" && (tickPlacement === "topLeft")) {
                let maxLabelWidth = 0;
                $.each(options.dataSource, function (index) {
                    var item = sliderItems.find("li:eq(" + (index) + ") span");
                    let thisWidth = item[0].getBoundingClientRect().width;
                    if (thisWidth > maxLabelWidth) {
                        maxLabelWidth = thisWidth;
                    }
                });
                $(`#${elementId}`).closest(".k-slider").wrap(`<div class="custom-form-slider" style="display: inline-block; padding-left: ${maxLabelWidth + 10}px; padding-bottom: 14px"></div>`);
            } else {
                $(`#${elementId}`).closest(".k-slider").wrap('<div class="custom-form-slider"></div>');
            }
        } else {
            $(`#${elementId}`).closest(".k-slider").wrap('<div class="custom-form-slider"></div>');
        }

        // Add event listener
        const debouncedResize = debounce(() => resizeKendoSlider(elementId), 300);
        window.addEventListener("resize", debouncedResize);

        return objectSlider;
    } else if (options.options) {
        // NOTE: This will use the standard KendoSlider initialization.
        let objectSlider = $(`#${options.elementId}`).kendoSlider(options.options).data("kendoSlider");
        return objectSlider;
    } else {
        console.error("No dataSource or options passed to initializeKendoSlider. Must have at least one");
        return false;
    }
}

function resizeKendoSlider(elementId) {
    let thisSlider = $(`#${elementId}`).data("kendoSlider");
    let options = thisSlider.options;
    let tickPlacement = options.tickPlacement;

    // Trigger the kendo slider resize to get any missing ticks
    thisSlider.resize();

    // Changes the numbers to text labels so we can calculate the size
    let sliderItems = $(`#${elementId}`).siblings(".k-slider-items");
    $.each(options.dataSource, function (index, step) {
        let item = sliderItems.find("li:eq(" + (index) + ")");
        item.find("span").text(step.label);
    });

    // Fixes the alignment due to absulutely positioned labels
    if (sliderItems.length > 0) {
        if (options.orientation !== "vertical" && (tickPlacement === "bottomRight" || tickPlacement === "both")) {
            let left = sliderItems.find("li:eq(0) span")[0].getBoundingClientRect().width;
            let right = sliderItems.find(`li:eq(${options.dataSource.length - 1}) span`)[0].getBoundingClientRect().width;
            $(`#${elementId}`).closest(".custom-form-slider").css({
                paddingRight: `${right / 2}px`,
                paddingLeft: `${left / 2}px`,
                paddingBottom: "1.2em"
            });
        } else if (options.orientation === "vertical" && (tickPlacement === "bottomRight" || tickPlacement === "both")) {
            let maxLabelWidth = 0;
            $.each(options.dataSource, function (index) {
                var item = sliderItems.find("li:eq(" + (index) + ") span");
                let thisWidth = item[0].getBoundingClientRect().width;
                if (thisWidth > maxLabelWidth) {
                    maxLabelWidth = thisWidth;
                }
            });
            $(`#${elementId}`).closest(".custom-form-slider").css({
                display: "inline-block",
                paddingRight: `${maxLabelWidth + 10}px`,
                paddingBottom: "14px"
            });
        } else if (options.orientation === "horizontal" && (tickPlacement === "topLeft")) {
            let left = sliderItems.find("li:eq(0) span")[0].getBoundingClientRect().width;
            let right = sliderItems.find(`li:eq(${options.dataSource.length - 1}) span`)[0].getBoundingClientRect().width;
            $(`#${elementId}`).closest(".custom-form-slider").css({
                paddingTop: "1.2em",
                paddingLeft: `${left / 2}px`,
                paddingRight: `${right / 2}px`
            });
        } else if (options.orientation === "vertical" && (tickPlacement === "topLeft")) {
            let maxLabelWidth = 0;
            $.each(options.dataSource, function (index) {
                var item = sliderItems.find("li:eq(" + (index) + ") span");
                let thisWidth = item[0].getBoundingClientRect().width;
                if (thisWidth > maxLabelWidth) {
                    maxLabelWidth = thisWidth;
                }
            });
            $(`#${elementId}`).closest(".custom-form-slider").css({
                display: "inline-block",
                paddingLeft: `${maxLabelWidth + 10} px`,
                paddingBottom: "14px"
            });
        } else {
            $(`#${elementId}`).closest(".custom-form-slider").css({
                display: "",
                paddingLeft: "",
                paddingBottom: ""
            });
        }
    }

    // Resize again to fix the track since we changed the padding. 
    thisSlider.resize();

    // Then replace the labels since the resize erases them.
    sliderItems = $(`#${elementId}`).siblings(".k-slider-items");
    $.each(options.dataSource, function (index, step) {
        var item = sliderItems.find("li:eq(" + (index) + ")");
        item.attr("title", step.label);
        item.find("span").text(step.label);
    });
}

function getKendoSliderSelection(elementId) {
    let thisSlider = $(`#${elementId}`).data("kendoSlider");
    let dataSource = thisSlider.options.dataSource;
    let value = thisSlider.value();
    if (dataSource) {
        return dataSource[value];
    } else {
        return {
            label: value,
            value: value
        };
    }
}

function setKendoSliderValue(elementId, newValue) {
    // newValue must exist in the dataSource or nothing will change
    let thisSlider = $(`#${elementId}`).data("kendoSlider");
    let dataSource = thisSlider.options.dataSource;
    let newValueIndex = dataSource.findIndex(x => x.value === newValue);
    if (newValueIndex > -1) {
        thisSlider.value(newValueIndex);
    } else {
        console.error(`Attempted to set the value of #${elementId} to non-existing value of ${newValue}`);
    }
    return newValueIndex;
}

function debounce(func, timeout = 300){
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => { func.apply(this, args); }, timeout);
  };
}

window.initializeKendoSlider = initializeKendoSlider;
window.getKendoSliderSelection = getKendoSliderSelection;
window.setKendoSliderValue = setKendoSliderValue;
window.resizeKendoSlider = resizeKendoSlider;

No answers yet. Maybe you can help?

Tags
Slider
Asked by
Lee
Top achievements
Rank 2
Bronze
Bronze
Bronze
Share this question
or