My custom javascript Carousel is not working properly [duplicate] - javascript

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I'm trying to implement a carousel with Javascript but I'm having trouble with my navigation buttons.
Prev and Next works fine but the navigation dots as I'm calling are not.
Also, I want to show the title of the images on a span as per the HTML on jsfiddle. You can see my attempt on the javascript file bellow the following comment.
// show the title of the image when hovering the associated dot.
Here is the javascript. The other files can be seem at jsfiddle
$(document).ready(function() {
var carouselItems = [
{ src: "http://placehold.it/600x300/cccccc/000000", title: "Sample 01" },
{ src: "http://placehold.it/600x300/f45a45/000000", title: "Sample 02" },
{ src: "http://placehold.it/600x300/b78d65/000000", title: "Sample 03" },
{ src: "http://placehold.it/600x300/666aa0/000000", title: "Sample 04" },
{ src: "http://placehold.it/600x300/cccddd/000000", title: "Sample 05" }
];
Carousel = function() {
// keep track of the current position
var position = 0;
// build carousel based on items in the carouselItems array
$(carouselItems).each(function(index, value){
var li = $('<li/>');
li.addClass('carousel-item');
li.css('width', 100 / carouselItems.length + '%');
li.appendTo($('#carousel'));
var img = $('<img/>');
img.attr('src', value.src);
img.appendTo(li);
var liDot = $('<li/>');
liDot.addClass('carousel-dots-nav-item').html('o');
liDot.appendTo($('#carousel-dots-nav'));
});
// increase width of the carousel
$('#carousel').css('width', carouselItems.length * 100 + '%');
// add events to dots
for (i = 0; i < $('.carousel-dots-nav-item').length; i++) {
var dot = $('.carousel-dots-nav-item')[i];
// show the title of the image when hovering the associated dot
$(dot).hover(function(e){
$('#title').text(carouselItems[i].title);
}, function(e){
$('#title').text('');
});
// move to the appropriate slide when a dot is clicked
$(dot).click(function(e){
position = i;
$('#carousel').animate({
left: -position * 100 + '%'
}, 500);
});
}
// add click event to next button
$("#next").click(function(e){
e.preventDefault();
if (position == carouselItems.length - 1) return;
position++;
$('#carousel').animate({
left: -position * 100 + '%'
}, 500);
});
// add click event to previous button
$("#previous").click(function(e){
e.preventDefault();
if (position == 0) return;
position--;
$('#carousel').animate({
left: -position * 100 + '%'
}, 500);
});
};
var carousel = new Carousel();
});
jsfiddle

In this loop:
for (i = 0; i < $('.carousel-dots-nav-item').length; i++) {
var dot = $('.carousel-dots-nav-item')[i];
/*...*/
// move to the appropriate slide when a dot is clicked
$(dot).click(function(e){
position = i;
$('#carousel').animate({
left: -position * 100 + '%'
}, 500);
});
}
You are using i to define the position. But all that is in the click function is not executed inside the loop but when you click on a dot element. So i is equal to $('.carousel-dots-nav-item').length. And you are lucky to have defined it globally.
fiddle
A solution is to store the position of each item in a data-position attribute. As you are using jquery, I used also it:
//
var liDot = $('<li/>');
liDot.data("position", index);
liDot.addClass('carousel-dots-nav-item').html('o');
liDot.appendTo($('#carousel-dots-nav'));
//
$(dot).click(function(e){
var position= $(this).data('position');
$('#carousel').animate({
left: -1*position * 100 + '%'
}, 500);
});

Related

ScrollFire Materialize reveal List

