Knockout, noUiSlider, custom bindings

痴心易碎 提交于 2019-12-11 10:26:35

问题


I am trying to meld knockout and noUiSlider with a custom binding. I have found similar code for the jQuery-UI slider and Knockout and used that as a basis.

If I use the sliderko custom binding below, the noUisliders do not update the observables. I get NaN, and nothing in the input fields.

If I use the slider custom binding below with noUiSlider events directly, then everything works. The slider custom binding doesn't perform well, probably due to tracking the noUiSlider update event. However, that's the only way I could figure out how to get the slider to continuously update the input fields.

I'd like to use Knockout's registerEventHandler, but I'm not sure how to get that to work.

// noUiSlider
ko.bindingHandlers.slider = {
  init: function(element, valueAccessor, allBindingsAccessor) {
    var options = allBindingsAccessor().sliderOptions || {};
    noUiSlider.create(element, options);

    // works with with noUiSlider but not with knockout event bindings
    element.noUiSlider.on('set', function(values, handle) {
      var observable = valueAccessor();
      observable(values[handle]);
    });

    // works with with noUiSlider but not with knockout event bindings
    element.noUiSlider.on('update', function(values, handle) {
      var observable = valueAccessor();
      observable(values[handle]);
    });

    ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
      element.noUiSlider.destroy();
    });
  },
  update: function(element, valueAccessor) {
    var value = ko.utils.unwrapObservable(valueAccessor());
    element.noUiSlider.set(value);

  }
};

// using knockout event handlers
ko.bindingHandlers.sliderko = {
  init: function(element, valueAccessor, allBindingsAccessor) {
    var options = allBindingsAccessor().sliderOptions || {};
    noUiSlider.create(element, options);

    ko.utils.registerEventHandler(element, 'set', function(values, handle) {
      var observable = valueAccessor();
      observable(values[handle]);
    });

    ko.utils.registerEventHandler(element, 'update', function(values, handle) {
      var observable = valueAccessor();
      observable(values[handle]);
    });

    ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
      element.noUiSlider.destroy();
    });
  },
  update: function(element, valueAccessor) {
    var value = ko.utils.unwrapObservable(valueAccessor());
    element.noUiSlider.set(value);

  }
};

// initialization for NoUiSlider - saves from adding stuff into page
var sillysv = {
  start: [10],
  step: 0.01,
  range: {
    'min': 0,
    'max': 100
  }
};

var sillysp = {
  start: [5],
  step: 0.01,
  range: {
    'min': 0,
    'max': 100
  }
};

var ViewModel = function() {
  var self = this;
  self.savings = ko.observable();
  self.spent = ko.observable();
  self.net = ko.computed(function() {
    return self.savings() - self.spent();
  });
};

ko.applyBindings(new ViewModel());
<link href="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/8.1.0/nouislider.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/8.1.0/nouislider.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<h2>Slider Demo</h2>
Savings:
<input data-bind="value: savings" />
<div style="margin: 10px" data-bind="slider: savings, sliderOptions: sillysv"></div>

Spent:
<input data-bind="value: spent" />
<div style="margin: 10px" data-bind="slider: spent, sliderOptions: sillysp"></div>

Net: <span data-bind="text: net"></span>

回答1:


If you're using jQuery there is no difference between binding events with jQuery or ko registerEventHandler. This function is for internal use, and is able to make bindings that work fine in different browsers. If jQuery is available, this function uses jQuery binding.

The second problem, updating the observable so many times, should be solved by throttling the upsated in the observable. You can do that using the rateLimit ko extender directly in your view model:

var ViewModel = function() {
  var self = this;
  self.savings = ko.observable()
    .extend({ rateLimit: { method: "notifyWhenChangesStop", timeout: 400 } });;
  self.spent = ko.observable()
    .extend({ rateLimit: { method: "notifyWhenChangesStop", timeout: 400 } });;
  self.net = ko.computed(function() {
     return self.savings() - self.spent();
}

You can also modify the custom binding if you want to extend the observables in the init. if you do so, you should check that the observable is not already extended: Check if extension was applied to observable.



来源:https://stackoverflow.com/questions/33490510/knockout-nouislider-custom-bindings

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!