IonDen / ion.rangeSlider

jQuery only range slider
http://ionden.com/a/plugins/ion.rangeSlider/en.html
MIT License
2.55k stars 507 forks source link

Integration: Ion.RangeSlider + DataTables.net #745

Closed arnonrdp closed 2 years ago

arnonrdp commented 3 years ago

I am trying an integration between DataTables and Ion.RangeSlider, but it is not working. My data is not being filtered when I am using the slider, it works only when I use the inputs.

Here is where I am using: http://myoption.com.br/ Just click on the gear on top right. There you can see the range slider. It should work on the column [6] called Strike.

Looking to the HTML and JS, do you guys know what am I missing?

<tr>
  <td><input type="text" size="5" class="js-input-from" id="min" name="min" value="0" /></td>
  <td class="col-8"><input type="text" class="js-range-slider" value="" /></td>
  <td><input type="text" size="5" class="js-input-to" id="max" name="max" value="0" /></td>
</tr>
$(function () {
  "use strict";

  /* Data Table Range Filtering */
  $.fn.dataTable.ext.search.push(
    function (settings, data, dataIndex) {
      var min = parseInt($('#min').val(), 10);
      var max = parseInt($('#max').val(), 10);
      var strike = parseFloat(data[6]) || 0; // use data to column number

      if ((isNaN(min) && isNaN(max)) ||
      (isNaN(min) && strike <= max) ||
      (min <= strike && isNaN(max)) ||
      (min <= strike && strike <= max)) {
        return true;
      }
        return false;
    }
  );

  // Ion Range Slider
  var $range = $(".js-range-slider"),
  $inputFrom = $(".js-input-from"),
  $inputTo = $(".js-input-to"),
  instance,
  min = 0,
  max = 100,
  from = 0,
  to = 0;

  $range.ionRangeSlider({
    type: "double", min: min, max: max,
    onStart: updateInputs,
    onChange: updateInputs,
    onFinish: updateInputs
  });
  instance = $range.data("ionRangeSlider");

  function updateInputs(data) {
    from = data.from;
    to = data.to;
    $inputFrom.prop("value", from);
    $inputTo.prop("value", to);
  }

  $inputFrom.on("input", function () {
    var val = $(this).prop("value");
    // validate
    if (val < min) {
      val = min;
    } else if (val > to) {
      val = to;
    }
    instance.update({
      from: val
    });
  });

  $inputTo.on("input", function () {
    var val = $(this).prop("value");
    // validate
    if (val < from) {
      val = from;
    } else if (val > max) {
      val = max;
    }
    instance.update({
      to: val
    });
  });
});

$(document).ready(function () {

  var table = $('#ajaxTable').DataTable({
    ajax: "../../dados/opcoes.json",
    columns: [
      { data: 0 },
      { data: 1 },
      { data: 2 },
      { data: 3 },
      { data: 4 },
      { data: 5 },
      { data: 6 },
      { data: 7 },
      { data: 8 },
      { data: 9 },
      { data: 10 },
      { data: 11 },
      { data: 12 },
      { data: 13 },
      { data: 14 },
      { data: 15 },
    ],
  });

  // Event listener to the two range filtering inputs to redraw on input
  $('#min, #max').keyup(function () {
    table.draw();
  });
});
arnonrdp commented 3 years ago

This is the first time I am posting on github, so please take it easy with me. lol

I used this example: https://datatables.net/examples/plug-ins/range_filtering.html to start making this integration.

IonDen commented 3 years ago

Hi, it is not working because of this:

  $('#min, #max').keyup(function () {
    table.draw();
  });

If you will look carefully you will notice that min and max input are listening for manual keyUp event and ignoring everything else. This is a weird behaviour, because you could not only change value by using your keyboard, you could paste it for example.

  1. So first you need to do is to change keyup to input
  2. If it will not work, than you will also need to trigger input event manually here. Like this:
    function updateInputs(data) {
    from = data.from;
    to = data.to;
    $inputFrom.prop("value", from);
    $inputTo.prop("value", to);
    $inputFrom.trigger('input'); // here
    $inputTo.trigger('input'); // and here
    }
arnonrdp commented 3 years ago

I made a simple live datatable so you can edit on your hands: http://live.datatables.net/gatadaqa/1/edit

