How to run the same function for different IDs separately - javascript

I'm trying to animate multiple progress/loading bars. The code below works how I want it to and I could just copy and paste then replace the ID name but that seems unnecessarily long. What's an efficient way to use my jquery code with different types of IDs (eg: #bar-x, #bar-y, #bar-z)? I've tried separating with commas like below
$(function() {
var $stat = $('#bar-x, #bar-y, #bar-z');
$stat.waypoint(function() {
$stat.css({
animation: "loading 1s linear",
opacity: "1"
});
}, { offset: '95%' });
});
but then it runs all the animations at the same time when the first object reaches the requirement instead of when each individual object reaches the said requirement.

You could always just wrap it in a function and use it like this
function myAnimation(selector){
selector.waypoint(function() {
selector.css({
animation: "loading 1s linear",
opacity: "1"
});
}, { offset: '95%' });
}
myAnimation($('#bar-y'));
This way you'd be able to call on your animation with any kind of selector repeatedly and re-usable fashion.
I'd suggest reading up on some functional programming.

After looking at Waypoints, it seems your issue comes from using the $stat object inside your callback function:
...
$stat.css({
animation: "loading 1s linear",
opacity: "1"
});
...
When the requirement for one of the waypoints is reached, it will call your .css animation on ALL of the elements that $stat contains. What you need is to make it a bit more dynamic and use this.element in place of $stat (or similar, depending on the version of Waypoints you're using).

It seems that the other answers aren't acknowledging the queue-ing aspect of your question so I figured I'd touch on that. In such a case, you could loop through the elements and attach the animation one second apart to each one.
Using the code below, all of the setTimeout()s will be instantiated at the same time, however the first will be for 0ms, the second 1000ms, the third 2000ms, so on and so forth.
var $stat = $('.bar'); //add class "bar" to each item you want to be included
var msDelay = 1000;
$stat.each(function(index) {
setTimeout(() => loadNext($(this)), msDelay * index);
});
function loadNext($elem) {
$elem.waypoint(function() {
$elem.css({
animation: "loading 1s linear",
opacity: "1"
});
}, {
offset: '95%'
});
};
Demo
var $stat = $('.bar');
var msDelay = 1000;
$stat.each(function(index) {
setTimeout(() => loadNext($(this)), msDelay * index);
});
function loadNext($elem) {
$elem.css({ opacity: "1" });
};
.bar {
opacity: 0;
padding: 20px;
margin: 5px;
background-color: red;
transition: opacity 1s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>

var divId = "#bar-x";
function animate (var divId)
{
var $stat = $(divId);
$stat.waypoint(function() {
$stat.css({
animation: "loading 1s linear",
opacity: "1"
});
}, { offset: '95%' });
}

Related

how to know opacity value using javascript?

I am using transition: opacity 5s; property. I want to show different alert or console message when my opacity value is 0.4 or 0.6 or .2 . on button click I am doing transition but I want to know opacity progress so that i will show those message ?
is there any way to do this
var btn = document.querySelector("button");
var par = document.querySelector("#parId");
btn.addEventListener("click", (e) => {
par.classList.add("removed");
});
par.addEventListener("transitionend", () => {
par.remove();
});
#parId {
transition: opacity 5s;
}
.removed {
opacity: 0;
}
we are getting transitionend callback if there any progress callback where I will check opacity value ?
There is no event that can be listened to to give what you want - unless you are going to use a linear transition. In that case you can carve your changes of opacity up into 0.2s slots, changing opacity on transitionend to the next value down - 0.8, 0.6 etc.
Your code however takes the default for the transition-timing-function property which is ease - not linear - so transitionend is of no use to you.
This snippet polls the opacity changes every tenth of a second and writes the current opacity to the console so you can see what is happening.
A couple of points: you will have to check for when the opacity goes just less than one of your break points, you are unlikely every to hit it just at exactly 0.6s or whatever; also notice that the console carries on being written to after the element has totally disappeared. The timing will not be exact, things are happening asynchronously.
<style>
#parId {
transition: opacity 5s;
width: 50vw;
height: 50vh;
background: blue;
opacity: 1;
display: inline-block;
}
.removed {
opacity: 0;
}
</style>
<div id="parId"></div>
<button>Click me</div>
<script>
var btn = document.querySelector("button");
var par = document.querySelector("#parId");
btn.addEventListener("click", (e) => {
let interval = setInterval(function () {
const opacity = window.getComputedStyle(par).opacity
console.log(opacity);
if (opacity == 0) {clearInterval(interval);}
}, 100);
par.style.opacity = 0;
});
</script>
You could potentially check periodically like this, although your interval will need to be at least the speed of the opacity animation or be quicker than it to catch the values.
var par = document.querySelector("#parId");
setInterval(function() {
console.log(window.getComputedStyle(par).opacity);
}, 100)
#parId{
opacity: 0.2;
transition: opacity 3s ease-in-out;
}
#parId:hover {
opacity: 1;
}
<div id="parId">
test
</div>
Take a look in this example
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/animationend_event
You could define your animation stages as diferent ranimations on css then call them in chain via javascript. Before, you must set an event listener for the animationend event, and every time the event is fired you check the #parId opacity.
You could do it.with jQuery to, totaly in javascript

