I want to toggle functions using the jQuery waypoint function, how can I combine these pieces of code to make that happen? (I would be happy with alternative solutions too).
I want to combine this.....
$('#pageborder').waypoint(function(direction) {
//do something here
}, { offset: 'bottom-in-view' });
With this......
.toggle(function(){
$('.play', this).removeClass('pausing');
$('.play', this).addClass('playing');
}, function(){
$('.play', this).addClass('pausing');
$('.play', this).removeClass('playing');
});
The end result should be functions getting toggled when the way point is reached.
More info on the JQuery Waypoint plugin here: http://imakewebthings.com/jquery-waypoints/#doc-waypoint
Here is an example of using the waypoint plugin to do something when the waypoint is reached. In my example I am showing and hiding something based on if the user is scrolling up or down:
Demo: http://jsfiddle.net/lucuma/pTjta/
$(document).ready(function () {
$('.container div:eq(1)').waypoint(function (direction) {
if (direction == 'down') $('.toggleme').show();
else {
$('.toggleme').hide();
}
}, {
offset: $.waypoints('viewportHeight') / 2
});
});
E.B.D., I see you have something working.
If you wanted a slightly more concise toggle action, then you might consider the following :
var $next_btn_containers = $('.next_btn_container, .next_btn_container_static');
$('#pageborder').waypoint(function(dir) {
$next_btn_containers
.toggleClass('next_btn_container_static', dir == 'down')
.toggleClass('next_btn_container', dir == 'up');
}, { offset: 'bottom-in-view' });
By pre-selecting and remembering all members of both classes, execution will be faster - particularly in a large DOM.
The original selector may well simplify, depending on how the elements are initialized.
With a little more thought (and appropriate adjustment of style-sheet directives), then you may be able to simplify things even further by toggling a single "static" class :
var $next_btn_containers = $('.next_btn_container');
$('#pageborder').waypoint(function(dir) {
$next_btn_containers.toggleClass('static', dir == 'down')
}, { offset: 'bottom-in-view' });
.next_btn_container would thus remain a reliable selector (for other purposes), regardless of the statc/non-static state of the element(s).
Note: Unlike the first version (and your own code), this will not handle two sets of elements toggling in anti-phase, if that's what you have.
I used this code to make it work, thanks to lucuma for pointing me in the right direction!
$('#pageborder').waypoint(function(direction) {
if (direction == 'down') $('.next_btn_container').removeClass('next_btn_container').addClass('next_btn_container_static');
else {
$('.next_btn_container_static').removeClass('next_btn_container_static').addClass('next_btn_container');
}
}, { offset: 'bottom-in-view' });
Related
I'm using a jQuery script from here.
So far it works great, but the only thing that I'm wondering about is how to go about getting a comma into one of the values.
Since the number animate up when you scroll, it's tricky to get the browser to check what the integer is after the fact. I've read a bunch of posts that will add a comma (in this case I'm trying to get 100,000) but it won't work since the browser can't see that integer initially (starts at 0).
Here's the script that I'm using to invoke the animaition when you scroll down the page:
$(function () {
var fx = function fx() {
$(".stat-number").each(function (i, el) {
var data = parseInt(this.dataset.n, 10);
var props = {
"from": {
"count": 0
},
"to": {
"count": data
}
};
$(props.from).animate(props.to, {
duration: 500 * 1,
step: function (now, fx) {
$(el).text(Math.ceil(now));
},
complete:function() {
if (el.dataset.sym !== undefined) {
el.textContent = el.textContent.concat(el.dataset.sym)
}
}
});
});
};
var reset = function reset() {
console.log($(this).scrollTop())
if ($(this).scrollTop() > 950) {
$(this).off("scroll");
fx()
}
};
$(window).on("scroll", reset);
});
It takes the value from the data attribute data-n in the HTML and then works it's magic from there. If I have 100,000 in the data-n attribute then it cuts it short at 100 when the numbers animate.
So yeah, I'm not sure if I need to amend this script so it can accommodate for the comma in the data attribute or if there is something else I might need to do after the fact?
Ok, so after digging through it a bit more, I was able to come up with a solution.
I found this:
$.fn.digits = function(){
return this.each(function(){
$(this).text( $(this).text().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,") );
})
}
and then added an addtional class in my HTML.
I then hooked into the complete:function and added:
$(".class-i-added").digits();
to the end of the animation.
Overall, that appears to provide the result that I am looking for.
Since I only need to attribute it to one number (so far) it works as it should.
My name is Adam, I'm new to Stack Exchange, but have found this site very useful for many past problems I have had.
I'm having a problem with a jquery function and thought I'd seek advice here. I have a pretty decent knowledge of html & css, a little of php, but virtually none of javascript or jquery.
I'm currently working on a site that uses specific html tags to enable dynamic content as php isn't permitted. Javascript is however so I've been looking it. I don't have a live example to show you here as I can only preview the design from within my account, however I have pasted the script below.
I wanted to create a responsive design, fluid down to mobile. Following recent design trends, I wanted to create 'Slide in/out' style menus from the side of the screen (think Facebook Mobile, Dolphin Browser). After viewing some examples, I wrote a function which altered the CSS, moving the main div#site template to the right, revealing the left menu. Everything was ok and it worked fine.
Today I decided it would be nice to have 2 slide out menus, one on the left, the other, on the right.
I added to the function what I thought was going to work, and it sort of does.
I have a button (with class .open-sidebar-right) to slide the main site (div#site) to the left, revealing the right hand menu. I can then click either the same button or the div#site to close the menu.
The problem occurs when I click on the left button. The left menu opens and closes absolutely perfectly, however it renders the right button totally useless and doesn't function at all.
I've tried writing it as two separate functions, using one variable for both menus with different values, and it always renders the right button useless after using the left button.
As I mentioned earlier, I have virtually no knowledge of Javascript or jQuery, so it's probably poorly coded, but I can't understand why this wouldn't work.
If anyone has any advice or suggestions I would really appreciate it.
Thanks in advance, Adam.
jQuery(function () {
var sidebarleft;
var sidebarright;
// ------------
// Left sidebar
jQuery(".open-sidebar-left").click(function () {
if (!sidebarleft) {
jQuery("#site").css({
'left':'50%',
});
sidebarleft = true;
return false;
} else {
jQuery("#site").css({
'left':'0%',
});
sidebarleft = false;
return false;
}
});
// ------------
// Right sidebar
jQuery(".open-sidebar-right").click(function () {
if (!sidebarright) {
jQuery("#site").css({
'right':'50%',
});
sidebarright = true;
return false;
} else {
jQuery("#site").css({
'right':'0%',
});
sidebarright = false;
return false;
}
});
// ----------------------------------
// Close sidebars by clicking on site
jQuery("#site").click(function () {
if (sidebarleft) {
jQuery("#site").css({
'left':'0%',
});
sidebarleft = false;
return false;
} else if (sidebarright) {
jQuery("#site").css({
'right':'0%',
});
sidebarright = false;
return false;
}
});
});
Adam,
#zgood says your code is good, but I thought I'd point out a few errors and make some suggestions which may solve your problem:
$(document).ready(function(){ // in the jQuery doc, they don't suggest you use $(<func>)
var sidebarleft = false, // sidebarleft and sidebarright has to be equal to something
sidebarright = false; // either true or false (I would use false since you're testing false in your conditional
$(".open-sidebar-left").click(function() {
if( !sidebarleft ) {
$("#site").css({
left: '50%' // remove the comma, and do not put quotes around single-word identifiers
});
sidebarleft = true;
return false;
} else {
$("#site").css({
left: '0'
});
sidebarleft = false;
return false;
}
});
$(".open-sidebar-right").click(function() {
if( !sidebarright ) {
$("#site").css({
right: '50%' // remove the comma, and do not put quotes around single-word identifiers
});
sidebarright = true;
return false;
} else {
$("#site").css({
right: '0'
});
sidebarright = false;
return false;
}
});
});
So as you can see in the comments in the code above,
jQuery says it's valid, but not suggested that you use jQuery(function(){}); so query the document element then test for ready, then call a function
sidebarright and sidebarleft were undefined (neither true or false) so your
if statements don't make sense.
In the css() declaration, you shouldn't put a comma on the last element. Only put commas if there are more than one element.
I would also suggest using animate() instead of css(), and also (if you're using Chrome) use the inspector and (if you're using Firefox) use FireBug to test for any errors in your javascript code. Hope this helps.
Your code is right, the problem seems to be a CSS issue.
When you click your left button your click event is adding an inline style to your #site div like so:
<div id="site" style="left:50%;">
Then when you click your right button your code appends the new style to your #site div like so:
<div id="site" style="left: 0%; right: 50%;">
See the problem?
To fix this you must do two things. Since you didn't post your CSS, I don't know how you have your #site styled, but remove any left or right style from your #site style declaration.
Next update your jQuery code to remove any previous inline styles like so:
// ------------
// Left sidebar
jQuery(".open-sidebar-left").click(function () {
jQuery("#site").removeAttr('style');
if (!sidebarleft) {
jQuery("#site").css({
'left':'50%',
});
sidebarleft = true;
return false;
} else {
jQuery("#site").css({
'left':'0%',
});
sidebarleft = false;
return false;
}
});
AND
jQuery(".open-sidebar-right").click(function () {
jQuery("#site").removeAttr('style');
if (!sidebarright) {
jQuery("#site").css({
'right':'50%',
});
sidebarright = true;
return false;
} else {
jQuery("#site").css({
'right':'0%',
});
sidebarright = false;
return false;
}
});
removeAttr is your friend here. Also you may want to use an animate instead of just changing the css values, but thats your call
jQuery .animate()
Let's say I have the following code:
$(function () {
$(".buy-it-now.ribbon").click(function () {
$(".bid-to-beat.ribbon.active").removeClass("active");
$(".bid-to-beat.ribbon").addClass("inactive");
$(".buy-it-now.ribbon.inactive").removeClass("inactive");
$(".buy-it-now.ribbon").addClass("active");
$(".bid-now").hide();
$(".buy-now").show();
$(".add-to-cart").hide();
})
$(".bid-to-beat.ribbon").click(function () {
$(".buy-it-now.ribbon.active").removeClass("active");
$(".buy-it-now.ribbon").addClass("inactive");
$(".bid-to-beat.ribbon").removeClass("inactive");
$(".bid-to-beat.ribbon").addClass("active");
$(".buy-now").hide();
$(".bid-now").show();
$(".add-to-cart").show();
});
});
It is a simple function that allows for multiple UI related things to happen on the front-end of a site I am working on. I am fairly (very) new to jQuery and JavaScript in general and am learning about refactoring and making my code more condensed now. The way I currently write code is sort of line per thought I have. So my question is how would an experienced developer write this same code? Or rather, how could I refactor this code?
Try the following:
$(function () {
var $handlers = $('.buy-it-now.ribbon, .bid-to-beat.ribbon');
$handlers.click(function() {
$handlers.toggleClass("active inactive");
var $elements = $(".bid-now, .add-to-cart"),
$buyElement = $(".buy-now");
if($(this).is('.buy-it-now.ribbon')) {
$elements.hide();
$buyElement.show();
} else {
$elements.show();
$buyElement.hide();
}
});
});
This question would be better suited for codereview, but yes it can be condensed a little using method chaining.
$(function () {
$(".buy-it-now.ribbon").click(function () {
$(".bid-to-beat.ribbon").removeClass("active").addClass("inactive");
$(".buy-it-now.ribbon").removeClass("inactive").addClass("active");
$(".bid-now").hide();
$(".buy-now").show();
$(".add-to-cart").hide();
})
$(".bid-to-beat.ribbon").click(function () {
$(".buy-it-now.ribbon").removeClass("active").addClass("inactive");
$(".bid-to-beat.ribbon").removeClass("inactive").addClass("active");
$(".buy-now").hide();
$(".bid-now").show();
$(".add-to-cart").show();
});
});
You could condense it further by pre selecting the elements and caching them in variables before the click events as long as no elements are added or removed during the life of the page.
As your code it is you can combine some of the selectors into a single line. And also because your elements looks to be static you can cache them into a variable and use them later as it reduces the number of times a element is looked up in the DOM reducing the accessing time..
Also you can limit the scope of these variables or selectors by encasing them in an object or a closure..
Maybe something in these lines..
$(function () {
cart.init();
});
var cart = {
elems : {
$buyRibbon : null,
$bidRibbon : null,
$bidNow: null,
$buyNow: null,
$addToCart: null
},
events : {
},
init : function() {
this.elems.$buyRibbon = $(".buy-it-now.ribbon");
this.elems.$bidRibbon = $(".bid-to-beat.ribbon");
this.elems.$bidNow = $(".bid-now") ;
this.elems.$buyNow = $(".buy-now") ;
this.elems.$addToCart = $(".add-to-cart") ;
this.events.buyClick();
this.events.bidClick();
}
};
cart.events.buyClick = function() {
cart.elems.$buyRibbon.on('click', function(){
cart.elems.$bidRibbon.removeClass('active').addClass('inactive');
cart.elems.$buyRibbon.removeClass('inactive').addClass('active');
cart.elems.$bidNow.hide();
cart.elems.$buyNow.show();
cart.elems.$addToCart.hide();
});
}
cart.events.bidClick = function() {
cart.elems.$bidRibbon.on('click', function(){
cart.elems.$buyRibbon.removeClass('active').addClass('inactive');
cart.elems.$bidRibbon.removeClass('inactive').addClass('active');
cart.elems.$bidNow.show();
cart.elems.$buyNow.hide();
cart.elems.$addToCart.show();
});
}
So basically in here your whole cart is a object ..And the cart has different properties which are related to this.. You follow the principles of object oriented programming here..
Using closures I heard gives you better design limiting the scope of your code..
Might I suggest something like this:
$(function () {
var buyNowButton = $('buy-it-now.ribbon'),
bidToBeatButton = $('.bid-to-beat.ribbon'),
buyNowEls = $('.buy-now'),
bidToBeatEls = $('.bid-now,.add-to-cart');
var toggleButtons = function(showBuyNow){
buyNowButton.toggleClass('active', showBuyNow);
bidToBeatButton.toggleClass('active', !showBuyNow);
buyNowEls.toggle(showBuyNow);
bidToBeatEls.toggle(!showBuyNow);
}
buyNowButton.click(function(){ toggleButtons(true) });
bidToBeatButton.click(function(){ toggleButtons(false) });
});
You could save a some lines by removing the selectors at the start and just do the selection in place, if the saved space would be more important than the minor performance hit. Then it would look like this:
$(function () {
var toggleButtons = function(showBuyNow){
$('buy-it-now.ribbon').toggleClass('active', showBuyNow);
$('.bid-to-beat.ribbon').toggleClass('active', !showBuyNow);
$('.buy-now').toggle(showBuyNow);
$('.bid-now,.add-to-cart').toggle(!showBuyNow);
}
$('buy-it-now.ribbon').click(function(){ toggleButtons(true) });
$('.bid-to-beat.ribbon').click(function(){ toggleButtons(false) });
});
The first version selects the elements once and holds them in memory; the second selects them each time the button is clicked. Both solve the problem I believe would occur with the selected answer where clicking the same button twice would cause the .active and .inactive classes to get out of sync with the shown/hidden elements.
I'm using JQuery UI - Selectable. I want to deselect the element if it has been pressed and it has already been selected (toggle)
Could you help me to add this functionality please !
Because of all the class callbacks, you're not going to do much better than this:
$(function () {
$("#selectable").selectable({
selected: function (event, ui) {
if ($(ui.selected).hasClass('click-selected')) {
$(ui.selected).removeClass('ui-selected click-selected');
} else {
$(ui.selected).addClass('click-selected');
}
},
unselected: function (event, ui) {
$(ui.unselected).removeClass('click-selected');
}
});
});
You already have that functionality with jQuery UI selectable if you're holding down the Ctrl key while clicking.
If you really need that as the default functionality, you don't need to use selectable, you can do it just as a simple onclick handler, like what nolabel suggested.
Or... you might as well edit jquery.ui.selectable.js and add an option which does just what you need. Shouldn't be too hard, there are 4 places where event.metaKey is checked, make sure if your option is set, just run the codepaths as if event.metaKey was always true.
As the selectables could use some more customisation, you could also make a feature request for jQuery UI developers to include it in the next official version.
You have to inject two simple elements in the code to achieve what you want. This just inverts the metaKey boolean, whenever you need inverted/toggle functionality.
options: {
appendTo: 'body',
autoRefresh: true,
distance: 0,
filter: '*',
tolerance: 'touch',
inverted: false /* <= FIRST*/
},
_mouseStart: function(event) {
var self = this;
this.opos = [event.pageX, event.pageY];
if (this.options.disabled)
return;
var options = this.options;
if (options.inverted) /* <= SECOND*/
event.metaKey = !event.metaKey; /* <= SECOND*/
I'm using the tipsy plugin for jQuery. Whenever I try to call tipsy with both a manual trigger and delayIn, the delayIn doesn't seem to work:
$('.interest').tipsy({trigger:'manual', gravity: 'n', html: true, delayIn: 3000});
Any ideas as to why?
The short answer is that once you turn on trigger:'manual', tipsy doesn't take care of delayIn any more. Your best bet might be to just have your manual trigger (wherever you do ...tipsy('show')) do a delay instead:
setTimeout("\$('#link').tipsy('show');",3000);
You could also look at the tipsy source to see that they have a slightly more elegant version that you could work from:
function enter() {
var tipsy = get(this);
tipsy.hoverState = 'in';
if (options.delayIn == 0) {
tipsy.show();
} else {
setTimeout(function() { if (tipsy.hoverState == 'in') tipsy.show(); }, options.delayIn);
}
}