Make a custom range slider using jQuery - javascript

I have created a custom slider. I want to make the position of the marker change as I drag the slider handle. However the gap between the marker and the handle is getting wider as the value gets bigger.
I think the problem is to do with using margin-left/left or absolute/relative positioning.
Can anyone help me to figure out if the concept of the position of mine is wrong?
$(function() {
$('.h-rs-line').on('input', function() {
var val = $(this).val();
var min = $(this).attr('min');
var max = $(this).attr('max');
var portion = (val - min) / (max - min);
$('.h-rs-indicator').text(val);
$('.h-rs-indicator').css('left', portion * $('.h-rs-line').width());
});
});
body {
background: #000;
}
.h-rs {
position: relative;
}
.h-rs-index {
color: #FFF;
}
.h-rs-container {
display: flex;
flex-direction: column;
margin: 32px;
}
.h-rs-indicator {
display: block;
width: 50px;
height: 35px;
border-radius: 12px;
text-align: center;
line-height: 35px;
background: #FFF;
position: absolute;
top: -30px;
left: 0;
margin-left: -16px;
}
.h-rs-indicator::after {
content: '';
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 9px solid #FFF;
position: absolute;
top: 98%;
left: 50%;
margin-left: -8px;
}
.h-rs-line {
width: 300px;
margin-top: 24px;
-webkit-appearance: none;
border-radius: 24px;
}
.h-rs-line::-webkit-slider-runnable-track {
-webkit-appearance: none;
height: 7px;
border-radius: 24px;
}
.h-rs-line::-webkit-slider-thumb {
-webkit-appearance: none;
background: #FFF;
height: 18px;
width: 18px;
border-radius: 100%;
box-shadow: 0px 10px 10px rgba(0, 0, 0, 0.25);
margin-top: -5.5px;
}
.h-rs-index {
display: flex;
margin-top: 9px;
width: 300px;
justify-content: space-between;
}
.h-rs-index span:first-child {
margin-left: 6.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="h-rs-container">
<div class="h-rs">
<span class="h-rs-indicator">0<span></span></span>
<input class="h-rs-line" type="range" value="0" min="0" max="100" />
</div>
<div class="h-rs-index">
<span>0</span><span>100</span>
</div>
</div>

Compensate for the thumb width
You forgot to compenstate for the size of the range slider thumb. The slider thumb can only travel the width of the slider minus the size of the thumb (so 300px minus ~18px). Because the thumb can only travel 282px, so should the label, or they will be out of sync.
Therefore this:
$('.h-rs-indicator').css('left', portion * $('.h-rs-line').width());
... should become this:
$('.h-rs-indicator').css('left', portion * ($('.h-rs-line').width() - 18));
... where 18 is the width of the range slider thumb in pixels.
$(function() {
$('.h-rs-line').on('input', function() {
var val = $(this).val();
var min = $(this).attr('min');
var max = $(this).attr('max');
var portion = (val - min) / (max - min);
$('.h-rs-indicator').text(val);
$('.h-rs-indicator').css('left', portion * ($('.h-rs-line').width() - 18));
});
});
body {
background: #000;
}
.h-rs {
position: relative;
}
.h-rs-index {
color: #FFF;
}
.h-rs-container {
display: flex;
flex-direction: column;
margin: 32px;
}
.h-rs-indicator {
display: block;
width: 50px;
height: 35px;
border-radius: 12px;
text-align: center;
line-height: 35px;
background: #FFF;
position: absolute;
top: -30px;
left: 0;
margin-left: -16px;
}
.h-rs-indicator::after {
content: '';
width: 0;
height: 0;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 9px solid #FFF;
position: absolute;
top: 98%;
left: 50%;
margin-left: -8px;
}
.h-rs-line {
width: 300px;
margin-top: 24px;
-webkit-appearance: none;
border-radius: 24px;
}
.h-rs-line::-webkit-slider-runnable-track {
-webkit-appearance: none;
height: 7px;
border-radius: 24px;
}
.h-rs-line::-webkit-slider-thumb {
-webkit-appearance: none;
background: #FFF;
height: 18px;
width: 18px;
border-radius: 100%;
box-shadow: 0px 10px 10px rgba(0, 0, 0, 0.25);
margin-top: -5.5px;
}
.h-rs-index {
display: flex;
margin-top: 9px;
width: 300px;
justify-content: space-between;
}
.h-rs-index span:first-child {
margin-left: 6.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="h-rs-container">
<div class="h-rs">
<span class="h-rs-indicator">0<span></span></span>
<input class="h-rs-line" type="range" value="0" min="0" max="100" />
</div>
<div class="h-rs-index">
<span>0</span><span>100</span>
</div>
</div>
Cross-browser
Getting your range slider to look the same (and being the same size) in every browser involves a lot of CSS. This is explained very well in this article on CSS tricks: https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/
Non-jQuery
How about a rewrite from jQuery to non-jQuery? That could be much lighter... Something like this:
<input type="range" min="0" max="100" oninput="updateRangeSlider(this)" onchange="updateRangeSlider(this)" />
With this function in the footer:
function updateRangeSlider(el){
var val = el.value;
var min = el.getAttribute('min');
var max = el.getAttribute('max');
var portion = (val - min) / (max - min);
var iel = el.parentNode.querySelector('.h-rs-indicator');
iel.innerHTML = val + '<span></span>';
iel.style.left = (portion * (el.offsetWidth-18)) + 'px';
}
Note that this function is reusable.

Related

Limit Max and Min on a two thumb slider

I have a two thumb range slider to set the max value and the min value, now I realized that it's possible to go over the thumbs - max can go over min and min over max.
I want to limit min to not go over max and max not over min
After some researched I've not seen any usefull JS.
Is there any option I can use for this one.
const twoRangeSlider = (() => {
const rangeCheck = (rangeInputs, rangeMinOutput, rangeMaxOutput) => {
const rangeMin = rangeInputs[0].min ? rangeInputs[0].min : 0;
const rangeMax = rangeInputs[0].max ? rangeInputs[0].max : 100;
let rangeMinValue = parseFloat(rangeInputs[1].value);
let rangeMaxValue = parseFloat(rangeInputs[0].value);
rangeMinValue = Math.min(Math.max(rangeMinValue, rangeMin), rangeMaxValue);
const rangeMinPercentage = Number(
((rangeMinValue - rangeMin) * 100) / (rangeMax - rangeMin));
const rangeMaxPercentage = Number(
((rangeMaxValue - rangeMin) * 100) / (rangeMax - rangeMin));
rangeInputs[0].style.background = `linear-gradient(to right, #000 ${rangeMaxPercentage}%, #c4c8ca ${rangeMaxPercentage}%)`;
rangeInputs[1].style.background = `linear-gradient(to right,#c4c8ca ${rangeMinPercentage}%, transparent ${rangeMinPercentage}%)`;
};
const bindComponent = (item) => {
const rangeInputs = item.querySelectorAll('.js-two-range-slider-input');
const rangeMinOutput = item.querySelector('.js-two-range-slider-min-value');
const rangeMaxOutput = item.querySelector('.js-two-range-slider-max-value');
item.addEventListener("input", () => {
rangeCheck(rangeInputs, rangeMinOutput, rangeMaxOutput);
});
rangeCheck(rangeInputs, rangeMinOutput, rangeMaxOutput);
};
const init = () => {
const rootEl = document.getElementsByClassName("js-two-range-slider");
[...rootEl].forEach((item) => bindComponent(item));
};
return {
init
};
})();
twoRangeSlider.init();
.two-range-slider {
position: relative;
height: 4px;
width: 164px;
margin-bottom: 50px;
}
.two-range-slider__input {
position: absolute;
left: 40%;
top: 15px;
box-shadow: 0;
appearance: none;
width: 60%;
height: 3px;
border-radius: 50px;
background-color: #000;
outline: 0;
}
.two-range-slider__value {
padding: 0px 10px;
color: #000;
position: relative;
top: 19px;
outline: none;
width: 50px;
position: absolute;
border: 1px solid #ccc;
box-sizing: border-box;
}
.two-range-slider__input::-webkit-slider-thumb {
z-index: 2;
position: relative;
-webkit-appearance: none;
appearance: none;
height: 13px;
width: 13px;
border-radius: 50%;
background: #000;
cursor: pointer;
}
.two-range-slider__input::-moz-range-thumb {
z-index: 2;
position: relative;
appearance: none;
width: 25px;
height: 25px;
border-radius: 50%;
border: 0;
background: #FFFFFF;
cursor: pointer;
}
.two-range-slider__output {
display: inline-flex;
flex-flow: row nowrap;
justify-content: space-between;
width: 140%;
top: -15px;
margin-left: 0px;
color: #000;
position: relative;
}
.range-slider__value {
padding: 0px 10px;
color: #000;
outline: none;
width: 50px;
}
<div class="two-range-slider js-two-range-slider">
<input type="range" value="80" min="10" max="100" step="1" class="two-range-slider__input js-two-range-slider-input">
<input type="range" value="30" min="10" max="100" step="1" class="two-range-slider__input js-two-range-slider-input">
<div class="two-range-slider__output">
<p class="minmax">Min</p><input class="two-range-slider__value js-two-range-slider-min-value" type="number" value="30" min="10" max="100" step="1"></input>
<p class="maxmin">Max</p><input style="right: -5px;" class="two-range-slider__value js-two-range-slider-max-value" type="number" value="80" min="10" max="100" step="1"></input>
</div>
</div>
I shortened your example a bit to show what i meant in my comment.
const twoRangeSlider = (() => {
const bindComponent = (item) => {
const rangeInputs = item.querySelectorAll('.js-two-range-slider-input');
item.addEventListener("input", ({ target }) => {
const [ right, left ] = rangeInputs;
if (target == right) {
left.value = Math.min(+right.value -1, +left.value);
} else {
right.value = Math.max(+left.value +1, +right.value);
}
});
};
const init = () => {
const rootEl = document.getElementsByClassName("js-two-range-slider");
[...rootEl].forEach((item) => bindComponent(item));
};
return {
init
};
})();
twoRangeSlider.init();
.two-range-slider {
position: relative;
height: 4px;
width: 164px;
margin-bottom: 50px;
}
.two-range-slider__input {
position: absolute;
left: 40%;
top: 15px;
box-shadow: 0;
appearance: none;
width: 60%;
height: 3px;
border-radius: 50px;
background-color: #000;
outline: 0;
}
.two-range-slider__value {
padding: 0px 10px;
color: #000;
position: relative;
top: 19px;
outline: none;
width: 50px;
position: absolute;
border: 1px solid #ccc;
box-sizing: border-box;
}
.two-range-slider__input::-webkit-slider-thumb {
z-index: 2;
position: relative;
-webkit-appearance: none;
appearance: none;
height: 13px;
width: 13px;
border-radius: 50%;
background: #000;
cursor: pointer;
}
.two-range-slider__input::-moz-range-thumb {
z-index: 2;
position: relative;
appearance: none;
width: 25px;
height: 25px;
border-radius: 50%;
border: 0;
background: #FFFFFF;
cursor: pointer;
}
.two-range-slider__output {
display: inline-flex;
flex-flow: row nowrap;
justify-content: space-between;
width: 140%;
top: -15px;
margin-left: 0px;
color: #000;
position: relative;
}
.range-slider__value {
padding: 0px 10px;
color: #000;
outline: none;
width: 50px;
}
<div class="two-range-slider js-two-range-slider">
<input type="range" value="80" min="10" max="100" step="1" class="two-range-slider__input js-two-range-slider-input">
<input type="range" value="30" min="10" max="100" step="1" class="two-range-slider__input js-two-range-slider-input">
<div class="two-range-slider__output">
<p class="minmax">Min</p><input class="two-range-slider__value js-two-range-slider-min-value" type="number" value="30" min="10" max="100" step="1">
<p class="maxmin">Max</p><input style="right: -5px;" class="two-range-slider__value js-two-range-slider-max-value" type="number" value="80" min="10" max="100" step="1">
</div>
</div>

Reverse() is not working and so does unshift() in vanilla javascript

The issue is only there when I'm trying to reverse the user input, reverse() is returning the string as it is and so does the unshift().
what I'm looking for is if the user enters input - 1234 the output should be 4,3,2,1, but I'm getting is output - 1,2,3,4.
const pahere = [];
const revephare = [];
let donereve = [];
let dff = document.getElementById("Udt1");
function tex(){
if(dff. value == "") {
console.log("enter text")
}
else {
pahere.push(dff.value);
console.log(dff.value);
console.log(pahere);
console.log(pahere.length);
for(let i = 0; i < pahere.length; i++){
revephare.push(pahere[i].split(""));
pahere.pop();
}
}
console.log("I should be splited",revephare);
donereve = revephare.reverse();
console.log("I should be reversed",donereve);
}
* {
box-sizing: border-box;
}
body{
background: #333;
margin: 0;
}
h1{
margin: 15px;
color: white;
}
.holder{
margin-left: 12px;
width: 34em;
height: 37em;
border: 2px solid rgba(255, 51, 153,1);
display: flex;
}
#Udt1 {
width: 56%;
height: 2em!important;
text-align: center;
}
span {
color: white;
margin-top: 5px;
}
.anshold {
width: 154px;
height: 34px;
margin-left: 43em;
position: relative;
top: -592px !important;
border: 2px solid rgba(255, 51, 153,1);
text-align: center;
}
#udans{
color: white;
text-align: center;
margin: 0;
padding: 4px;
}
.btn {
width: 16%;
height: 2em!important;
text-align: center;
margin-left: 14px;
}
<body>
<h1>Palidrom Checker</h1>
<div class="holder">
<span>Word goes here-</span>
<input type="text" name="textin" label ="textin" id="Udt1" placeholder="Eg-Racecar">
<button class="btn" onclick="tex()"> Check</button>
</div>
<div class="anshold"><p id="udans"> </p>
</div>
</body>
Your trying to spliting Array pahere[i].split("")
const pahere = [];
const revephare = [];
let donereve = [];
let dff = document.getElementById("Udt1");
function tex(){
if(dff. value == "") {
console.log("enter text")
}
else {
pahere.push(dff.value);
console.log(dff.value);
console.log(pahere);
console.log(pahere.length);
for(let i = 0; i <dff.value.length; i++){
revephare.push(dff.value[i]);
pahere.pop();
}
}
console.log("I should be splited",revephare);
donereve = revephare.reverse();
console.log("I should be reversed",donereve);
}
* {
box-sizing: border-box;
}
body{
background: #333;
margin: 0;
}
h1{
margin: 15px;
color: white;
}
.holder{
margin-left: 12px;
width: 34em;
height: 37em;
border: 2px solid rgba(255, 51, 153,1);
display: flex;
}
#Udt1 {
width: 56%;
height: 2em!important;
text-align: center;
}
span {
color: white;
margin-top: 5px;
}
.anshold {
width: 154px;
height: 34px;
margin-left: 43em;
position: relative;
top: -592px !important;
border: 2px solid rgba(255, 51, 153,1);
text-align: center;
}
#udans{
color: white;
text-align: center;
margin: 0;
padding: 4px;
}
.btn {
width: 16%;
height: 2em!important;
text-align: center;
margin-left: 14px;
}
<body>
<h1>Palidrom Checker</h1>
<div class="holder">
<span>Word goes here-</span>
<input type="text" name="textin" label ="textin" id="Udt1" placeholder="Eg-Racecar">
<button class="btn" onclick="tex()"> Check</button>
</div>
<div class="anshold"><p id="udans"> </p>
</div>
</body>
This is because you're using Array.prototype.push incorrectly which gives you an array of arrays as a result
revephare.push(pahere[i].split("")); // this line is incorrect
Replace it by the following to make it work
// use spread operator to pass each element as a separate argument
revephare.push(...pahere[i].split(""));
Hi i know you fixed the issue, you can achieve your output by this single line code, just try if you can
let reversed=(pahere.toString()).split("").map(Number).reverse();