If you make it work here, I believe I can make it work there.

I wonder what is the best way to do it because when it is working I am about to apply range slider filtering over a lot of columns.

IonDen commented 3 years ago

Fixed

http://live.datatables.net/sivelagi/1/edit

arnonrdp commented 3 years ago

Works pretty fine. I appreciate your help.

I have dynamic data over table. Where can I use Math.min() and Math.max()? Or is there any other method to identify?

arnonrdp commented 3 years ago

I took the example you fixed to insert another range slider, but it is not working and I don't know what I am doing wrong.

Here is: http://live.datatables.net/sivelagi/2/edit

I will also ask on datatables forum how to use Math.min() and Math.max().

IonDen commented 3 years ago

Basic idea behind many sliders is that you need to have many of everything else (instances, support functions, etc.)

To not to do it manually (that usually leads to mistakes like yours). I would recommend you to create a wrapper class, which will generate all logic for every range slider you are using and have a public methods to control it.

I can give you a small hint how to do that, but for the rest - please go to StackOverflow. Because this is already an off-topic and your job to figure it out :)

Hint:

class IonRangeWrapper {
  constructor() {
    // init ion.rangeSlider
    // create instance
    // connect it to inputs
  }

  update() {} // public method
}

// then you will just create as many instances of that class as needed, like this.

const slider1 = new IonRangeWrapper(config);
const slider2 = new IonRangeWrapper(config);
arnonrdp commented 3 years ago

Appreciate your help. Thanks a lot Ion!!

arnonrdp commented 3 years ago

I made it. But I confess I think the code is still really big. Here is what I did:

class Range {
  constructor(min, max, updateInputs) {
    this.min = min;
    this.max = max;
    this.from = min;
    this.to = max;
    this.type = "double";
    this.onStart = updateInputs;
    this.onChange = updateInputs;
    this.onFinish = updateInputs;
  }
}
class InputFrom {
  constructor(el, min, instance) {
    var val = $(el).prop("value");
    if (val < min) { val = min; }
    else if (val > to) { val = to; }
    instance.update({ from: val });
  }
}
class InputTo {
  constructor(el, max, instance) {
    var val = $(el).prop("value");
    if (val < from) { val = from; }
    else if (val > max) { val = max; }
    instance.update({ to: val });
  }
}

// COLUNA STRIKE //
var $rangeStrike = $(".rangeStrike");
var $inputFromStrike = $(".fromStrike");
var $inputToStrike = $(".toStrike");
var minStrike = 0;
var maxStrike = 200;

$rangeStrike.ionRangeSlider(new Range(minStrike, maxStrike, updateInputsStrike));
var instanceStrike = $rangeStrike.data("ionRangeSlider");

$inputFromStrike.on("input", function () { new InputFrom(this, minStrike, instanceStrike) });
$inputToStrike.on("input", function () { new InputTo(this, maxStrike, instanceStrike) });

function updateInputsStrike(data) {
  from = data.from;
  to = data.to;
  $inputFromStrike.prop("value", from);
  $inputToStrike.prop("value", to);
  table.draw();
}

// COLUNA PREÇO DA AÇÃO //
var $rangePracao = $(".rangePracao");
var $inputFromPracao = $(".fromPracao");
var $inputToPracao = $(".toPracao");
var minPracao = 0;
var maxPracao = 100;

$rangePracao.ionRangeSlider(new Range(minPracao, maxPracao, updateInputsPracao));
var instancePracao = $rangePracao.data("ionRangeSlider");

$inputFromPracao.on("input", function () { new InputFrom(this, minPracao, instancePracao) });
$inputToPracao.on("input", function () { new InputTo(this, maxPracao, instancePracao) });

function updateInputsPracao(data) {
  from = data.from;
  to = data.to;
  $inputFromPracao.prop("value", from);
  $inputToPracao.prop("value", to);
  table.draw();
}

// Event listener to the two range filtering inputs to redraw on input
$('#minStrike, #maxStrike, #minPracao, #maxPracao').keyup(function () {
  table.draw();
});

I believe it is possible to create a Constructor to updateInputs function, but I confess I don't know hot to do it.

IonDen commented 3 years ago

Told you) This is already a question to Stack Overflow)