Transition Opacity w/javascript not working

I want to fadein a component after ajax call completes and jquery has rebuilt DOM.
I have this setup:
index.html:
<head>
<style>
body {
opacity: 0;
transition: opacity 2s;
}
</style>
</head>
<body onload="document.body.style.opacity='1'">
<div class="content">
<!-- Markup for content -->
</div>
</body>
main.css
.content {
opacity: 0;
transition: opacity 6s;
transition: opacity 2s;
-webkit-transition: opacity 6s;
-moz-transition: opacity 6s;
}
main.js
$(document).ready(function () {
const contentEl = document.querySelector(".content");
$(".submit").on("click", async function (e) {
e.preventDefault();
console.log(contentEl.style.opacity);
if (contentEl.style.opacity == 1) {
contentEl.style.opacity = 0;
console.log("Style opacity is in if and = %s", contentEl.style.opacity);
}
// Do Ajax and update DOM via jQuery
contentEl.style.opacity = 1;
}
The first time thru .content fades in as expected as well as fade in of whole page on initial render. However subsequent times thru there is no transition effect. Logging shows that I am changing style.opacity from 1 -> 0 and back to 1 after initial iteration. Any CSS guru's versed in CSS's dark secrets input advice appreciated.
$(document).ready(function () {
const contentEl = document.querySelector(".content");
contentEl.style.opacity = 1; // Define initial opacity (starting val)
$(".submit").on("click", async function (e) {
e.preventDefault();
contentEl.style.opacity = 0; // on click set opacity to 0?
FadeIn(); // Let's Fade from 0 to 1!
});
let FadeIn = () => { // Function
if (contentEl.style.opacity < 1) { // If opacity doesn't equal 1
contentEl.style.opacity += 0.2; // Let's add 0.2!
setTimeout(FadeIn(), 300); // Hell let's repeat that more 300ms
}
}; // Once we equal 1 we should be done
});
I don't play with the JQuery like that, I much rather too use CSS entirely for the animation process of these types of things, it's cleaner (less jitter). I'm assuming this is what you're sort of after though, a simple set value and slowly loop till finished. Button will start out 1 opacity, when clicked jump to 0 and slowly climb its way back up to 1.

Is it possible to restore an element to it's previous position without passing the position as a parameter?

The following function takes an options parameter and animates the element to a particular amount of pixels based on a startValue:
options: {
property: 'right',
startValue: '-250px',
amount: '250px'
},
function (options) {
const $el = $(this.el)
$el.click(() => {
const startValue = $el.parent().css(slide.property)
const calcValue = parseInt(startValue, 10) + parseInt(slide.amount, 10)
if (startValue === slide.startValue) {
$el.parent().animate({ [slide.property]: calcValue }, 200)
} else {
$el.parent().animate({ [slide.property]: slide.startValue }, 200)
}
})
}
But I'm wondering, is it possible to accomplish the same without having to provide the startValue to the function? (e.g if the initial value of right was 0 then restore it to 0 the second time you click the element.)
You can take advantage of the fact that .animate() is adding an inline style attribute when it is called. So if you want to restore an element back to the right value specified in your CSS, you can call .removeAttr("style"). To get the animated effect, you would have to include a transition property in your CSS.
For example, check out this working fiddle: https://jsfiddle.net/hr0cxax2/1/
$("#slideButton").on("click", function() {
$("div").animate({right:"-=50px"}, 200);
});
$("#restoreButton").on("click", function() {
$("div").removeAttr("style");
});
div {
height: 50px;
width: 50px;
top: 20px;
right: 300px;
background-color: red;
position: fixed;
-webkit-transition: right 0.2s;
-moz-transition: right 0.2s;
transition: right 0.2s;
}
Otherwise, as far as I know, you would need to get and save the original right value before .animate() is called.

Loop through divs and toggle class if another class exists

I want to toggle a class (and make the text blink using an interval) if another class is found.
CSS
.flash {
color: #DC4900;
}
HTML
<div class="text notify">Flash</div>
<div class="text notify">Flash</div>
<div class="text">Don't Flash</div>
JS
$(document).ready(function() {
$('.text').each(function() {
if ($(this).hasClass('notify')) {
setInterval(function() {
$(this).toggleClass('flash');
}, 1000);
}
});
});
https://jsfiddle.net/s9dv9qv3/
The interval is not working like it should. It should be adding the flash class to the text if the class notify is found.
Inside of the setInterval callback, this refers to the window object.
To work around this, one option is to capture a reference to this outside of the callback:
Example Here
$('.text.notify').each(function() {
var self = this;
setInterval(function() {
$(self).toggleClass('flash');
}, 1000);
});
I also removed the check for the notify class since you can just select those elements directly.
Alternatively, you could also just use the .bind() method to set the value of this:
Example Here
$('.text.notify').each(function() {
setInterval(function() {
$(this).toggleClass('flash');
}.bind(this), 1000);
});
As a side note, since you're toggling the class on all of the elements at the same time, you could just use:
setInterval(function() {
$('.text.notify').toggleClass('flash');
}, 1000);
If you want to set a delay, you could add a timeout based on the current index of the .each() loop:
Example Here
$('.text.notify').each(function(i) {
var self = this;
setTimeout(function() {
setInterval(function() {
$(self).toggleClass('flash');
}, 1000);
}, 1000 * i);
});
Lastly, you can avoid jQuery completely and use an infinite CSS3 animation:
.text.notify {
animation: flash 2s infinite;
}
#keyframes flash {
0%, 49% {
color: #000;
}
50%, 100% {
color: #DC4900;
}
}
<div class="text notify">Flash</div>
<div class="text notify">Flash</div>
<div class="text notify">Flash</div>
<div class="text notify">Flash</div>
<div class="text">Don't Flash</div>
You can do it using following code and css3 easily:
$( document ).ready(function() {
$('.text.notify').toggleClass('flash');
});
Css3:
.flash {
color: #DC4900;
animation: flasher 1s linear 2;
}
#keyframes flasher {
50% { opacity: 0.0; }
}
Check the fiddle here.
Do this instead:
$( document ).ready(function() {
setInterval(function() {
$('.text').each(function(){
if($(this).hasClass('notify')) {
$(this).toggleClass('flash');
}
});
}, 1000);
});
Hey I had the same problem, a have a list of divs all with .d-unit class, some I would set to available others would be pending or sold.
so this function will highlight all the d.units that also have the class of available. If yes then it will add or a remove the 'available-green' class which is how I change the highlight color.
*watch to see if you need period or not when putting in a class name.
function unitd() {
$(".unitd").toggleClass('filter-on');
$('.d-unit.available').each(function() {
var self = this;
if($(self).hasClass('available')) {
$(self).toggleClass( "available-green' );
}
})
}

Angular way to do an Element Directive animation when Object is deleted?

I'm rendering an scoped Array of Objects(payments in this case), and passing each one to a payment Directive like this:
<div id="payable" ng-controller="PaymentsController">
<payment ng-repeat="payment in payments" data="payment" class="payment"></payment>
</div>
This works really well! So when I delete an element from the scoped Array from the controller like this:
app.controller('PaymentsController', function($scope) {
//The Payments Array(each object passed to a Directive)
$scope.payments = [ { id: 1, amount: 10 }, { id: 2, amount: 15 } ];
$scope.deletePayment = function(index) {
//This deletes the Array Element and removes associated
//Directive template from the DOM
$scope.payments.splice(index, 1);
}
});
The CSS (uses compass mixins for simplicity)
.payment.ng-enter {
#include transition(all 2s ease-out);
opacity: 0;
}
.payment.ng-enter-active {
opacity: 1;
}
.payment.ng-leave {
#include transition(all 2s ease-out);
}
.payment.ng-leave-active {
opacity: 0;
}
Again, the above works as expected, I delete an element from the payments Array and the directive-template/view corresponding to the deleted Array element is removed from the DOM, This is PERFECT, except for the fact it's removed instantly!
EDIT:
The reason the animations like fadeOut don't work and the result is that the ( < payment > ) is removed instantly(after a specified time in the CSS) is that the animation is acting over the ( < payment >) custom tag, which is just a wrapper for the actual element.
Directive JS definition:
(function() {
var app = angular.module('paymentDirectives', []);
app.directive('payment', function() {
return {
restrict: 'E',
scope: {
payment: '=data'
},
templateUrl: 'partials/payment.html'
};
});
})();
The animation should act on the template referenced/wrapped by the directive custom tag( < payment > )
partials/payment.html
<div class="a-payment">
<div class="content">
<p>
<label>{{payment.amount}}</label>
</p>
</div>
</div>
In this case it would be the div with class="a-payment" of course and when the animation is complete it should then remove the payment tag element
What is the Angular way(for the latest version) to do an animation for this case(ie. Element Directive is removed from the DOM)?
Thank you very much in advance, and let me know if you need more from the code I'm using.
This is likely to do with the fact that most custom tags, such as your <payment>, are display: inline; by default.
You should set their style to be display: block in the CSS/SASS.
You can do this in many ways, for example, you can create a class that will trigger the CSS animation, and before deleting the object, you first assign it that class. Here's how:
var deleteAnimDuration = 1000; // let's use one second for our example
$scope.deletePayment = function(index) {
//This deletes the Array Element and removes associated
//Directive template from the DOM
$scope.payments[index].deleteAnim = true; // or whatever property makes sense to you
$timeout(function(){
$scope.payments.splice(index, 1);
}, deleteAnimDuration);
}
Then on the directive, you can use ng-class:
<payment
ng-repeat="payment in payments"
data="payment"
ng-class="{deleting: payment.deleteAnim}">
</payment>
Then in the CSS:
payment.deleting {
transition: opacity 1s linear; // again, one second
opacity: 0;
}
Since this sample animation (opacity fade) will run for one second, you need to set deleteAnimDuration for the $timeout to one second (1000 in milliseconds).
So, what happens:
you click delete on a payment
it sets payment.deleteAnim to true, which assigns the deleting class to the element
the timeout for the animation duration is set
animation starts
animation ends
element removed from the DOM
This is the concept from the DOM standpoint:
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', function(e) {
e.target.className = 'deleting';
deleteEl(this)
})
}
function deleteEl(el) {
setTimeout(function() {
el.parentElement.removeChild(el);
}, 1000);
}
.deleting {
transition: opacity 1s linear;
opacity: 0;
}
div {
width: 50px;
height: 50px;
display: inline-block;
background: #eee;
}
<div>Click me</div>
<div>Click me</div>
<div>Click me</div>
<div>Click me</div>
Of course, this can work with JS animations as well.
Load angular-animate.min.js in your HTML.
Add ngAnimate into your module dependencies.
Add a class to your payment directive element: e.g. <payment class="my-animation" ...></payment>.
Add the following CSS (referencing your class in step 3):
.my-animation.ng-leave { opacity: 1; transition: opacity 300ms linear; }
.my-animation.ng-leave.ng-leave-active { opacity: 0; transition: opacity 300ms linear; }
Celebrate

Categories

Resources