Index not being counted on click - javascript

I have a slider where I want to keep track of the current position of the slider. The function that runs when the ('next') and ('prev') are being clicked, is supposed to log the current position of the slider.
Unfortunately it skips the first child and starts the count on the second item in the slider. Instead of the first item being index 0, the second item is index 0
$(document).foundation()
$('.bullet').first().addClass('active');
//sets first item to active
$('.slider-item').first().addClass('active');
function dec() {
var $this = $(this);
var current = $('.slider-items').find('.active');
var position = $('.slider-items').children().index(current);
console.log(position)
}
$('.next, .prev').click(function() {
dec();
var $this = $(this);
var current = $('.slider-items').find('.active');
var position = $('.slider-items').children().index(current);
var numItems = $('.slider-item').length;
if ($this.hasClass('next')) {
if (position < numItems - 1) {
$('.active').removeClass('active').next().addClass('active');
} else {
$('.slider-item').removeClass('active').first().addClass('active');
$('.bullet').removeClass('active').first().addClass('active');
} //else
} else {
if (position === 0) {
$('.slider-item').removeClass('active').last().addClass('active');
$('.bullet').removeClass('active').last().addClass('active');
} else {
$('.active').removeClass('active').prev().addClass('active');
}
}
}); // click function

The code seems to work when I run it against a simple bullet list example. It correctly states that the first bullet point is index 0. Are you simply calling the dec() function in the wrong place? Note that when you click next, you are logging the current position before the change is made to the position. I updated the dec() code to accept a parameter to show what I mean.
$(document).ready(function() {
//sets first item to active
$('.slider-item').first().addClass('active');
function dec(prefix) {
var $this = $(this);
var current = $('.slider-items').find('.active');
var position = $('.slider-items').children().index(current);
console.log(prefix + position);
}
$('.next, .prev').click(function() {
dec("before click handled: ");
var $this = $(this);
var current = $('.slider-items').find('.active');
var position = $('.slider-items').children().index(current);
var numItems = $('.slider-item').length;
if ($this.hasClass('next')) {
if (position < numItems - 1) {
$('.active').removeClass('active').next().addClass('active');
} else {
$('.slider-item').removeClass('active').first().addClass('active');
$('.bullet').removeClass('active').first().addClass('active');
} //else
} else {
if (position === 0) {
$('.slider-item').removeClass('active').last().addClass('active');
$('.bullet').removeClass('active').last().addClass('active');
} else {
$('.active').removeClass('active').prev().addClass('active');
}
}
dec("after click handled: ");
})}); // click function
li.active {
color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="slider-items">
<li class="slider-item">A</li>
<li class="slider-item">B</li>
<li class="slider-item">C</li>
<li class="slider-item">D</li>
</ul>
<button class="prev">Prev</button>
<button class="next">Next</button>

Related

jQuery behavior on variable

I am customizing the jump example of markjs.
markjs_example
I have added some actions when I press the next button at the last instance of searched term, at this point it works.
if(currentIndex == 0 && jQuery(this).is($nextBtn)){
if(confirm("No more instances found! Go to the next page?")){
alert("NEXT PAGE");
}
}
Now I wanted to change the search behavior if I have reached the last marked word so I have added a variable i that I increment if I have reached the last marked word.
So i = 1 if nothing happened.
And i = 2 if I have reached the last word and pressed next, aka I am on the imaginary next page
To test all this I have added console log as you will see in the jsfiddle.
The problem is : it never prompt "page2" in the console, and i stays at 1, why?
jsfiddle_of_my_code
The code in if(i === 1) and else are evaluated only first time when page loads, and only the if condition is executed and registers the unmark method. Once i changes to 2 , the else condition for i===2 is never executed, therefore the second method $content.unmark is not registered or executed
You need to call unmark method once i changes to 2.
As in the code below,
jQuery(function() {
// the input field
$input = jQuery("input[type=\'search\']");
// clear button
var $clearBtn = jQuery("button[data-search=\'clear\']"),
// prev button
$prevBtn = jQuery("button[data-search=\'prev\']"),
// next button
$nextBtn = jQuery("button[data-search=\'next\']"),
// the context where to search
$content = jQuery(".content"),
// jQuery object to save <mark> elements
$results,
// the class that will be appended to the current
// focused element
currentClass = "current",
// top offset for the jump (the search bar)
offsetTop = 50,
// the current index of the focused element
currentIndex = 0,
//2 after last occurence reached
i = 1;
/**
* Jumps to the element matching the currentIndex
*/
function jumpTo() {
if ($results && $results.length) {
var position,
$current = $results.eq(currentIndex);
$results.removeClass(currentClass);
if ($current.length) {
$current.addClass(currentClass);
position = $current.offset().top - offsetTop - 100;
window.scrollTo(0, position);
}
}
}
/**
* Searches for the entered keyword in the
* specified context on input
*/
$input.on("input", function() {
searchVal = this.value;
$content.unmark({
done: function() {
$content.mark(searchVal, {
separateWordSearch: true,
done: function() {
$results = $content.find("mark");
currentIndex = 0;
console.log("page1");
console.log(i);
jumpTo();
}
});
}
});
});
function registerClear(){
$content.unmark({
done: function() {
$content.mark(searchVal, {
separateWordSearch: true,
done: function() {
$results = $content.find("mark");
currentIndex = 0;
console.log(searchVal);
console.log("page2");
jumpTo();
}
});
}
});
}
/**
* Clears the search
*/
$clearBtn.on("click", function() {
$content.unmark();
$input.val("").focus();
});
/**
* Next and previous search jump to
*/
$nextBtn.add($prevBtn).on("click", function() {
if ($results.length) {
currentIndex += jQuery(this).is($prevBtn) ? -1 : 1;
if (currentIndex < 0) {
currentIndex = $results.length - 1;
}
if (currentIndex > $results.length - 1) {
currentIndex = 0;
}
//if next pressed after last instance
if(currentIndex == 0 && jQuery(this).is($nextBtn)){
if(confirm("No more instances found! Go to the next page?")){
alert("NEXT PAGE");
i = 2;
registerClear();
}else{
//do nothing
}
}
jumpTo();
}
});
});

JQuery count up with a timeout or endpoint

I have a timer which counts up to a figure based on a set of results from the database. however, when the data isnt present the timer will just keep going with no timeout or end point.
Is there a way I can either not show the timer if the value does not exist or show 0/40 see my code below:
$(function() {
function count($this) {
var current = parseInt($this.html(), 10);
$this.html(++current);
if (current !== $this.data('count')) {
setTimeout(function(){
count($this)
}, 50);
}
}
$(".fiveStarScore").each(function() {
$(this).data('count', parseInt($(this).html(), 10));
$(this).html('0');
count($(this));
});
});
This is the div that is targeted and will stop at the desired value.
<div>
<span class="fiveStarScore"><?php echo $total_five_stars;?></span>/40
</div>
You can fix this by checking if the text value of the element on load is 0 (or is any non numerical value) and not calling count() if so:
$(function() {
function count($el) {
var current = parseInt($el.text(), 10);
$el.html(++current);
if (current !== $el.data('count')) {
setTimeout(function() {
count($el)
}, 50);
}
}
$(".fiveStarScore").each(function() {
var $el = $(this);
var total = parseInt($el.text(), 10) || 0;
$el.data('count', total).text('0');
if (total == 0)
return;
count($el);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<span class="fiveStarScore">0</span>/40
</div>
<div>
<span class="fiveStarScore">25</span>/40
</div>

Stop loop and fade in area that is hovered on

I have a bit of javascript/jquery I am trying to figure out. What I have already is three boxes that the content fades in and out and loops through the three and repeats. What I am trying to do is when "box x" is hovered over the loop fades out and stops never to start again, and the box that is hovered on, the content below the box fades in and stays... unless another box is hovered over, then the content that faded in from the other hovered box will fade out and the new box that was hovered on, the content that coincides with that box fades in and stays fade in, and so forth.
How would I go about doing this?
Here is a jsfiddle example: http://jsfiddle.net/q0htx0no/
javascript/jquery
var infoboxes = $(".count p");
var counter = 0;
function rotate() {
$(infoboxes[counter]).fadeIn(1000, function() {
setTimeout(function() {
$(infoboxes[counter]).fadeOut(1000, function() {
counter = counter < infoboxes.length - 1 ? counter + 1 : 0;
rotate();
})
}, 1000);
});
}
$(function() {
rotate();
});
Thanks for any help
One option would be to have a global variable (a 'flag') that would indicate if the rotation should be stopped. Once a box has been hovered over, it should set hovered to True and should fade in that specific box.
Yep, use a global variable. Something like this:
var infoboxes = $(".count p");
var counter = 0;
var goAhead = true;
function rotate() {
$(infoboxes[counter]).fadeIn(1000, function() {
setTimeout(function() {
$(infoboxes[counter]).fadeOut(1000, function() {
counter = counter < infoboxes.length - 1 ? counter + 1 : 0;
checkRotate();
})
}, 1000);
});
}
function checkRotate() {
if (goAhead) { rotate(); }
}
$('.about').on('mouseover', function() {
goAhead = false;
var index = $(this).index();
var boxesToClear = $(infoboxes).filter(function(i) { return i !== index; });
$(boxesToClear).fadeOut(1000, function() {
$(infoboxes[index]).fadeIn(1000);
});
});
checkRotate();
DEMO
Here's one way to do it. It can probably be improved.
http://jsfiddle.net/vbt67x0h/2/
var infoboxes = $(".count p");
var counter = 0;
var isrotating = false;
function rotate(){
isrotating = true;
$(infoboxes[counter]).fadeIn(1000).delay(1000).fadeOut(1000);
counter = counter < infoboxes.length - 1 ? counter + 1 : 0;
}
//immediately stop rotate and hide all
function stoprotate(){
clearInterval(tmrrotate);
isrotating = false;
for(var x=0;x<infoboxes.length;x++){
$(infoboxes[x]).stop();
$(infoboxes[x]).hide();
}
}
rotate();
//rotate every 3 seconds, 1 to fadein, 1 to pause, 1 to fadeout
var tmrrotate = setInterval(function() {
rotate();
}, 3000);
$(".about").on('mouseover', function() {
if(isrotating){stoprotate()}
$(infoboxes[$(this).index()]).fadeIn(1000);
})
.on('mouseleave', function() {
$(infoboxes[$(this).index()]).fadeOut(1000);
});
You should make a timed array:
var arTimer = [];
and push all timers into that array, clearTimeout on hover and show only hovered index:
var infoboxes = $(".count p");
var counter = 0;
var arTimer = [];
function rotate() {
$(infoboxes[counter]).fadeIn(1000, function() {
arTimer.push(setTimeout(function() {
$(infoboxes[counter]).fadeOut(1000, function() {
counter = counter < infoboxes.length - 1 ? counter + 1 : 0;
rotate();
})
}, 1000));
});
}
function cleararTimer(){
for (var i = 0; i < arTimer.length; i++) {
clearTimeout(arTimer[i]);
}
}
$(function() {
rotate();
$('.about').on('mouseover', function(){
cleararTimer();
var hovered = $(this).index();
$('.count p').not(':eq('+hovered+')').fadeOut(1000);
$('.count p:eq('+hovered+')').fadeIn(1000);
});
});
jsFiddle Example

How to make random selector only pick shown items?

Yeah not very familiar with JQuery and I'm trying to make a random lunch picker for our web team.
http://jsfiddle.net/vy8RL/1/
I want to hide certain items. For example when you hit the "Quick Eats" button it only displays 4 options and when you hit "EAT ME" it still selects the LI's that are hidden. Is there any way to allow it only to select options that are visible?
$(document).ready(function() {
$("#button").click(function(){
random();
});
$("#unhealthy-food").click(function(){
$(".unhealthy").hide();
});
$("#all").click(function(){
$("li").show();
});
$("#fast-food").click(function(){
$(".food").hide();
$(".fast").show();
});
});
function random() {
$("li.selected").removeClass("selected");
var menuItems = $("ul#list li");
var numItems = menuItems.length;
if(window.sessionStorage && window.sessionStorage.getItem("selected")) {
previous = Number(window.sessionStorage.getItem("selected"));
} else {
previous = -1;
}
var selected = Math.floor(Math.random()*numItems);
while(selected === previous && numItems > 1) {
selected = Math.floor(Math.random()*numItems);
}
if(window.sessionStorage) window.sessionStorage.setItem("selected", selected);
$("ul#list li:nth-child("+(selected+1)+")").addClass("selected");
}
You can use the :visible selector:
function random() {
$("li.selected").removeClass("selected");
var menuItems = $("#list li").filter(':visible');
var numItems = menuItems.length;
// ...
menuItems.eq(selected).addClass("selected");
}
Please note that I have replaced the $("ul#list li:nth-child("+(selected+1)+")") with the cached collection + eq() method.
http://jsfiddle.net/3n9ex/
here you go. I just added tracking of menu preference. Also added $(".food").show(); in line 9 to correct a bug.
$(document).ready(function() {
var user_choice = ".food";
$("#button").click(function(){
random(user_choice);
});
$("#unhealthy-food").click(function(){
user_choice = "li:not(.unhealthy)";
$(".food").show();
$(".unhealthy").hide();
});
$("#all").click(function(){
$("li").show();
user_choice = ".food";
});
$("#fast-food").click(function(){
$(".food").hide();
$(".fast").show();
user_choice = ".fast";
});
});
function random(user_choice) {
$("li.selected").removeClass("selected");
var menuItems = $(user_choice);
console.log(menuItems);
var numItems = menuItems.length;
if(window.sessionStorage && window.sessionStorage.getItem("selected")) {
previous = Number(window.sessionStorage.getItem("selected"));
} else {
previous = -1;
}
var selected = Math.floor(Math.random()*numItems);
while(selected === previous && numItems > 1) {
selected = Math.floor(Math.random()*numItems);
}
if(window.sessionStorage) window.sessionStorage.setItem("selected", selected);
$(menuItems[selected]).addClass("selected");
}
http://jsfiddle.net/vy8RL/19/

.next() not working as intended

So,
if($(this).hasClass('active')){
$(this).removeClass('active');
$(this).prev().addClass('active');
}
works fine, it adds the class "active" to this previous div of the same kind.
if($(this).hasClass('active')){
$(this).removeClass('active');
$(this).next().addClass('active');
}
However, adds the class to the next div (as i intend for it to do) for about 0.5 of a second BUT then removes it.
Here's ALL of the jQuery (as per your comments below) - Please do not comment on my horrible code organization
$(window).load(function () {
// Initial variables
var numberSlides = 0;
var currentSlide = 1;
var ready = true;
var pageWidthR = $(document).width() - 352;
var pageWidthL = $(document).width() - 352;
// Update number of slides by number of .slide elements
$('#features-slider .slide').each(function () {
numberSlides++;
});
// Go through each slide and move it to the left of the screen
var i = 0;
$($('#features-slider .slide').get().reverse()).each(function () {
if (i == 0) {
} else {
var newWidth = i * 115;
$(this).css('left', '-' + newWidth + '%');
}
i++;
});
// Animate the first slide in
$('#features-slider .slide:last-child').addClass('active').animate({
left: 0
}, 1500);
// Remove the loading message
$('#loading').fadeOut(1000, function () {
$('#loading').remove();
// Now that we're done - we can show it
$('#features-slider').show();
});
/***** Left and Right buttons *****/
/* Right */
$('#rightbutton').click(function () {
var numberSlides = 0;
$('#features-slider .slide').each(function () {
numberSlides++;
});
var index = $('.slide.active').index() + 1;
if (!$('.slide').is(':animated') && index != 1) {
$('#features-slider .slide').each(function () {
if ($(this).hasClass('active')) {
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft) + 115;
} else {
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft) + 115;
}
$(this).animate({
left: newLeft + '%'
}, 1500);
if ($(this).hasClass('active')) {
$(this).removeClass('active');
$(this).prev().addClass('active');
}
});
}
});
/* Left */
$('#leftbutton').click(function () {
var numberSlides = 0;
$('#features-slider .slide').each(function () {
numberSlides++;
});
var index = $('.slide.active').index() + 1;
if (!$('.slide').is(':animated') && index != numberSlides) {
$('#features-slider .slide').each(function () {
if ($(this).hasClass('active')) {
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft) - 115;
} else {
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft) - 115;
}
$(this).animate({
left: newLeft + '%'
}, 1500);
if ($(this).hasClass('active')) {
$(this).next().addClass('active');
$(this).removeClass('active').not($(this).next());
}
});
}
});
});
$(document).ready(function () {
// Hide the slider and show a loading message while we do stuff and the images / DOM loads - Also disable overflow on the body so no horizontal scrollbar is shown
$('body').css('overflow-x', 'hidden');
$('#features-slider').hide();
$('#loading').html('<center> <img id="loader" src="/wp-content/themes/responsive/library/images/ajax-loader.gif" /> Loading</center>');
});
RESOLVED
New left button function :
$('#leftbutton').click(function(){
var numberSlides = 0;
$('#features-slider .slide').each(function(){
numberSlides++;
});
var index = $('.slide.active').index()+1;
if( !$('.slide').is(':animated') && index != numberSlides ){
var done = false;
$('#features-slider .slide').each(function(){
if($(this).hasClass('active')){
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft)-115;
} else {
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft)-115;
}
$(this).animate({left: newLeft+'%'}, 1500);
if($(this).hasClass('active') && done == false){
$(this).next().addClass('active');
$(this).removeClass('active');
done = true;
}
});
});
If you're iterating forward through the elements, then it should be clear what's going on - you add the "active" class to the next element, and then the next iteration takes it away.
This is just a guess however as you did not post enough code for me (or anybody else) to be sure.
edit — ok now that you've updated the question, it's clear that the guess was correct. The .each() function will iterate forward through the elements. When an element has the "active" class, and the code removes it and adds it to the next element, then on the next iteration the work is undone.
Since you are referencing this and by the behavior you're describing, you are likely iterating a loop for a list of elements. As a result, you are completing the action you want but the next iteration is removing the previous changes due to your usage of removing a class and then adding the class back.
As it stands now, your code does not illustrate how this occurence can be happening.
Update:
As suspected, you seem to be looping as signified by: each(function(){. While iterating through your objects the class is being pushed forward and is not acting as desired. You are stating add the class to the next element, but remove it from the current element, and this behavior continues through your iteration.
On a side note, update your code to call removeClass() on the current object first, before adding it to the next object:
if ($(this).hasClass('active')) {
$(this).removeClass('active').next().addClass('active');
}

Categories