jquery .fadein .fadeout callback nesting not ordering correctly - javascript

I am trying to nest fadein and fadeout methods in order to get the following effect. I would like the characters in 10 seperate tags to one by one fadeout, change text and then fade in. With what I know about callback functions the following code should achieve that but the effect I am getting now is all the elements change simultaneously and the text change does not wait for the fadeout resulting in the text flashing and then fading out and in. What am I doing wrong!! Here is a simplified version of what I have currently.
HTML/PHP:
<?php
echo '<div onclick="addname(this)">';
for ($i=0; i<10; i++){
echo '<h1 id="temp'.$i.'">Y</h1>';
}
?>
Javascript
function addname(item){
//Other stuff that works fine
hideChar(0);
}
function hideChar(i){
if(i<10){
var tag = "temp" + i;
var x = document.getElementById(tag);
$(x).fadeOut(200, showChar(i));
}
}
function showChar(i){
var tag = "temp" + i;
var x = document.getElementById(tag);
var j = i+1;
$(x).html("X");
$(x).fadeIn(200, hideChar(j));
}

You're not passing your function as the callback properly. When you include the () - the function will be triggered immediately - omit the () to pass it along:
$(x).fadeOut(200, showChar);
The default parameters will be passed along. If you need something other than the default - you'll have to use an anonymous function to call yours:
$(x).fadeOut(200, function() {
showChar(i)
});

Related

Javascript - passing a variable to event handler

Apologies if my problem sounds trivial to JS experts.
I've created an image slider (carousel) and, while loading thumbnails, I'm trying to create a reference to a full-size image, so that when a thumbnail is clicked - the image opens in another div.
The relevant code within window.onload handler is:
for (var i = 0; i < numImages; ++i) {
var image = images[i],
frame = document.createElement('div');
frame.className = 'pictureFrame';
/* some styling skipped */
carousel.insertBefore(frame, image);
frame.appendChild(image);
} /* for */
My first attempt was to add "onclick" at the end of the for loop:
frame.onclick= function () {
var largeImage = document.getElementById('largeImage');
largeImage.style.display = 'block';
largeImage.style.width=200+"px";
largeImage.style.height=200+"px";
var url=largeImage.getAttribute('src');
document.getElementById('slides').style.display = 'block';
document.getElementById("slides").innerHTML="<img src='url' />";
}
However, this may only work with hard-coded ids (e.g. 'largeImage').
Ideally, I need to pass image.src as a parameter but this (frame.onclick= function (image.src)) will not work.
My next thought was to put all logic of getting image.src to a separate function and displaying it with frame.onclick= myFunction;
However, I came over an example:
<input type="button" value="Click me" id="elem">
<script>
elem.onclick = function(event) {
// show event type, element and coordinates of the click
alert(event.type + " at " + event.currentTarget);
alert("Coordinates: " + event.clientX + ":" + event.clientY);
};
</script>
And here it is above me to understand why in this example a handler can accept a parameter.
What would be a correct way of assigning an image to the onclick event? Or is there a better way of turning a thumbnail into href?
While it might not be the best way, you could place the full size image path as a data-attribute on your thumbnail.
<img id="thumbnail" src="thumbnailpath" data-fullSizeImage="fullSizePath">
Then on your onclick, you could access the thumbnail element and get it's data- attribute.
function onClick(event){
var fullSizePath = event.currentTarget.getAttribute("data-fullSizeImage");
//Do whatever you want with fullsizepath
}
Code is untested; but, something like that should work based on my experience.
data attributes are a very flexible custom attribute for developers to use. Essentially you start with "data-" and then append a name to represent the attribute. Here is the documententation link.
You can create a closure (that is, an anonymous function) and register it as an event handler to access variables from outside the event handler inside the event handler itself:
for (var i = 0; i < numImages; ++i) {
/* create element */
element.addEventListener('click', function (event) {
console.log('The index is ' + i);
});
}
However, this will not quite work, since the variable i is changed every time the loop increases it, and closures don't "capture" the current value, only the reference itself, so at the end i will be equal to numImages for each event listener.
If you're using ES6 you can overcome this by using let (or const) to prevent this behavior:
for (let i = 0; i < numImages; ++i) {
/* create element */
element.addEventListener('click', function (event) {
console.log('The index is ' + i);
});
}
If using ES6 is not an option, you can still accomplish this in ES5 and earlier by wrapping the inside of your loop in a function that takes i as a parameter, which makes sure each event handler references different variables, since these parameters are different variables for each iteration:
for (var i = 0; i < numImages; ++i) {
(function (index) {
/* create element */
element.addEventListener('click', function (event) {
console.log('The index is ' + index);
});
})(i); /* pass in i here, which will be assigned to the index parameter */
}

