Adding comma to jQuery animated numbers - javascript

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.

Related

jQuery store .each() .text() for truncation possible?

I have asked a similar question previously, but didn't give enough context. As a result I received an excellent, technically-correct answer that didn't solve my issue.
I've also looked around on Stack but don't know enough about jQuery to find my answer.
I need to truncate multi-line text with jQuery. The code needs to add/remove text as well when the browser window expands and contracts. So from my minimal understanding the code needs to store the text before truncating it so that it can add text back in when the browser window is expanded.
Initially this piece of code solved my problem:
$(function () {
var initial = $('.js-text').text();
$('.js-text').text(initial);
while($('.js-text').outerHeight() > $('.js-text-truncator').height()) {
$('.js-text').text(function(index, text) {
return text.replace(/\W*\s(\S)*$/, '...');
});
}
$(window).resize(function() {
$('.js-text').text(initial);
while($('.js-text').outerHeight() > $('.js-text-truncator').height()) {
$('.js-text').text(function(index, text) {
return text.replace(/\W*\s(\S)*$/, '...');
});
}
});
});
This code no longer cuts it as when I use these .js classes more than once on a single page all the text is stored together and then spat out whenever the classes are being used.
Here is a jsFiddle of the the issue:
http://jsfiddle.net/1ddxtpke/
I need to store each .js-text text separately, so that I can use this jQuery snippet across a large project and have all instances of truncated text fed back into the DOM if a user were to expand their browser window size.
Is this possible? If so, how would I do it?
Thanks in advance for tackling my question. I hope I have been specific enough in what I'm looking for.
There are several ways how to do this. You can store it in an array:
var initialValues = [];
// Save the initial data
$('.js-text').each(function () {
initialValues.push($(this).text());
});
// On start
while($('.js-text').outerHeight() > $('.js-text-truncator').height()) {
$('.js-text').text(function(index, text) {
return text.replace(/\W*\s(\S)*$/, '...');
});
}
// When the window gets resized
$(window).resize(function() {
$('.js-text').text(function () { return initialValues[$('.js-text').index($(this))]; });
while($('.js-text').outerHeight() > $('.js-text-truncator').height()) {
$('.js-text').text(function(index, text) {
return text.replace(/\W*\s(\S)*$/, '...');
});
}
});
It has a catch though - the .js-text elements can't be erased or moved about, because it'll destroy the ordering. That'd require another function for order resetting in case something changes.
I haven't tested it, but in principle it should work this way.
EDIT: Okay, I reworked it a bit and here's the result:
var initialValues = [];
// Save the initial data
$('.js-text').each(function () {
initialValues.push($(this).text());
while ($(this).outerHeight() > $(this).parent().height()) {
$(this).text($(this).text().replace(/\W*\s(\S)*$/, '...'));
}
});
// When the window gets resized
$(window).resize(function() {
$('.js-text').each(function (index) {
$(this).text(initialValues[index]);
while ($(this).outerHeight() > $(this).parent().height()) {
$(this).text($(this).text().replace(/\W*\s(\S)*$/, '...'));
}
});
});
I see 2 ways of doing this :
1) Storing the full text as an attribute when needed. With this your text will stay with your div and can be retrived on expanding with a simple .attr .
2) Storing the text in an array and storing the index as an attribute on the div. This way is probably much more efficient than the previous one as I'm not sure what is the max length of a value of an attribute.
your function one syntax error
var initialValues = [];
// Save the initial data
$('.js-text').each(function () {
initialValues.push($(this).text());
});
// On start
while ($('.js-text').outerHeight() > $('.js-text-truncator').height()) {
$('.js-text').text(function (index, text) {
return text.replace(/\W*\s(\S)*$/, '...');
});
}
// When the window gets resized
$(window).resize(function() {
$('.js-text').text(function () { return initialValues[$('.js-text').index($(this))]; });
while($('.js-text').outerHeight() > $('.js-text-truncator').height()) {
$('.js-text').text(function(index, text) {
return text.replace(/\W*\s(\S)*$/, '...');
});
}
});
Demo Link http://jsfiddle.net/1ddxtpke/2/

jQuery fade in and fade out loop issue

