I've written a script for a simple jquery ui slider. There are two sliders (later I'll add more) and when you change their value, it displays below them, and then updates a total. What I'm having a hard time figuring out, is how to make it so as you're sliding the values are getting updated, instead of getting updated after you've finished.
Thanks for any help!
Fiddle of Demo
http://jsfiddle.net/tMmDy/
HTML
<div class="slider_1 slider"></div>
<p id="slider_1-value"></p>
<div class="slider_2 slider"></div>
<p id="slider_2-value"></p>
CSS
.slider {
width:100px;
height:5px;
background:blue;
}
JS
$(".slider").slider({
animate: "fast",
max: 25,
min: 0,
step: 1,
value: 10,
option: {}
});
$(".slider_1").on("slidechange", function (event, ui) {
total_1 = $(".slider_1").slider("value");
$("#slider_1-value").html(total_1);
total_value_update();
});
$(".slider_2").on("slidechange", function (event, ui) {
total_2 = $(".slider_2").slider("value");
$("#slider_2-value").html(total_2);
total_value_update();
});
function total_value_update() {
total_values = total_1 + total_2;
$("#total_value").html(total_values);
}
Use the slider's .slide() event and try it like this:
jsFiddle example
var total_1, total_2;
$(".slider").slider({
animate: "fast",
max: 25,
min: 0,
value: 10,
slide: function (event, ui) {
total_1 = $(".slider_1").slider("value");
total_2 = $(".slider_2").slider("value");
$("#slider_1-value").html(total_1);
$("#slider_2-value").html(total_2);
total_value_update();
},
change: function (event, ui) {
total_1 = $(".slider_1").slider("value");
total_2 = $(".slider_2").slider("value");
$("#slider_1-value").html(total_1);
$("#slider_2-value").html(total_2);
total_value_update();
}
});
function total_value_update() {
total_values = total_1 + total_2;
$("#total_value").html(total_values);
}
Related
I do have some dynamically loaded ItemViews that load into layout regions. The templates contain jquery-ui components, e.g. a slider '#mySlider'. I do initialize the component with the Maronette.Region onShow event. My view looks like this:
var MyView = Backbone.Marionette.ItemView.extend({
template: '#my-tpl',
initialize: function() {
_.bindAll(this);
},
onShow: function(){
$('#mySlider').slider({
min: 1,
max: 10,
slide: function( event, ui ) {
//some code here to update the the Views model, like
//this.model.set({'stroke': ui.value});
}});
.....
Obviously this does not work, because the this.model is not defined like so within #mySlider. How do I properly do this and capture the jquery-ui events as as Marionette.ItemView event?
A simple closure will do.
fiddle: http://jsfiddle.net/puleos/z7QsC/
var SliderView = Marionette.ItemView.extend({
template: "#slide-template",
initialize: function() {
_.bindAll(this);
},
onShow: function() {
var self = this;
$('#slider-range').slider({
min: 1,
max: 10,
slide: self.updateSlider
});
},
updateSlider: function(event, ui) {
this.model.set({'stroke': ui.value});
}
});
I have a jquery-ui slider which updates a textbox with the slider's value.
the textbox has ng-model so I can get the value from the controller - but the value is not updated after the slider is moved (the value is changing inside the textbox visually, but $scope.slider remains the same).
If I change the value manually inside the textbox everything is working as expected and the value of $scope.slider is updated with the new value.
Is there a way to make the slider update the value for the scope as well?
<input type="text" id="rent" ng-model="rent" style="border: 0; color: #f6931f; font-weight: bold;" />
<div id="slider-rent" style="width: 80%;"></div>
$("#slider-rent").slider({
range: false,
min: 0,
max: 20000,
step: 10,
value: 0,
slide: function (event, ui) {
$("#rent").val(ui.value);
}
});
$("#rent").val($("#slider-rent").slider("value"));
$("#rent").change(function () {
$("#slider-rent").slider("value", $("#rent").val());
});
(This is a rtl slider, this is why the values are negative)
It would be better to put your slider code into an angular directive so you can access the controller scope.
However if you trigger input event on the input element it will update the angular model
function updateInputValue( newVal){
$("#rent").val(newVal).trigger('input');
}
$(function () {
$("#slider-rent").slider({
range: false,
min: 0,
max: 20000,
step: 10,
value: 0,
slide: function (event, ui) {
updateInputValue(ui.value);
}
});
updateInputValue($("#slider-rent").slider("value"));
$("#rent").change(function () {
$("#slider-rent").slider("value", $("#rent").val());
});
})
DEMO:http://jsfiddle.net/zwHQs/
Try this:
slide: function (event, ui) {
$scope.rent = ui.value;
}
The above assumes the code you show is inside/wrapped in a directive.
I want to embed the max of my sliders range in an html data parameter. I did some debug, and despite the fact that the data can be accessed and is a number, the slider will still use the default max of 100.
My HTML:
<div class="slider" data-max="10"></div>
<label for="slider_value">Slider Value:</label>
<input type="text" id="slider_value" />
My Javascript:
$(document).ready(function () {
$("div.slider").slider({
min: 0,
max: $(this).data("max"),
slide: function (event, ui) {
$("input#slider_value").val(ui.value);
}
});
});
See this fiddle
When the argument object for slider() is evaluated, this is a reference to the document object, not div.slider. You'd need to find div.slider again or save a reference to it (demo):
$(document).ready(function () {
var div = $("div.slider");
div.slider({
min: 0,
max: div.data("max"),
slide: function (event, ui) {
$("input#slider_value").val(ui.value);
}
});
});
Use the jQuery UI create event with option method to set options dynamically:
$(document).ready(function() {
$('div.slider').slider({
min: 0,
create: function(event, ui) {
$(this).slider('option', 'max', $(this).data('max'));
},
slide: function(event, ui) {
$("input#slider_value").val(ui.value);
}
});
});
I'm trying to figure out if knockout js would work nicely for the following problem:
I have multiple sliders that I want to link to textboxes.
When the textbox is changed the corresponding slider must update to the new value and vice versa.
On changing the slider value or textbox a function needs to be called that uses the input from all textboxes to calculate a result.
I have my quick and dirty jQuery solution here.
Would it be easy to achieve the same result in a more elegant way using knockout js?
I guess I would need to create a custom binding handler like its done in jQuery UI datepicker change event not caught by KnockoutJS
Here is an example: http://jsfiddle.net/jearles/Dt7Ka/
I use a custom binding to integrate the jquery-ui slider and use Knockout to capture the inputs and calculate the net amount.
--
UI
<h2>Slider Demo</h2>
Savings: <input data-bind="value: savings, valueUpdate: 'afterkeydown'" />
<div style="margin: 10px" data-bind="slider: savings, sliderOptions: {min: 0, max: 100, range: 'min', step: 1}"></div>
Spent: <input data-bind="value: spent, valueUpdate: 'afterkeydown'" />
<div style="margin: 10px" data-bind="slider: spent, sliderOptions: {min: 0, max: 100, range: 'min', step: 1}"></div>
Net: <span data-bind="text: net"></span>
View Model
ko.bindingHandlers.slider = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().sliderOptions || {};
$(element).slider(options);
$(element).slider({
"slide": function (event, ui) {
var observable = valueAccessor();
observable(ui.value);
},
"change": function (event, ui) {
var observable = valueAccessor();
observable(ui.value);
}
});
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).slider("destroy");
});
},
update: function (element, valueAccessor) {
var value = ko.unwrap(valueAccessor());
if (isNaN(value)) {
value = 0;
}
$(element).slider("value", value);
}
};
var ViewModel = function() {
var self = this;
self.savings = ko.observable(10);
self.spent = ko.observable(5);
self.net = ko.computed(function() {
return self.savings() - self.spent();
});
}
ko.applyBindings(new ViewModel());
I know it's some days ago but I made a few adjustments to John Earles code:
ko.bindingHandlers.slider = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().sliderOptions || {};
$(element).slider(options);
ko.utils.registerEventHandler(element, "slidechange", function (event, ui) {
var observable = valueAccessor();
observable(ui.value);
});
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).slider("destroy");
});
ko.utils.registerEventHandler(element, "slide", function (event, ui) {
var observable = valueAccessor();
observable(ui.value);
});
},
update: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
if (isNaN(value)) value = 0;
$(element).slider("option", allBindingsAccessor().sliderOptions);
$(element).slider("value", value);
}
};
The reason for this is that if you use options that change (fx another observable) then it won't affect the slider even if you wanted it to do so.
#John Earles and #Michael Kire Hansen: thanks for your wonderful solutions!
I used the advanced code from Michael Kire Hansen. I tied the "max:" option of the slider to a ko.observable and it turned out that the slider does not correctly update the value in this case. Example: Lets say the slider is at value 25 of max 25 und you change the max value to 100, the slider stays at the most right position, indicating that it is at the max value (but value is still 25, not 100). As soon as you slide one point to the left, you get the value updated to 99.
Solution:
in the "update:" part just switch the last two lines to:
$(element).slider("option", allBindingsAccessor().sliderOptions);
$(element).slider("value", value);
This changes the options first, then the value and it works like a charm.
Thanks so much for the help, I needed to use a range slider in my scenario so here is an extension to #John Earles and #Michael Kire Hansen
ko.bindingHandlers.sliderRange = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().sliderOptions || {};
$(element).slider(options);
ko.utils.registerEventHandler(element, "slidechange", function (event, ui) {
var observable = valueAccessor();
observable.Min(ui.values[0]);
observable.Max(ui.values[1]);
});
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).slider("destroy");
});
ko.utils.registerEventHandler(element, "slide", function (event, ui) {
var observable = valueAccessor();
observable.Min(ui.values[0]);
observable.Max(ui.values[1]);
});
},
update: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
if (isNaN(value.Min())) value.Min(0);
if (isNaN(value.Max())) value.Max(0);
$(element).slider("option", allBindingsAccessor().sliderOptions);
$(element).slider("values", 0, value.Min());
$(element).slider("values", 1, value.Max());
}
};
and then the HTML to accompany it
<div id="slider-range"
data-bind="sliderRange: { Min: 0, Max: 100 },
sliderOptions: {
range: true,
min: 0,
max: 100,
step: 10,
values: [0, 100]
}"></div>
Using the jQuery UI Slider, I'm trying to figure out how to make it so that the slider stops working once certain conditions are met. Any ideas? I thought stopping event propogation in the "start" part would work, but ...it doesn't. So I'm still clueless and lost.
<script type="text/javascript">
$(document).ready(function () {
var spendable = 1000;
var spent = 0;
function spend(quantity) {
var remaining = spendable - quantity;
$('#spendable').text(remaining);
}
$("#eq .slider").each(function () {
var current = 0;
$(this).slider({
range: "min",
step: 100,
value: 0,
min: 0,
max: 500,
animate: true,
orientation: "horizontal",
start: function (event, ui) {
if (spent < spendable)
return true;
event.stopPropagation();
},
slide: function (event, ui) {
// set the current value to whatever is selected.
current = ui.value;
$(this).parent('div:eq(0)').find('.spent').text(current);
var totalled = 0;
$("#eq .slider").each(function () {
totalled += parseInt($(this).parent('div:eq(0)').find('.spent').text());
spend(totalled);
});
}
});
});
Try:
.....
slide: function (event, ui) {
// set the current value to whatever is selected.
current = ui.value;
if(current > 300){
current = 300; //otherwise, it's stuck at 301
return false;
}
....rest of your code