Refresh a DIV content after faded it out

I got X DIV (TopRowRight1, TopRowRight2, TopRowRight3...) , each containing a different Google Geochart generated by a php page : GeochartPerProvince.php?template=X.
function getResult(template){
jQuery.post("GeochartPerProvince.php?template="+template,function( data ) {
jQuery("#TopRowRight"+template).html(data);
});
}
jQuery().ready(function(){
getResult(1);
setInterval("getResult(1)",10000);
getResult(2);
setInterval("getResult(2)",10000);
getResult(3);
setInterval("getResult(3)",10000);
});
jQuery(function () {
var $els = $('div[id^=TopRowRight]'),
i = 0,
len = $els.length;
$els.slice(1).hide();
setInterval(function () {
$els.eq(i).fadeOut(function () {
i = (i + 1) % len
$els.eq(i).fadeIn();
})
}, 5000)
});
Every 5 seconds, i fade out one and fade in the next one. This works perfectly.
For now, the php page in the DIV is refreshed every 10 seconds. This works too.
But what i dream about is that the php page in the DIV is reloaded AFTER the DIV is faded out instead of every 10 seconds. How to do it?
Solved. How it works properly:
function getResult(template){
jQuery.post("GeochartPerProvince.php?template="+template,function( data ) {
jQuery("#TopRowRight"+template).html(data);
});
}
$(document).ready(function(){
getResult(0);
getResult(1);
getResult(2);
//setInterval("getResult(2)",10000); <== keep this piece of code in case of need.
});
$(document).ready(function () {
var $els = $('div[id^=TopRowRight]'),
i = 0,
len = $els.length;
$els.slice(1).hide();
setInterval(function () {
$els.eq(i).fadeOut(function () {
i = (i + 1) % len
getResult(i);
$els.eq(i).fadeIn();
})
}, 10000)
});
You're already using a callback function after the element has been faded out. So why not call your getResult function inside it?
$el.fadeOut(function(){
// stuff
getResult(i)
})
I have a few suggestions and an example code for you to achieve what you need :
Use $ instead of jQuery for easier reading / writing
$(document).ready is the proper start point for dom related functions
If only one div is visible at a time, do not use too many divs. Most of the time one div is enough for alternating / refreshing content. If there is in/out animation or cross-fading, two divs would be needed. (Example below uses two divs)
Avoid using setInterval except you really really need. Logics with setTimeout better handles unexpected delays such $.post may cause.
start with html code something like this:
...
<div class="top-row-right" style="display:block"></div>
<div class="top-row-right" style="display:none"></div>
...
js:
$(document).ready( function() {
var len = 4; // 'I got X DIV..' This is where we put the value of X.
var template = -1;
function refreshChart() {
template = (template + 1) % len;
$.post("GeochartPerProvince.php?template="+template, function(data) {
var offscreenDiv = ('.top-row-right:hidden');
var onscreenDiv = ('.top-row-right:visible');
offScreenDiv.html(data);
onScreenDiv.fadeOut('slow', function() {
offScreenDiv.fadeIn();
setTimeout(refreshChart, 10000);
});
});
}
refreshChart();
});

Jquery fadeIn in callback for fadeOut not lasting