I am making a results screen which toggles between showing the user their best time/score and their latest time/score. I found a solution using this site but after leaving the website open for a few hours I saw that the timings had gone out of sync. I know that this is hard to test so I thought I would see if any experts on here could help me to optimize or fix my code.
CODEPEN
JSFIDDLE
JS
$(document).ready(function() {
setInterval( function() { resultsTransition(); }, 4000);
function resultsTransition() {
$('.latest-transition').fadeOut(500).delay(3500).fadeIn(500).delay(3500);
$('.best-transition').fadeIn(500).delay(3500).fadeOut(500).delay(3500);
}
});
I think your design could be improved (and the out-of-sync problem solved) by simply toggling the opacity of the elements in your resultsTransition method instead of starting a new sequence, which could interfere unpredictably with the interval.
Something like:
var latestTransitionElementVisible = true; //the initial state of your elements
setInterval(resultsTransition, 4000); //note you can just pass the function name
function resultsTransition() {
$('.latest-transition').fadeTo(500, latestTransitionElementVisible ? 0 : 1);
$('.best-transition').fadeTo(500, latestTransitionElementVisible ? 1 : 0);
latestTransitionElementVisible = !latestTransitionElementVisible ;
}
I guess whatever problem/issue you are facing is because of varying animation times .Try the following:
$(document).ready(function() {
setTimeout( function() { resultsTransition(); }, 4000);
function resultsTransition() {
if(!$('.latest-transition').is(':animated') && !$('.best-transition').is(':animated'))
{
$('.latest-transition').fadeOut(500).delay(3500).fadeIn(500).delay(3500);
$('.best-transition').fadeIn(500).delay(3500).fadeOut(500).delay(3500);
setTimeout( function() { resultsTransition(); }, 4000);
}
}
});

Using .style.opacity = using javascript is not working for some reason

I'm new to javascript and jquery and I am trying to make a video's opacity change when I mouseover a li item. I know 'onmouseover' works because I have tested using the same jquery I use to scroll to the top of the page onclick.
The problem seems to be the syntax to check and update the style of the video div is not working. I adapted the code from a lesson on codeacademy and don't see why it work:
window.onload = function () {
// Get the array of the li elements
var vidlink = document.getElementsByClassName('video');
// Get the iframe
var framecss = document.getElementsByClassName('videoplayer1');
// Loop through LI ELEMENTS
for (var i = 0; i < vidlink.length; i++) {
// mouseover function:
vidlink[i].onmouseover = function () {
//this doesn't work:
if (framecss.style.opacity === "0.1") {
framecss.style.opacity = "0.5";
}
};
//onclick function to scroll to the top when clicked:
vidlink[i].onclick = function () {
$("html, body").animate({
scrollTop: 0
}, 600);
};
}
};
Here is a jsfiddle you can see the html and css:
http://jsfiddle.net/m00sh00/CsyJY/11/
It seems like such a simple problem so I'm sorry if I'm missing something obvious.
Any help is much appreciated
Try this:
vidlink[i].onmouseover = function () {
if (framecss[0].style.opacity === "0.1") {
framecss[0].style.opacity = "0.5";
}
};
Or alternatively:
var framecss = document.getElementsByClassName('videoplayer1')[0];
Or, better, give the iframe an id and use document.getElementById().
The getElementsByClassName() function returns a list, not a single element. The list doesn't have a style property. In your case you know the list should have one item in it, which you access via the [0] index.
Or, given that you are using jQuery, you could rewrite it something like this:
$(document).ready(function(){
// Get the iframe
var $framecss = $('.videoplayer1');
$('.video').on({
mouseover: function () {
if ($framecss.css('opacity') < 0.15) {
$framecss.css('opacity', 0.5);
}
},
click: function () {
$("html, body").animate({
scrollTop: 0
}, 600);
}
});
});
Note that I'm testing if the opacity is less than 0.15 because when I tried it out in your fiddle it was returned as 0.10000000149011612 rather than 0.1.
Also, note that the code in your fiddle didn't run, because by default jsfiddle puts your JS in an onload handler (this can be changed from the drop-down on the left) and you then wrapped your code in window.onload = as well. And you hadn't selected jQuery from the other drop-down so .animate() wouldn't work.
Here's an updated fiddle: http://jsfiddle.net/CsyJY/23/

How to toggle function with jquery waypoint

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' });

Refactoring Code

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.

Categories