Implementing a Parameter to a plugin - Shows 'X' number of elements - javascript

The current plugin, shown below, scrolls the top-most div in a series of divs with the same class upwards, then removes it from the container, and appends it to the bottom of the series (within the container). This gives the illusion of a vertical slideshow.
$.fn.rotateEach = function ( opts ) {
var $this = this,
defaults = {
delay: 5000
},
settings = $.extend(defaults, opts),
rotator = function ($elems) {
$elems.eq(0).slideUp(500, function(){
var $eq0 = $elems.eq(0).detach();
$elems.parent().append($eq0);
$eq0.fadeIn();
setTimeout(function(){ rotator( $($elems.selector) ); },
settings.delay);
});
};
setTimeout(function(){ rotator( $this ); }, settings.delay);
};
$('.dynPanelContent').rotateEach();
However, if there are a large number of elements to scroll through, this would make for a VERY long page. As such, I am attempting to re-write this script so that it accepts a parameter which will determine how many elements to display. Any elements exceeding this number will be hidden until they are in the top 'x' number of elements. Here is an example of what I have attempted to implement.
$.fn.rotateEach = function (opts) {
var $this = this,
defaults = {
delay: 5000,
//Add a parameter named elementsShown, pass in a default value of 3
elementsShown: 3
},
settings = $.extend(defaults, opts),
rotator = function ($elems) {
//Hide the elements that are past the number to be shown
for (i = settings.elementsShown; i <= $elems.eq; i++) {
$elems.eq(i).hide();
}
$elems.eq(0).slideUp(500, function () {
var $eq0 = $elems.eq(0).detach();
var $eqN = $elems.eq(settings.elementsShown) - 1;
//Check & Show the element that is now within the show range
if ($elems.eq() == $eqN) {
$elems.eq($eqN).show('slow');
}
$elems.parent().append($eq0);
$eq0.fadeIn();
setTimeout(function () { rotator($($elems.selector)); },
settings.delay);
});
};

You can use simple CSS for this, mate.
If your elements are all of the same height (which your problem has to assume: if you are rotating a whole bunch of things dynamically, you won't want your page to change height), then you don't really need to use JavaScript for this at all. Just set the height of the container to what you want and hide the overflow. Then when you remove and append, everything appears to work. This won't take care of your dynamic configuration, though.

Improved plug-in: http://jsfiddle.net/morrison/tTJaM/
Notes:
Added support for showing X elements.
Added support for rotating only certain elements.
Added support for stopping the rotations:
Stop after X milliseconds.
Stop after X rotations.
overflow-y:hidden is added to container dynamically.
Simplified your detaching/attaching.
Known Issues:
Displaying X elements doesn't check for a maximum.

Related

How do I check if an element is higher than itself?

I'm trying to make a collapsible submenu that, when there isn't enough space to fit all items, will throw overflowing items into a Bootstrap-style dropdown menu.
I'm doing this by checking if the submenu is greater than a certain height. If it's higher than this set height, it's considered overflowing and thus need to run it's function. However, the project I'm working on can't really have set heights on elements. These might change over time, and it will be a maintenance nightmare to go through all the code if something changes.
So how do I check if an element's height is higher than its own (I guess 'initial') height?
Setting if(menuHeight >= menuHeight) will cause a Maximum call stack size exceeded-error and crash the tab in Chrome.
Example:
var CollapseMenu = {
init: function(parent) {
var menu = parent;
var menuHeight = menu.height(); // Using jQuery here; vanilla JS could also work
if(menuHeight >= 64) // This is the set height I want to avoid
// ...
} else {
// ...
}
}
}
$(function() {
var submenu = $('.submenu');
if(submenu.length) {
CollapseMenu.init($('.submenu ul'));
}
$(window).resize(function() {
if(submenu.length) {
CollapseMenu.init($('.submenu ul'));
}
});
});

Detecting the end of a overflow-x:scroll element and add a class before animation

As the title suggests I want to detect the start and end of a scrollable element built using overflow.
The following code works:
var scrollAmount = 150;
var scrollBox = $('.js-compare_scroll');
var arrowLeft = $('.js-compare_scroll_left');
var arrowRight = $('.js-compare_scroll_right');
var inactive = 'm-inactive';
$(arrowLeft).on('click', function () {
$(this).parent().find(scrollBox).stop().animate({
scrollLeft: '-='+scrollAmount
}, function() {
arrowRight.removeClass(inactive);
if(scrollBox.scrollLeft() === 0) {
arrowLeft.addClass(inactive);
}
});
});
$(arrowRight).on('click', function () {
$(this).parent().find(scrollBox).stop().animate({
scrollLeft: '+='+scrollAmount
}, function() {
arrowLeft.removeClass(inactive);
if(scrollBox.scrollLeft() + scrollBox.innerWidth() >= scrollBox[0].scrollWidth) {
arrowRight.addClass(inactive);
}
});
});
However the class to style the inactive colour of the arrows only appears once the animation completes. I need to add the class before the animation completes because it has a delay. I believe by default it is 400.
Is there anyway to detect this and apply the arrow classes where needed?
Thanks.
Came back from a break and realised I should take the checking if its at the end off the click event and onto a scroll event. This works a lot better now.

remove one class when animating

I try to animate menu-panel. It should slide to the left. But it doesn't work right. And I can't understand why.
There are a few issues with the current code (e.g. you were missing a . on one panel selector and not referencing panel1 after changing the panel class. I also switched to absolute positioning with the arrow inside the panel.
I did a little cleanup to make the changes obvious (you should not repeat jQuery selectors - use temp vars instead):
JSFiddle: http://jsfiddle.net/TrueBlueAussie/2x3uT/8/
$(function () {
$('.slider-arrow').click(function () {
var $this = $(this);
var $panel = $(".panel, .panel1");
var left = -53;
var text = '»';
if ($this.hasClass('hide')) {
text = '«';
left = 0;
}
$panel.animate({
left: left
}, 700, function () {
// Animation complete.
$this.html(text).toggleClass('hide').toggleClass('show');
$panel.toggleClass('panel').toggleClass('panel1');
});
});
});
You can tweak the position numbers to make it match what you wanted.

jQuery wait for an action to complete on different functions

I have created a newsfeed. The feed switches every 2 seconds. You can also manually switch left/right, or click the panel from the squares at the bottom. The switching between slides is down using jQuery UI Slide.
Right now, if you are in the middle of a slide, and you click left/right/squares, then another slide occurs on top of the existing, still going slide and the whole system is messed up.
How can I prevent other actions occurring if a slide/switch is already in progress?
This is my code:
$(document).ready(function(){
newsfeedTimer = setInterval(newsfeed, displayDuration);
// Manual change of feed (LEFT)
$('#newsfeeds_wrapper > .left').click(function(event){
event.stopPropagation();
feedLeft();
clearInterval(newsfeedTimer);
newsfeedTimer = setInterval(newsfeed, displayDuration);
});
// Very similar code for feed right
// Ignore the other method of switching (if it works for above, I can implement it for this one)
});
function newsfeed() {
feedRight();
}
// Feed to the Right
// jump is used to jump multiple newsfeed instead of one at a time
function feedRight(jump)
{
jump = typeof jump !== 'undefined' ? jump : 1;
var current = $('.newsfeed:first');
var next = $('.newsfeed:nth(' + jump + ')');
current.hide('slide',{duration: transitionDuration}, function(){
// Append as many needed
for( var i = 0; i < jump; i++ ) {
$('.newsfeed:first').appendTo('#newsfeeds');
}
next.show('slide',{direction : 'right' , duration: transitionDuration});
}
I don't want to stop() an animation! I want to disable changing the slides IF there is animation happening!!
without seeing the full breadth of the code, I am shooting myself in the foot here. But here is a direction I would take it. You could also have two functions, one to bind, another to unbind. When animation is initiated, you unbind the left/right controls. When stopped, you bind. Or, set a global variable... ala.
var config = {'inProgress': false};
$('#newsfeeds_wrapper > .left').click(function(event){
if(!config.inProgress){
event.stopPropagation();
feedLeft();
clearInterval(newsfeedTimer);
newsfeedTimer = setInterval(newsfeed, displayDuration);
}
});
in your animation function. Seems like when you cut/paste, some of the code is lost, so lets just assume some animation.
when you enter your animation functions, set config.inProgress = true;
function feedRight(jump)
{
config.inProgress = true;
// removed your code, but just using for simplicity sake
// added a callback
next.show('slide',{direction : 'right' , duration: transitionDuration},
function() {
// Animation complete. Set inProgress to false
config.inProgress = false;
});
)
}

Slide boxes with margin-left check if overslided

I made a simple content/box slider which uses the following javascript:
$('#left').click(function () {
$('#videos').animate({
marginLeft: '-=800px'
}, 500);
});
$('#right').click(function () {
$('#videos').animate({
marginLeft: '+=800px'
}, 500);
});
Here is the demo: http://jsfiddle.net/tjset/2/
What I want to do and I can't figure out how to show and hide arrows(left and right box) as the all the boxes slided.
So I clicked 4 time to the LEFT and slided all the boxes! then hide "left" so that you can't give more -800px
What can I do?
What you can do is check after the animation completes to see if the margin-left property is smaller or larger than the bounds of the video <div>. If it is, depending on which navigation button was clicked, hide the appropriate navigation link.
Check out the code below:
$('#left').click(function () {
// reset the #right navigation button to show
$('#right').show();
$('#videos').animate({
marginLeft: '-=800px'
}, 500, 'linear', function(){
// grab the margin-left property
var mLeft = parseInt($('#videos').css('marginLeft'));
// store the width of the #video div
// invert the number since the margin left is a negative value
var videoWidth = $('#videos').width() * -1;
// if the left margin that is set is less than the videoWidth var,
// hide the #left navigation. Otherwise, keep it shown
if(mLeft < videoWidth){
$('#left').hide();
} else {
$('#left').show();
}
});
});
// do similar things if the right button is clicked
$('#right').click(function () {
$('#left').show();
$('#videos').animate({
marginLeft: '+=800px'
}, 500, 'linear', function(){
var mRight = parseInt($('#videos').css('marginLeft'));
if(mRight > 100){
$('#right').hide();
} else {
$('#right').show();
}
});
});
Check out the jsfiddle:
http://jsfiddle.net/dnVYW/1/
There are many jQuery plugins for this. First determine how many results there are, then determine how many you want visible, then use another variable to keep track with how many are hidden to the left and how many are hidden to the right. So...
var total = TOTAL_RESULTS;
var leftScrolled = 0;
var rightScrolled = total - 3; // minus 3, since you want 3 displayed at a time.
instead of using marginLeft I would wrap all of these inside of a wrapper and set the positions to absolute. Then animate using "left" property or "right". There's a lot of code required to do this, well not MUCH, but since there are many plugins, I think you'd be better off searching jquery.com for a plugin and look for examples on how to do this. marginLeft is just not the way to go, since it can cause many viewing problems depending on what version of browser you are using.

Categories

Resources