Hi i am looking for a possible solution for the following problem.
I am building a website and i have a table which has many many rows.
I am using materialize (but if there is another plugin that can do it i am open for it).
Materialize uses this
var options = [
{selector: '#staggered-test', offset: 50, callback: function(el) {
Materialize.toast("This is our ScrollFire Demo!", 1500 );
} },
{selector: '#staggered-test', offset: 205, callback: function(el) {
Materialize.toast("Please continue scrolling!", 1500 );
} },
{selector: '#staggered-test', offset: 400, callback: function(el) {
Materialize.showStaggeredList($(el));
} },
{selector: '#image-test', offset: 500, callback: function(el) {
Materialize.fadeInImage($(el));
} }
];
Materialize.scrollFire(options);
But how to implement it on table rows?
I would simply like to hide most of the rows but get visible the more the user scrolls down.
Is this possible?
Thanks
Instead of scroll i made a button to show more using javascript and jquery here is the function
$.fn.RowReveal = function(RowsToShow, numMore) {
var numShown = RowsToShow;
var numMore = numMore;
var $table = $(this).find('tbody');
var numRows = $table.find('tr').length;
var btn_id = parseInt(Math.random()*1000)+numRows;
// Hide rows and add clickable div
$table.find('tr:gt(' + (numShown - 1) + ')').hide().end()
.after('<tbody id="more-'+btn_id+'"><tr><td colspan="' +
$table.find('tr:first td').length + '"><div>Show More</div></tbody></td></tr>');
$('#more-'+btn_id).click(function () {
numShown = numShown + numMore;
if (numShown >= numRows) {
$('#more-'+btn_id).remove();
}
if (numRows - numShown < numMore) {
$('#more-'+btn_id+' span').html(numRows - numShown);
}
$table.find('tr:lt(' + numShown + ')').fadeIn();
});
}

Javascript slider function - How to objectify the selectors?

I'm currently working on a project where a custom slider was needed and i quickly grabbed a neat looking tutorial of the web and went away and staticly it all works great.
Now i want to be able to put several sliders on my page and therefore need to add the controls dynamicly rather than just selecting a certain slider with jquery like I've done below.
This is my code with comments added to explain what im trying to achieve:
var Slider = function() { this.initialize.apply(this, arguments) };
Slider.prototype = {
initialize: function(slider) {
this.ul = slider.children[2];
this.li = this.ul.children;
this.nav = slider.children[3]; //Why cant i use .append on this element?
// make <ul> as large as all <li>’s
this.ul.style.width = (100 * this.li.length) + '%';
// set width of the li's
for(i = 0; i < this.li.length; i++) {
this.li[i].style.width = (100 / this.li.length) + '%';
$(".slider-nav").append( '<div class="slider-dot"></div>'); //Want to make it a this.nav or something similar instead of an external selector
//console.log(this.nav);
}
this.currentIndex = 0;
},
goTo: function(index) {
if (index < 0 || index > this.li.length - 1)
return;
// move <ul> left
this.ul.style.left = '-' + (100 * index) + '%';
this.currentIndex = index
},
goToPrev: function() {
this.goTo(this.currentIndex - 1)
},
goToNext: function() {
this.goTo(this.currentIndex + 1)
}}
var sliders = [];
$('.slider').each(function() {
sliders.push(new Slider(this));
});
//Find a way to implement theese 2 within the slider function, how to find out what position in the array a slider has?
$(".prev-btn").click(function() {
sliders[0].goToPrev();
});
$(".next-btn").click(function() {
sliders[0].goToNext();});
The marks up for the slider looks like this: http://puu.sh/hAUH1/a865792137.png
I managed to get it done by defining this as another var
var sliderEle = this;
I could then call it like this:
$(this.prev).click(function(e) {
e.preventDefault();
sliderEle.goToPrev();
});
with prev and next defined like this:
this.prev = slider.children[0];
this.next = slider.children[1];

Create a new div and display it where the mouse cursor is on page