Input Range with opaque range button isn't working in Chrome but in Firefox

I have a input range that is style like a ruler and the range button that is styled as a opaque circle. It's working fine in Firefox and Safari but not in chrome.
I appreciate any suggestions how to make the code work in all browsers.
Here is the code:
obj_sukanya = {
slidePointPos: function(scope, fval, maxVal, scopeWidth) {
console.log('scope', scope)
var figure = fval,
max = maxVal;
var h = figure / max * (scopeWidth - scope.next().width()) + 'px';
scope.next().css({
left: h
}).removeClass('hidden');
scope.next().find('.dynamicVal').html(fval).attr('data-slideval', fval);
scope.parents('.active').find('.inputbox .amount input').val(fval);
},
bind: function(){
$(document).on('mousedown', '.pl-amount', function() {
$('.pl-amount').bind('change mousemove mouseup', function(){
obj_sukanya.slidePointPos($(this), $(this).val(), 10000000, 696);
});
});
}
}
$(document).ready(function(){
obj_sukanya.bind();
})
.rangelabel {
position: relative;
display: inline-block;
background: transparent url(https://img.etimg.com/photo/56312378.cms) no-repeat;
width: 830px;
margin-bottom: 18px;
}
input[type=range].pl-amount {
width: 696px;
height: 120px;
padding: 0;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.rangeval{
position: absolute;
width: 110px;
font-size: 17px;
font-weight: 700;
top: 50%;
text-align: center;
margin-top: -15px;
margin-left: -52px;
z-index: 9;
background-color: #fff;
margin-left: 73px;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<label class="rangelabel" for="homeLoan1">
<input max="10000000" min="0" name="points" type="range" class="pl-amount" value="50000" step="50000" id="homeLoan1">
<span style="left: 123.06px;" class="rangeval"><span data-slideval="2100000" class="dynamicVal">2100000</span></span>
</label>
Since your code didn't work for me in any browser, i changed it a bit to reproduce the design from your image. I:
changed the scopeWidth in the script a bit and resized the input, both for perfectly fitting to the image and made the input completely opaque
gave the outer span the same height like its width and 50% border-radius plus boxshadow and made it partially opaque
gave the outer span a display: inline-flex (plus the centering) for aligning the inner span
defined for the outer span pointer-events: none for moving the input without the span as obstacle
With these changes it worked for me in any browser (inkl. firefox)...
Working example:
obj_sukanya = {
slidePointPos: function(scope, fval, maxVal, scopeWidth) {
var figure = fval,
max = maxVal;
var h = figure / max * (scopeWidth - scope.next().width()) + 'px';
scope.next().css({
left: h
}).removeClass('hidden');
scope.next().find('.dynamicVal').html(fval).attr('data-slideval', fval);
scope.parents('.active').find('.inputbox .amount input').val(fval);
},
bind: function() {
$(document).on('mousedown', '.pl-amount', function() {
$('.pl-amount').bind('change mousemove mouseup', function() {
obj_sukanya.slidePointPos($(this), $(this).val(), 10000000, 672);
});
});
}
}
$(document).ready(function() {
obj_sukanya.bind();
})
.rangelabel {
position: relative;
display: inline-block;
width: 830px;
margin-bottom: 18px;
background: transparent url(https://img.etimg.com/photo/56312378.cms) no-repeat;
}
input[type=range].pl-amount {
position: relative;
top: 0;
left: 120px;
width: 580px;
height: 120px;
padding: 0;
opacity: 0;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.rangeval {
position: absolute;
top: 20%;
z-index: 9;
display: inline-flex;
justify-content: center;
align-items: center;
width: 110px;
height: 110px;
margin-top: -15px;
margin-left: 78px;
border-radius: 50%;
box-shadow: 0 0 6px 1px #ccc;
text-align: center;
font-size: 17px;
font-weight: 700;
background-color: #fff;
opacity: 0.7;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<label class="rangelabel" for="homeLoan1">
<input id="homeLoan1" class="pl-amount" name="points" type="range" max="10000000" min="0" step="50000" value="50000">
<span class="rangeval" style="left: 123.06px;">
<span class="dynamicVal" data-slideval="2100000">2100000</span>
</span>
</label>

Multiple range sliders

I have multiple html5 range sliders on my page, this was working for one however I can't make this work for seperate sliders. They should have no relation, so the user can select a score on each different question.
I know the jQuery code should target the slider, however I cannot get this to work. We are going to be using around 20 of these sliders, so need this to be dynamic really.
var sheet = document.createElement('style'),
$rangeInput = $('.range input'),
prefs = ['webkit-slider-runnable-track', 'moz-range-track', 'ms-track'];
document.body.appendChild(sheet);
var getTrackStyle = function(el) {
var curVal = el.value,
val = (curVal - 1) * 25,
style = '';
// Set active label
$('.range-labels li').removeClass('active selected');
var curLabel = $('.range-labels').find('li:nth-child(' + curVal + ')');
curLabel.addClass('active selected');
curLabel.prevAll().addClass('selected');
//curLabel.addClass('halfselect');
// Change background gradient
for (var i = 0; i < prefs.length; i++) {
style += '.range {background: linear-gradient(to right, #a50e2d 0%, #a50e2d ' + val + '%, #fff ' + val + '%, #fff 100%)}';
style += '.range input::-' + prefs[i] + '{background: linear-gradient(to right, #a50e2d 0%, #a50e2d ' + val + '%, #b2b2b2 ' + val + '%, #b2b2b2 100%)}';
}
return style;
}
$rangeInput.on('input', function() {
sheet.textContent = getTrackStyle(this);
});
// Change input value on label click
$('.range-labels li').on('click', function() {
var index = $(this).index();
$rangeInput.val(index + 1).trigger('input');
});
body {
padding: 100px;
}
.range {
position: relative;
width: 100%;
height: 5px;
}
.range input {
width: 100%;
position: absolute;
top: 2px;
height: 0;
-webkit-appearance: none;
}
.range input::-webkit-slider-thumb {
-webkit-appearance: none;
width: 30px;
height: 30px;
margin: -16px 0 0 0;
border-radius: 50%;
background: #a50e2d;
cursor: pointer;
border: 0 !important;
}
/*
.range input::-moz-range-thumb {
width: 30px;
height: 30px;
margin: -8px 0 0;
border-radius: 50%;
background: #a50e2d;
cursor: pointer;
border: 0 !important;
}
.range input::-ms-thumb {
width: 30px;
height: 30px;
margin: -8px 0 0;
border-radius: 50%;
background: #a50e2d;
cursor: pointer;
border: 0 !important;
}
*/
.range input::-webkit-slider-runnable-track {
width: 100%;
height: 2px;
cursor: pointer;
background: #272725;
}
.range input::-moz-range-track {
width: 100%;
height: 2px;
cursor: pointer;
background: #272725;
}
.range input::-ms-track {
width: 100%;
height: 2px;
cursor: pointer;
background: #272725;
}
.range input:focus {
background: none;
outline: none;
}
.range input::-ms-track {
width: 100%;
cursor: pointer;
background: transparent;
border-color: transparent;
color: transparent;
}
.range-labels {
margin: 18px -11% 0;
padding: 0;
list-style: none;
display: flex;
position: relative;
}
.range-labels li {
position: relative;
text-align: center;
color: #272725;
font-size: 14px;
cursor: pointer;
flex: 1;
}
.range-labels li::before,
.halfselect::before {
position: absolute;
top: -37px;
right: 0;
left: 0;
content: "";
margin: 0 auto;
width: 30px;
height: 30px;
background: #272725;
border-radius: 50%;
}
.range-labels .active {
color: #a50e2d;
}
.range-labels .selected::before,
.range-labels .active::before {
background: #a50e2d;
}
.range-labels .active.selected::before {
display: none;
}
.halfselect {}
.halfselect:after {
position: absolute;
top: -23px;
right: auto;
left: 0;
content: "";
margin: 0 auto;
width: 50%;
height: 5px;
background: #a50e2d;
z-index: 9999;
}
span.question {
color: #272725 !important;
padding: 5px 0;
display: block;
width: 70%;
margin: auto;
}
span.inp-value {
position: absolute;
top: -60px;
display: block;
text-align: center;
width: 100%;
color: #272725;
}
<div class="questions">
<div class="range">
<input type="range" min="1" max="5" steps="1" value="1">
</div>
<ul class="range-labels" id="working-with-people-question1">
<li id="1" class="active selected"><span class="inp-value">1</span><span class="question">Shows little interest in or understanding of others</span></li>
<li id="2"><span class="inp-value">2</span></li>
<li id="3"><span class="inp-value">3</span></li>
<li id="4"><span class="inp-value">4</span></li>
<li id="5"><span class="inp-value">5</span><span class="question">Demonstrate an interest in and understanding of others</span></li>
</ul>
</div>
<div class="questions" style="padding-top: 100px">
<div class="range">
<input type="range" min="1" max="5" steps="1" value="1">
</div>
<ul class="range-labels" id="working-with-people-question1">
<li id="1" class="active selected"><span class="inp-value">1</span><span class="question">Question 2</span></li>
<li id="2"><span class="inp-value">2</span></li>
<li id="3"><span class="inp-value">3</span></li>
<li id="4"><span class="inp-value">4</span></li>
<li id="5"><span class="inp-value">5</span><span class="question">Question 2</span></li>
</ul>
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
Codepen here - https://codepen.io/scottYg55/pen/BazGamz
The problem is that getTrackStyle(this) is sending all the elements and not just (this). (this) is global and not set to the individual (this) function

Increasing CSS value instead of decreasing with jquery

I have a page that I need to convert to rtl.
The active tab & tab arrow position doesn't match.
I need to change the tab arrow position from TAB 1 to TAB 2 and vice versa.
I already changed some js value but in vain
HTML :
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="main-search-container">
<form class="main-search-form">
<div class="search-type">
<label class="active"><input class="first-tab" name="tab" checked="checked" type="radio">TEXT</label>
<label><input name="tab" type="radio">TEXT</label>
<label><input name="tab" type="radio">TEXT</label>
<div class="search-type-arrow"></div>
</div>
<div class="main-search-box">
<div class="main-search-input larger-input">
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
CSS :
body {
direction:rtl;
color: #707070;
background-color: #cccccc;
}
.parallax {
background-repeat: no-repeat;
background-position: 50% 50%;
position: relative;
z-index: 99;
}
.parallax-overlay {
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;
z-index: 101;
background-color: #333;
opacity: 0.4;
}
.parallax-content {
position: relative;
z-index: 999;
padding: 105px 0;
}
.main-search-container {
transform: translate3d(0,-12px,0);
}
.main-search-form {
width: 660px;
display: block;
margin: 0 auto;
position: relative;
margin-top: 35px;
}
.search-type {
display: inline-block;
padding-bottom: 35px;
position: relative;
}
.search-type input[type="radio"] { display: none; }
.search-type label {
background-color: #fff;
color: #333;
cursor: pointer;
display:inline-block;
text-align: center;
padding: 9px 18px;
margin: 0 0 0 15px;
float: right;
transition: all 0.2s;
border-radius: 3px;
}
.search-type label:hover,
.search-type label.active {
background-color: #66676b;
color: #fff;
}
.search-type-arrow {
width: 0;
height: 0;
border-right: 15px solid transparent;
border-left: 15px solid transparent;
border-bottom: 15px solid #fff;
position: absolute;
bottom: 0;
right: 0;
transform: translate3d(-3px,0,0);
}
.main-search-box {
background-color: #fff;
box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.12);
padding: 30px;
padding-bottom: 20px;
margin-top: -9px;
border-radius: 3px;
}
.main-search-box.no-shadow {
box-shadow: none;
padding: 0;
margin: 0;
}
.search-container .main-search-input input {
font-weight: 500;
font-size: 17px;
height: 57px !important;
float: right;
box-sizing: border-box;
border: none;
float: right;
height: auto;
}
.search-container .main-search-input button.button {
width: initial;
min-width: 100px;
max-width: 100px;
margin: 0;
font-size: 18px;
position: relative;
margin-right: 20px;
flex: 0 auto;
height: 57px;
}
.search-container .main-search-input button.button i {
position: relative;
right: 2px;
}
JS :
(function($){
"use strict";
$(document).ready(function(){
function searchTypeButtons() {
// Radio attr reset
$('.search-type label.active input[type="radio"]').prop('checked',true);
// Positioning indicator arrow
var buttonWidth = $('.search-type label.active').width();
var arrowDist = $('.search-type label.active').position().left;
$('.search-type-arrow').css('right', arrowDist + (buttonWidth/2) );
$('.search-type label').on('change', function() {
$('.search-type input[type="radio"]').parent('label').removeClass('active');
$('.search-type input[type="radio"]:checked').parent('label').addClass('active');
// Positioning indicator arrow
var buttonWidth = $('.search-type label.active').width();
var arrowDist = $('.search-type label.active').position().left;
$('.search-type-arrow').css({
'right': arrowDist + (buttonWidth/2),
'transition':'right 0.4s cubic-bezier(.87,-.41,.19,1.44)'
});
});
}
// Init
if ($(".main-search-form").length){
searchTypeButtons();
$(window).on('load resize', function() { searchTypeButtons(); });
}
// ------------------ End Document ------------------ //
});
})(this.jQuery);
I'm using bootstrap, bootstrap rtl flipped & jquery 2.2.0 as external ressources.
Here's the snippet:
https://jsfiddle.net/s3hy37nd/5/
Can someone help with that?
So many errors... I can only say I tried to comment them all inside the code so... yeah it's all there:
"use strict";
jQuery(function($) { // DOM ready and $ alias secured
// Radio attr reset (on DOM ready... makes sense?)
$('.search-type label.active input[type="radio"]').prop('checked', true);
function repositionArrow() { // Use a meaningful fn name
// Positioning indicator arrow
// Width? No. You need .outerWidth! you have paddings!!
var buttonWidth = $('.search-type label.active').outerWidth();
// Again use meaningful names
// If you do console.log( $('.search-type label.active').position() );
// you'll see no `.right` property. So yeah, use .left
var posLeft = $('.search-type label.active').position().left;
$('.search-type-arrow').css({
left: posLeft + (buttonWidth / 2)
// No need for transition here - move it to Stylesheet instead
});
}
// Init
if ($(".main-search-form").length) {
// You might want this too inside the "if"
$('.search-type label').on('change', function() {
$('.search-type input[type="radio"]').parent('label').removeClass('active');
$('.search-type input[type="radio"]:checked').parent('label').addClass('active');
repositionArrow(); // Now you have such function
});
repositionArrow();
$(window).on('load resize', repositionArrow);
}
});
body {
direction: rtl;
color: #707070;
background-color: #cccccc;
}
.parallax {
background-repeat: no-repeat;
background-position: 50% 50%;
position: relative;
z-index: 99;
}
.parallax-overlay {
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;
z-index: 101;
background-color: #333;
opacity: 0.4;
}
.parallax-content {
position: relative;
z-index: 999;
padding: 105px 0;
}
.main-search-container {
transform: translate3d(0, -12px, 0);
}
.main-search-form {
width: 660px;
display: block;
margin: 0 auto;
position: relative;
margin-top: 35px;
}
.search-type {
display: inline-block;
padding-bottom: 35px;
position: relative;
}
.search-type input[type="radio"] {
display: none;
}
.search-type label {
position: relative;
/* YOU NEED SOME POSITION! */
background-color: #fff;
color: #333;
cursor: pointer;
display: inline-block;
text-align: center;
padding: 9px 18px;
margin: 0 0 0 15px;
/*float: right; WHY? you use rtl already */
transition: all 0.2s;
border-radius: 3px;
}
.search-type label:hover,
.search-type label.active {
background-color: #66676b;
color: #fff;
}
.search-type-arrow {
width: 0;
height: 0;
border-right: 15px solid transparent;
border-left: 15px solid transparent;
border-bottom: 15px solid #fff;
position: absolute;
bottom: 0;
/*right: 0; ...Nope. See JS, we need left */
left: calc(100% - 30px);
/* calc to the rescue */
/*transform: translate3d(-3px,0,0); but why */
transition: left 0.4s cubic-bezier(.87, -.41, .19, 1.44);
/* Moved from JS */
}
.main-search-box {
background-color: #fff;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.12);
padding: 30px;
padding-bottom: 20px;
margin-top: -9px;
border-radius: 3px;
}
<div class="parallax-content">
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="main-search-container">
<form class="main-search-form">
<div class="search-type">
<label class="active"><input class="first-tab" name="tab" checked="checked" type="radio">TAB 1</label>
<label><input name="tab" type="radio">TAB 2</label>
<label><input name="tab" type="radio">TAB 3</label>
<div class="search-type-arrow"></div>
</div>
<div class="main-search-box">
<div class="main-search-input larger-input">
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
Updated jsFiddle

Categories