I have two range sliders filtering a list of rental properties by rent and number of bedrooms. I'm trying to set cookies on them so the selected values and handle positions are remembered when the user comes back to this page via a "back to rentals" link. But every solution I've tried either does nothing or breaks the existing functionality of the sliders. I'm new to jQuery, can someone please give me a hand?
Thanks for your help. Here's the code for the two sliders:
<form id="formBeds">
<label for="amountBeds"># of Beds:</label>
<input type="text" id="amountBeds" style="border:0; color:#f6931f; font-weight:bold;" />
</form>
<div class="slider" id="beds"></div>
<form id="formPrice">
<label for="amountPrice">Rent:</label>
<input type="text" id="amountPrice" style="border:0; color:#f6931f; font-weight:bold;" />
</form>
<div class="slider" id="price"></div>
<script>
function showProducts(minPrice, maxPrice, minBeds, maxBeds) {
$("#bedrooms li").filter(function() {
var price = parseInt($(this).data("price"), 10);
var beds = parseInt($(this).data("beds"), 10);
if(price >= minPrice && price <= maxPrice && beds >= minBeds && beds <= maxBeds){
$(this).show();
} else {
$(this).hide();
}
});
}
$(function() {
var options = {
range: true,
min: 0,
max: 800,
values: [ 0, 800 ],
change: function(event, ui) {
var minPrice = $("#price").slider("values", 0);
var maxPrice = $("#price").slider("values", 1);
var minBeds = $("#beds").slider("values", 0);
var maxBeds = $("#beds").slider("values", 1);
$("#amountPrice").val("$" + minPrice + " - $" + maxPrice);
$("#amountBeds").val(minBeds + " - " + maxBeds);
showProducts(minPrice, maxPrice, minBeds, maxBeds);
}
};
var bounds = $("#slider").slider(options, "bounds");
$("#price").slider(options, "bounds", {min: 300, max: 800});
$("#beds").slider(options, "bounds", {min: 1, max: 4});
});
</script>
Related
I am trying to get the slider values to stay where they were moved to when the SEARCH button is pressed. They default back to the starting values whenever the search is pressed. I have tried all sorts of things and nothing appears to work. Any help would be appreciated.
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="css/jquery-ui.css">
</head>
<body>
<form method="post" id="formMain">
<label>Price Range</label>
<div>
<div id="slider-range" ></div>
<input type="hidden" name="price_l" id="price_l" value="<?php echo
(isset($_REQUEST["price_l"])?$_REQUEST["price_l"]:"50000")?>"/>
<input type="hidden" name="price_h" id="price_h" value="<?php echo
(isset($_REQUEST["price_h"])?$_REQUEST["price_h"]:"400000")?>"/>
<input type="text" name="text" id="amount" disabled="" />
</div>
<div>
<input type="submit" value="Search">
</div>
</form>
<script src="js/jquery-3.5.1.min.js"></script>
<script src="js/jquery-ui.js"></script>
<script>
var siteSliderRange = function() {
$( "#slider-range" ).slider({
range: true,
min: 5000,
max: 450000,
step: 5000,
values: [ 50000, 400000 ],
slide: function( event, ui ) {
$( "#amount" ).val( "$" + ui.values[ 0 ] + " - $" + ui.values[ 1 ] );
// when the slider values change, update the hidden fields
$("#price_l").val(ui.values[ 0 ]);
$("#price_h").val(ui.values[ 1 ]);
}
});
$( "#amount" ).val( "$" + $( "#slider-range" ).slider( "values", 0 ) +
" - $" + $( "#slider-range" ).slider( "values", 1 ) );
};
siteSliderRange();
</script>
</body>
</html>
Consider the following example that uses localStorage to store the slider values in the browser.
https://jsfiddle.net/Twisty/e28pqhy9/11/
HTML
<fieldset class="ui-widget">
<legend>Price Range</legend>
<div class="content">
<div id="slider-range"></div>
<div id="amount"></div>
<button>Search</button>
</div>
</fieldset>
JavaScript
$(function() {
function getValues(k) {
if (k == undefined) {
return false;
}
var v = localStorage.getItem(k);
if (v != null) {
return JSON.parse(v);
} else {
return -1;
}
}
function setValues(k, v) {
if (k == undefined || v == undefined) {
return false;
}
localStorage.setItem(k, JSON.stringify(v));
}
function showRange(tObj, v) {
tObj.html("$" + v[0] + " - $" + v[1]);
}
function searchRange(q) {
$.post("searchRange.php", {
price_l: q[0],
price_h: q[1]
}, function(response) {
// Do the needful
})
}
function siteSliderRange(tObj) {
tObj.slider({
range: true,
min: 5000,
max: 450000,
step: 5000,
values: [50000, 400000],
slide: function(event, ui) {
showRange($(this).next(), ui.values);
},
stop: function(e, ui) {
setValues($(this).attr("id"), ui.values);
}
});
}
function init() {
var cVal = getValues("slider-range");
if (cVal != -1) {
showRange($("#amount"), cVal);
siteSliderRange($("#slider-range"));
$("#slider-range").slider("values", cVal);
} else {
showRange($("#amount"), [50000, 400000]);
siteSliderRange($("#slider-range"));
setValues("slider-range", [50000, 400000]);
}
$(".content button").click(function() {
searchRange($("#slider-range").slider("values"));
});
}
init();
});
This will check the localStorage upon initialization to see if any values have been stored. If not, 50000 and 400000 are set as defaults. If there is a value, it will be loaded to both the Slider and the display area. Moving away from the Form model will give you added security. Less chance of someone entering their own values by manually enabling the Text field.
When the User moves the Slider, the display is updated. When they stop it then updates the localStorage. This ensure if they refresh the page or navigate back later, the Slider will recall their selection.
When the Search button is clicked, an AJAX Post is performed, this sends the data to PHP and expects some results to be passed back. I assume those results would be appended to the page.
Update
New Example for PHP: https://jsfiddle.net/Twisty/e28pqhy9/20/
If you want to echo the PHP Values, you can do this, you just need to adjust your JS to look for these values.
HTML
<form>
<fieldset class="ui-widget">
<legend>Price Range</legend>
<div class="content">
<div id="slider-range"></div>
<div class="amount-display"></div>
<input type="hidden" id="amount" value="<?php echo $price_l . ',' . $price_h ?>" />
<button type="submit">Search</button>
</div>
</fieldset>
</form>
JavaScript
$(function() {
function getValues() {
return $("#amount").val().split(",");
}
function setValues(v) {
$("#amount").val(v.join(","));
}
function showRange(tObj, v) {
tObj.html("$" + v[0] + " - $" + v[1]);
}
function siteSliderRange(tObj) {
tObj.slider({
range: true,
min: 5000,
max: 450000,
step: 5000,
values: getValues(),
slide: function(event, ui) {
showRange($(this).next(), ui.values);
},
stop: function(e, ui) {
setValues($(this).attr("id"), ui.values);
}
});
}
function init() {
var cVal = getValues();
showRange($(".amount-display"), cVal);
siteSliderRange($("#slider-range"));
}
init();
});
When the form is submitted, the $_POST['amount'] will be a string and you can use this to convert it back:
PHP
$amounts = explode(",", $_POST['amount']);
$price_l = (int)$amounts[0];
$price_h = (int)$amounts[1];
i try to make a multiple dialog form from some data in the database but when i clicked the button, the dialog form not showed
i use PHP increment numeric to differentiate the attribute id
then i use for to sync the id on my php code with the id on jquery code
when i try on jsfiddle, it says "Functions declared between loop referencing an outer scoped variable may lead to confusing semantics"
this is my php code:
<button class="btn btn-danger" id="create-user<?php echo $no2++; ?>">Buka Blokir</button>
<div id="dialog-form<?php echo $no++; ?>" title="Create new user">
<p class="validateTips">All form fields are required.</p>
<form>
<fieldset>
<label for="reason">Reason</label>
<input type="text" name="reason" id="reason" value="Jane Smith" class="text ui-widget-content ui-corner-all">
<input type="submit" tabindex="-1" style="position:absolute; top:-1000px">
</fieldset>
</form>
</div>
and thisis my jquery code:
$( function() {
var dialog, form,
reason = $( "#reason" ),
allFields = $( [] ).add( reason ),
tips = $( ".validateTips" );
function updateTips( t ) {
tips
.text( t )
.addClass( "ui-state-highlight" );
setTimeout(function() {
tips.removeClass( "ui-state-highlight", 1500 );
}, 500 );
}
function checkLength( o, n, min, max ) {
if ( o.val().length > max || o.val().length < min ) {
o.addClass( "ui-state-error" );
updateTips( "Length of " + n + " must be between " +
min + " and " + max + "." );
return false;
} else {
return true;
}
}
function checkRegexp( o, regexp, n ) {
if ( !( regexp.test( o.val() ) ) ) {
o.addClass( "ui-state-error" );
updateTips( n );
return false;
} else {
return true;
}
}
function unBlock() {
var valid = true;
allFields.removeClass( "ui-state-error" );
valid = valid && checkLength( reason, "reason", 6, 80 );
if ( valid ) {
$( "#users tbody" ).append( "<tr>" +
"<td>" + dasar.val() + "</td>" +
"</tr>" );
dialog.dialog( "close" );
}
return valid;
}
for (var i = 1; i < 50; i++) {
dialog = $( "#dialog-form"+i ).dialog({
autoOpen: false,
height: 400,
width: 350,
modal: true,
buttons: {
"Unblock": unBlock,
Cancel: function() {
dialog.dialog( "close" );
}
},
close: function() {
form[ 0 ].reset();
allFields.removeClass( "ui-state-error" );
}
});
}
form = dialog.find( "form" ).on( "submit", function( event ) {
event.preventDefault();
addUser();
});
for (var b = 1; b < 50; b++) {
$( "#create-user"+b ).button().on( "click", function() {
dialog.dialog( "open" );
});
}
} );
I think you're making it overly complicated. Consider the following code.
$(function() {
var reasons = $("[id^='reason']"),
tips = $(".validateTips");
function updateTips(t) {
tips
.text(t)
.addClass("ui-state-highlight");
setTimeout(function() {
tips.removeClass("ui-state-highlight", 1500);
}, 500);
}
function checkLength(o, n, min, max) {
if (o.val().length > max || o.val().length < min) {
o.addClass("ui-state-error");
updateTips("Length of " + n + " must be between " +
min + " and " + max + ".");
return false;
} else {
return true;
}
}
function checkRegexp(o, regexp, n) {
if (!(regexp.test(o.val()))) {
o.addClass("ui-state-error");
updateTips(n);
return false;
} else {
return true;
}
}
$("[id^='dialog-form']").dialog({
autoOpen: false,
height: 400,
width: 350,
modal: true,
buttons: {
"Unblock": function() {
var valid = true;
reasons.removeClass("ui-state-error");;
var reason = $(this).find("[id^='reason']");
valid = valid && checkLength(reason, "reason", 6, 80);
if (valid) {
/*
$("#users tbody").append("<tr>" +
"<td>" + dasar.val() + "</td>" +
"</tr>");
*/
$("[id^='dialog-form']").dialog("close");
}
return valid;
},
Cancel: function() {
$(this).dialog("close");
}
},
close: function() {
$(this).find("form")[0].reset();
reasons.removeClass("ui-state-error");
}
});
$("div[id^='dialog-form'] form").on("submit", function(e) {
e.preventDefault();
/*
addUser();
*/
});
$("button[id^='create-user']").on("click", function(e) {
var selfId = $(this).attr("id");
var d = selfId.match(/\d+/g).map(Number);
var dlg = $("#dialog-form-" + d);
dlg.dialog("open");
});
});
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<button class="btn btn-danger" id="create-user-1">Buka Blokir</button>
<div id="dialog-form-1" title="Create new user">
<p class="validateTips">All form fields are required.</p>
<form>
<fieldset>
<label for="reason-1">Reason</label>
<input type="text" name="reason" id="reason-1" value="Jane Smith" class="text ui-widget-content ui-corner-all">
<input type="submit" tabindex="-1" style="position:absolute; top:-1000px">
</fieldset>
</form>
</div>
<button class="btn btn-danger" id="create-user-20">Buka Blokir</button>
<div id="dialog-form-20" title="Create new user">
<p class="validateTips">All form fields are required.</p>
<form>
<fieldset>
<label for="reason-20">Reason</label>
<input type="text" name="reason" id="reason-2" value="John Smith" class="text ui-widget-content ui-corner-all">
<input type="submit" tabindex="-1" style="position:absolute; top:-1000px">
</fieldset>
</form>
</div>
With a selector that encompasses more than one element, you can still assign UI Widgets to it. You just have to understand how to use this and $(this) to your advantage.
I'm trying to make use of the knockout slider binderhalders that RP Niemeyer has posted a few times. Unfortunately while trying to use it I receive the error within the title.
(function($){
ko.bindingHandlers.slider = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().sliderOptions || {};
var sliderValues = ko.utils.unwrapObservable(valueAccessor());
if(sliderValues.min !== undefined) {
options.range = true;
}
options.slide = function(e, ui) {
if(sliderValues.min) {
// Errors here
sliderValues.min(ui.values[0]);
sliderValues.max(ui.values[1]);
} else {
sliderValues.value(ui.value);
}
};
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).slider("destroy");
});
$(element).slider(options);
},
update: function (element, valueAccessor) {
var sliderValues = ko.toJS(valueAccessor());
if(sliderValues.min !== undefined) {
$(element).slider("values", [sliderValues.min, sliderValues.max]);
} else {
$(element).slider("value", sliderValues.value);
}
}
};
this.range = {
'cook': function(kitchen, name, label, recipe){
var food = new this.viewModel(kitchen);
food.name = name;
food.label = label;
food.total(recipe.numberOfResults);
food.criteriaMin = recipe.minValue;
food.criteriaMax = recipe.maxValue;
return food;
},
'viewModel': function(kitchen){
var self = this;
this.name = '';
this.label = '';
this.total = window.ko.observable();
this.criteriaMin = ko.observable(0);
this.criteriaMax = ko.observable(100);
this.loading = window.ko.observable(false);
this.template = '';
this.getSelection = function(){
return null;
};
this.setSelection = function(){
};
},
'template': '<th class="idc-td-criteria" scope="row" data-bind="text:label"></th>' +
'<td class="idc-td-value idc-td-slider">' +
' <label for="AmountMin" class="hiddenText">Amount Min</label>' +
' <input type="text" data-default="0" data-maxdecimal="2" class="idc-textinput idc-sliderinput" maxlength="6" data-bind="value: criteriaMin || \'0.00\'">' +
' <span class="slider" data-bind="slider: { min: criteriaMin, max: criteriaMax }, sliderOptions: {min: 0, max: 100, step: 1}"></span>' +
' <label for="AmountMax" class="hiddenText">Amount Max</label>' +
' <input type="text" data-default="10" data-maxdecimal="2" class="idc-textinput idc-sliderinput" maxlength="6" data-bind="value: criteriaMax || \'10.00\'">' +
'</td>' +
'<td class="idc-td-results" data-bind="text:total"></td>' +
'<td class="idc-td-remove">' +
' <a href="#">' +
' <img src="images/column_delete.png" alt="Delete criteria [criteria name]" role="button" />' +
' </a>' +
'</td>'
};
}).call(window.idmsScreener.chefs, jQuery);
I've tried to change it from sliderValues.min() to sliderValues.min = ui.values[0]; However by changing that I can't seem to get the values back correctly. I also tried changing the min and max values of the slider options so that they are not statically set but that throws a completely different error. Any help on solving this would be greatly appreciated.
Was able to resolve this. Determined that I was setting my min and max criteria in correctly. I was doing assignment using an equals sign which was overriding the observable.
I use jQuery-Mobile-DateBox for date and time picker in jQueryMobile.
<input id="start" type="date" data-role="datebox" data-options='{"mode": "calbox", "afterToday": true, "useFocus": true, "overrideDateFormat": "%m/%d/%Y"}'>
<input id="end" type="date" data-role="datebox" data-options='{"mode": "calbox", "afterToday": true, "useFocus": true, "overrideDateFormat": "%m/%d/%Y"}'>
I need not to allow user to select end day that are before start day.
$("#end").datebox("minDays", $("#start").val());
The above code doesn't work.
If you want to prevent end day from been lower then a start day
Working example: http://jsfiddle.net/Gajotres/QTuma/
HTML :
<label for="start-date">Start Date</label>
<input name="start-date" id="start-date" type="date" data-role="datebox" data-options='{"mode": "calbox", "useNewStyle":true,"overrideDateFormat":"%-m/%-d/%Y"}'/>
<label for="end-date">End Date</label>
<input name="end-date" id="end-date" type="date" data-role="datebox" data-options='{"mode": "calbox", "useNewStyle":true,"overrideDateFormat":"%m/%-d/%Y"}'/>
Javascript
$('#end-date').bind('datebox', function(e, p) {
if ( p.method === 'set' && $('#start-date').val().length > 0) {
e.stopImmediatePropagation();
var startDate = new Date($('#start-date').val());
var endDate = new Date($('#end-date').val());
if (startDate > endDate)
{
$('#end-date').val('');
}
}
});
Here is how to disabled date as per selection of start or end dates:
If a date is selected in start datebox, then end date will be limited to selection of days after start date (inclusive of start date) and vise-verse for end date too.
$(document).on('pageinit', '#index', function(){
$('#end-date').bind('datebox', function(e, p) {
if ( p.method === 'open') {
// Make it a date
var startDate = new Date($('#start-date').val());
var todaysDate = new Date();
// Length of 1 Day
var lengthOfDay = 24 * 60 * 60 * 1000;
// Get the difference
var diff = parseInt((((startDate.getTime() - todaysDate.getTime()) / lengthOfDay)+1)*-1,10);
// Set minDays to disallow anything earlier
$('#end-date').datebox({'minDays': diff});
}
});
$('#start-date').bind('datebox', function(e, p) {
if ( p.method === 'open') {
// Make it a date
var endDate = new Date($('#end-date').val());
var todaysDate = new Date();
// Length of 1 Day
var lengthOfDay = 1000 * 60 * 60 * 24;
// Get the difference
var diff = parseInt((((endDate.getTime() - todaysDate.getTime()) / lengthOfDay)+1),10);
// Set minDays to disallow anything earlier
$('#start-date').datebox({'maxDays': diff});
}
});
});
check the updated fiddle link: http://jsfiddle.net/QTuma/6/
OR as per below solution a simpler method to set min and max:
$(document).on('pageinit', '#index', function(){
$('#start-date').bind('datebox', function(e, p) {
if ( p.method === 'set') {
var endDate = $('#start-date').val().replace(/(\d{1,2})\/(\d{1,2})\/(\d{4})$/,'$3-$1-$2');
$('#end-date').attr({'min':endDate,'max':'2999-01-01'});
$('#end-date').datebox('applyMinMax');
}
});
$('#end-date').bind('datebox', function(e, p) {
if ( p.method === 'set') {
var endDate = $('#end-date').val().replace(/(\d{1,2})\/(\d{1,2})\/(\d{4})$/,'$3-$1-$2');
$('#start-date').attr({'min':'1000-01-01','max':endDate});
$('#start-date').datebox('applyMinMax');
}
});
});
I have designed a jQuery Slider Control that takes a 'pool' of points, and allows them to be distributed between multiple sliders. It works pretty well, except that I am having some problems with very small overflow increments.
Basically, it is possible to make adjustments in large quantities based on mouse movement, and so it lets someone 'spend' more in a slider than intended. I am at a loss as to how to deal with this. Posted below is my entire code.
To test it, build a simple HTML page with this code and try sliding the first two sliders all the way to 500, then try sliding the third. It won't slide (intended behavior).
Then, slide the first or second slider back a little bit (subtracting), and slide the third forward. You are able to occasionally go over the intended 'spendable' bounds.
Sample will require jQuery UI, latest version from google CDN.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.js"></script>
Javascript
<style type="text/css">
#eq > div {
width:300px;
}
#eq > div .slider {
width: 200px; float: left;
}
#eq > div > span {
float: right;
}
</style>
<script type="text/javascript">
$(document).ready(function () {
var spendable = 1000;
var spent = 0;
function spend(quantity) {
spent += quantity;
$('#attemptedToSpend').text(spent);
}
function change(previous, current) {
var adjustment = (current - previous);
$('#change').text(adjustment);
return adjustment;
}
function calculateSpent() {
var totalled = 0;
$("#eq .slider").each(function () {
totalled += parseInt($(this).parent('div:eq(0)').find('.spent').text());
});
$('#spent').text(totalled);
}
$("#eq .slider").each(function () {
var current = 0;
var previous = 0;
var adjustment = 0;
$(this).slider({
range: "min",
value: 0,
min: 0,
max: 500,
step: 1,
animate: true,
orientation: "horizontal",
start: function (event, ui) {
},
stop: function (event, ui) {
},
slide: function (event, ui) {
// set the current value to whatever is selected.
current = ui.value;
// determine the adjustment being made relative to the last
// adjustment, instead of just the slider's value.
adjustment = change(previous, current);
if (spent >= spendable) {
if (adjustment > 0)
return false;
}
// spend the points, if we are able to.
spend(adjustment);
// set the previous value
previous = current;
$(this).parent('div:eq(0)').find('.spent').text(current);
calculateSpent();
}
});
});
});
</script>
Html
<p class="ui-state-default ui-corner-all" style="padding: 4px; margin-top: 4em;">
<span style="float: left; margin: -2px 5px 0 0;"></span>Distribution
</p>
<strong>Total Points Spendable: </strong><div id="spendable">1000</div>
<strong>Total Points Spent (Attempted): </strong><div id="attemptedToSpend">0</div>
<strong>Total Points Spent: </strong><div id="spent">0</div>
<strong>Change: </strong><div id="change">0</div>
<div id="status"></div>
<div id="eq">
<div style="margin: 15px;" id="test1">Test1</div>
<br />
<div class="slider"></div><span class="spent">0</span>
<div style="margin: 15px;" id="test2">Test2</div>
<br />
<div class="slider"></div><span class="spent">0</span>
<div style="margin: 15px;" id="test3">Test3</div>
<br />
<div class="slider"></div><span class="spent">0</span>
<div style="margin: 15px;" id="test4">Test4</div>
<br />
<div class="slider"></div><span class="spent">0</span>
<div style="margin: 15px;" id="test5">Test5</div>
<br />
<div class="slider"></div><span class="spent">0</span>
</div>
I tried keeping your script intact, but ended up largely rewriting it. It should be solid now. Good news: I have only changed the JS, everything else is intact, though I don't update all your monitoring fields any more.
DEMO
$(
function()
{
var
maxValueSlider = 500,
maxValueTotal = 1000,
$sliders = $("#eq .slider"),
valueSliders = [],
$displaySpentTotal = $('#spent');
function arraySum(arr)
{
var sum = 0, i;
for(i in arr) sum += arr[i];
return sum;
}
$sliders
.each(
function(i, slider)
{
var
$slider = $(slider),
$spent = $slider.next('.spent');
valueSliders[i] = 0;
$slider
.slider(
{
range: 'min',
value: 0,
min: 0,
max: maxValueSlider,
step: 1,
animate: true,
orientation: "horizontal",
slide:
function(event, ui)
{
var
sumRemainder = arraySum(valueSliders) - valueSliders[i],
adjustedValue = Math.min(maxValueTotal - sumRemainder, ui.value);
valueSliders[i] = adjustedValue;
// display the current total
$displaySpentTotal.text(sumRemainder + adjustedValue);
// display the current value
$spent.text(adjustedValue);
// set slider to adjusted value
$slider.slider('value', adjustedValue);
// stop sliding (return false) if value actually required adjustment
return adjustedValue == ui.value;
}
}
);
}
);
}
);