At the moment, the circles are being appended to <p> in the html markup.
You can see how I have done this below.
But what I actually want is for the div to be created where the mouse cursor is the on the page.
How might I get the position of the cursor and create a div there?
Thanks.
var count = 0;
/*
* Function(makeLetters)
* Removes first character in text box.
* Creates circle Letters using first character.
*/
$(document).click(function (makeLetters) {
//Get characters currently entered into textbox
var letters = $('#letters').val();
//Take the firstLetter only
var firstLetter = letters.substr(0, 1);
//Count how many characters currently entered
var numberOfLetters = letters.length;
//Use length of entry to take all characters except first
var restOfLetters = letters.substr(1, numberOfLetters);
//All characters except first set as textbox entry
$("#letters").val(restOfLetters);
//Check that there is a first character
if (firstLetter != "") {
count++;
//Create a new circle letter by inserting new div class
$("p").append('<div class="circle' + count + '" style="border-radius: 50%;width: 36px;height:36px;padding:8px;background:#FF7D5C;color:black;text-align:center;font:32px Arial, sans-serif;display:inline-block;margin-right:4px;margin-bottom:4px;">' + firstLetter.toUpperCase() + '</div>');
$("p").children().last().hide().fadeIn();
}
});
As far as I'm aware you cant get the mouse position on its own, but you could use jQuery to listen to the mousemove event and store the position in a variable for use later like so:
var mousePosition = { x: 0, y: 0 };
$(document).mousemove(function(e) {
mousePosition.x = e.pageX;
mousePosition.y = e.pageY;
});
Then you would need to use postion: [absolute/fixed]; to position the div based on the mousePosition.
You'd do that by getting the mouse position from the event, that you for some strange reason named makeLetters ?
$(document).click(function(event) {
var letters = $('#letters').val();
var firstLetter = letters.substr(0, 1);
var numberOfLetters = letters.length;
var restOfLetters = letters.substr(1, numberOfLetters);
var mouseLeft = event.pageX;
var mouseTop = event.pageY;
$("#letters").val(restOfLetters);
if (firstLetter != "") {
count++;
var div = $('<div />', {
'class' : 'circle' + count,
text : firstLetter.toUpperCase(),
css : {
position: 'fixed',
top : mouseTop + 'px',
left : mouseLeft + 'px',
display : 'none'
// ... the rest of the styles here
}
});
$("p").append( div.fadeIn() );
}
});

Adding delay to DIV animation

I'm trying to create div boxes step by step and animate them for several times when a button is pressed. I have a running code, and everything is going well. It goes right to the endhost, then it goes left again to its original place. This is mainly what I do, and also the demo is found here: http://jsfiddle.net/54hqm/3/
Now I want to happen after each click, is basically to move each DIV one after another, with a delay, instead of moving the whole stack of DIVs at once. I don't exactly know what to do. Can anyone help me with that?
$(document).ready(function () {
var count = 0;
var items = 0;
var packetNumber = 0;
var speed = 0;
$("button").click(function () {
if (count < 4) {
items = items + 1;
count++;
} else {
items = items * 2;
}
speed = $("#speed").val();
createDivs(items);
animateDivs();
});
function createDivs(divs) {
packetNumber = 1;
var left = 60;
for (var i = 0; i < divs; i++) {
var div = $("<div class='t'></div>");
div.appendTo(".packets");
$("<font class='span'>" + packetNumber + "</font>").appendTo(div);
packetNumber++;
div.css("left",left+"px");
div.hide();
left += 20;
}
}
function animateDivs() {
$(".t").each(function () {
var packet = $(this);
packet.show();
packet.animate({
left: '+=230px'
}, speed);
packet.animate({
left: '+=230px'
}, speed);
packet.animate({
top: '+=20px',
backgroundColor: "#f09090",
text: '12'
}, speed / 4, "swing", function () {
$('.span').fadeOut(100, function () {
$(this).text(function () {
return 'a' + $(this).text().replace('a', '');
}).fadeIn(100);
});
});
packet.delay(1000).animate({left:'-=230px'}, speed);
packet.animate({left:'-=230px'}, speed);
}).promise().done(function(){
$(".packets").empty();});
}
});
You can make this with 2 small modifications:
In your each() function, add the index parameter to know the index of the currently animating packet:
$(".t").each(function (index) {
Before your animate calls, insert a packet.delay() with a delay increasing with every item:
packet.delay(index * 250);
I updated your fiddle to show results.
Update: I made a second version based on your comment.

.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