Hope someone can shed some light on this issue for me.... I'm using a setInterval to alternate displaying headlines on a webpage. it fades out the previous one, then in the callback function fades in the new one. it used to work fine, however I separated the callback function from the fadeOut because I wanted to run it initially without a delay, and now I'm getting the initial headline, however when it comes time to change, they fade in for a split second and disappear again.
function processSidebar(data) {
var headlines = $.parseJSON(data);
var sIndex = 0;
function newSidebar(surl, sIndex) {
$(".sidebar").html(headlines[sIndex].date + '<br>' + headlines[sIndex].line + '');
$(".sidebar").fadeIn(400);
}
newSidebar("getme.php?blog=1&headline=1", sIndex);
setInterval(function() {
++sIndex;
if (sIndex == headlines.length) {sIndex = 0}
var surl="getme.php?blog=1&headline=" + headlines[sIndex].index;
$(".sidebar").fadeOut(400,newSidebar(surl,sIndex));
}, 10000); // end setInterval
}; // end processSidebar
jQuery's fadeOut wants a function as the complete argument.
You're giving newSidebar(surl,sIndex), which gets evaluated immediately and returns nothing (but does the whole fadeIn stuff).
You want to use an anonymous function:
$(".sidebar").fadeOut(400,function() { newSidebar(surl,sIndex) });

call function from inside another Ajax function. works with Pure javascript

I have a quite rare problem, or I don't know since I am a beginner :)
I'm creating a DOM tree with ajax, the output is perfect, except that the functions I'm calling does not work. . If I create the same three with pure JavaScript. it actually calls the function. Well quite hard to explain, will show with some code.
function stickers(){
$(document).ready(function() {
$('#add-new-sticker-btn').click(function() {
$.get('xml/data.xml', function(data) {
$('#page-content-wrapper').empty();
$(data).find('car').each(function() {
var $car = $(this);
var sticker = '<div class="sticker">';
sticker += '<div class ="sticker-drag">' + '</div>';
sticker += '<textarea>' + $car.find('product').text() + '</textarea>';
sticker += '<div class="sticker-close">' + '</div>';
$('#page-content-wrapper').append(sticker);
});
});
return false;
});
});
movewrap(); // <!-- this is the function that I'm trying to call.
}
but If I instead write the pure javascript
function stickers(){
var sticker = createElementWithClass('div', 'sticker'),
textArea = document.createElement('textarea');
var stickerDrag = createElementWithClass('div','sticker-drag')
var stickerClose = createElementWithClass('div','sticker-close')
sticker.appendChild(stickerDrag);
sticker.appendChild(textArea);
sticker.appendChild(stickerClose);
document.getElementById('page-content-wrapper').appendChild(sticker);
movewrap();
} // its calling the moveWrap function.
Any ideas ?
Place the call to moveWrap at the end of your AJAX callback. Currently it's being called after the request is made, not after the response is received, and there won't be anything for it to do because the DOM elements aren't there yet.

Help with JQuery Callback

As per my previous question, I have a working animation which fades in and out each element within the div slideshow. The problem is that I want this animation to continue from the beginning once it has reached the last element. I figured that was easy and that I'd just place an infinite loop inside my JQuery function, but for some reason if I insert an infinite loop, no animation displays and the page hangs. I also cannot find anything in the documentation about how properly place a callback. How can I get this code to restart from the beginning of the animation once it finishes iterating over each object and why is an infinite loop not the right way to go about this?
<div id="slideshow">
<p>Text1</p>
<p>Text2</p>
<p>Test3</p>
<p>Text4</p>
</div>
<script>
$(document).ready(function() {
var delay = 0;
$('#slideshow p').each(
function (index, item)
{
$(this).delay(delay).fadeIn('slow').delay(800).fadeOut('slow');
delay += 2200;
}
);
});
</script>
You could do something like this:
$(function() {
var d = 2200;
function loopMe() {
var c = $('#slideshow p').each(function (i) {
$(this).delay(d*i).fadeIn('slow').delay(800).fadeOut('slow');
}).length;
setTimeout(loopMe, c * d);
}
loopMe();
});
You can give it a try here.
Instead of keeping up with a delay, you can just multiple it by the current index in the loop...since the first index is 0, the first one won't be delayed at all, then 2200ms times the amount of elements later, do the loop again. In the above code d is the delay, so it's easily adjustable, and c is the count of elements.
This solution is in my opinion more elegant, also more natural, it is easier to control, to correctly edit values of delays etc. I hope you'll like it.
$(document).ready(function () {
var elementsList = $('#slideshow p');
function animationFactory(i) {
var element = $(elementsList[i % elementsList.length]);
return function () {
element.delay(200).fadeIn('slow').delay(800).fadeOut('slow', animationFactory(i + 1));
};
}
animationFactory(0)();
});

Categories

Resources