When I drop a debug point in my source file I can see the following image:
But when I remove this debug point, I only see the following:
The change in color is affected by an overlay with some opacity.
The relevant code is:
flashSuccessMessage = function(msg) {
$('#overlay').hide();
var $ch = $("#content-header");
$ch.after('<div id="flash_message" class="alert"></div>');
var $fm = $("#flash_message");
$fm.addClass("alert-success");
$fm.append(msg);
$fm.show().children().show();
$fm.fadeOut(3000);
$fm.empty();
}
And in this case msg is "Job Type Added Successfully"
I can't understand why I only see the message when I break on the execution after the point where I call $fm.append(msg); It doesn't matter which I break on after that (of the three lines), it will appear. When I don't have any break and let the page execute the script, the green alert appears but no words.
Any ideas?
I've tried various jQuery methods here - instead of .append() using .html() for example, and I've tried inserting the msg inside the with the flash_message id to begin, tried inserting the message wrapped in tags, tried re-ordering things, (but I need to clear the contents of this div at the end...)
I've used jQuery's .delay() method, etc. Is it jumping to executing .empty() despite other elements using a timer to fully execute?
Add a callback to your fadeOut so that the contents aren't emptied until $fm is completely hidden:
flashSuccessMessage = function(msg) {
$('#overlay').hide();
var $ch = $("#content-header");
$ch.after('<div id="flash_message" class="alert"></div>');
var $fm = $("#flash_message");
$fm.addClass("alert-success");
$fm.append(msg);
$fm.show().children().show();
$fm.fadeOut(3000, function(){ // empty() is not called until
$(this).empty(); // the animation is complete
});
}
Without the callback, the empty() method is being triggered immediately after fadeOut(). This causes the content to be emptied BEFORE the animation is complete.
More information on jQuery's fadeOut method can be found in the docs.
The animations in JQuery are asynchronous, so the code keeps executing while the animation happens. .fadeOut has a completion block which you can read about at http://api.jquery.com/fadeOut/.
So, instead of calling fm.empty() after your animation, you should put it inside a function and pass that function into fade out. That function will then run after the animation completes.
but I need to clear the contents of this div at the end...
Use html instead of append:
$fm.html(msg);
$fm.fadeOut(3000, function(){
$fm.empty();
});
Check doc of fadeOut:
.fadeOut( [duration ] [, complete ] )
complete
Type: Function()
A function to call once the animation is complete.
Related
I am working on a font-test page that should switch the font of the header and paragraph tags on click. Which works fine but the experience is really jarring so I want to smooth it out with the following path:
fadeout -> do the font swap -> fade in
But the code runs the font swap first, then the animation.
I have the following code snippet, I am only including the jQuery because it's the root cause of my problem.
// Anytime a card is clicked
$('.card').click(function(){
// Call card by id and switch the fonts
var id = "#" + this.parentElement.id;
$(this).fadeOut(900,swapFont(id));
$(this).fadeIn(500);
// attach the above to some sort of transition callback
});
// Function to swap the font around so that the header is now the body font and the body font is now the header font
function swapFont(id) {
// font-swap logic in here which works fine
}
The issue is because the fadeOut() animation is (effectively) asynchronous. This means the next statement will be evaluated while the animation is in progress - hence the behaviour you're seeing. To fix this you need to use the callback pattern that the fadeX() methods provide.
Also, you're passing the result of the immediate execution of swapFont() to the callback, instead of a function reference to run when the event occurs. Try this:
$('.card').click(function(){
var id = "#" + this.parentElement.id;
$(this).fadeOut(900, function() {
swapFont(id);
$(this).fadeIn(500);
});
});
You are currently passing the result of the swapFont() call, instead you need to point to the function itself.
So this:
$(this).fadeOut(900,swapFont(id));
is the same as:
var x = swapFont(id);
$(this).fadeOut(900, x);
Easiest way is to wrap it in an anonymous function:
$(this).fadeOut(900, function() { swapFont(id) });
Edit:
The fadeIn will also execute before the fadeOut has completed. You can add a .delay or, better, call the fadeIn in the callback as per Rory's answer (so I won't repeat here).
My question is in two parts. One overall question and one relating to it with explicit code.
The general question:
Is Javascript read into the memory on load, and by this "installed", or is it read each time I do something? How are handlers installed? Once I .click() on an element, is then the handler in memory, including the function inside it? I once had trouble with a .mouseleave(), every time I left the element, the function was installed again and it was absolute chaos...how does this work with .click() then? Is the function then every time read again or does it stay in memory? The solution to the .mouseleave() was: here.
The specific question:
I just found out, that a .click() function I use here runs on first click once, on the second click twice, etc. ? You can see it, when you open the link, open the console and click on an image. Click on it to close it again, then click on ANY(!!) image and it loads as described. Weird, huh? Also it logs in the console the boolean for .data("installed") as true, although the switch to true comes only later in code?
Hope you can help me.
jQuery code:
$('.pfiles').data("installed", false);
if (!$('.pfiles').data("installed")) {
$('.pfiles img').click(function() {
var scroll = $('body').scrollTop(),
imgThis = $(this).attr('src'),
txtThis = $(this).attr('src').split('/')[2].split('.')[0] + ".txt",
$this = $(this),
bigImgH = $(this).height(),
bigImgW = $(this).width();
$('.progress').show();
console.log($('.pfiles').data("installed"));
$('.pfiles').fadeOut(200, function() {
$('.big').fadeIn(400);
$('.frame').height($('.big').height());
});
$.ajax({
type: 'GET',
url: imgThis,
dataType: 'HTML',
success: function(data) {
$('.big').empty().append("<img src='" + imgThis + "'/>");
if (bigImgW / bigImgH <= 1.3529411176) {
$('.big img').css({'height': '100%'});
} else {
$('.big img').css('width', '100%');
}
$('body').scrollTop(0);
$('.big img').click(function(){
$('.big').fadeOut(400, function() {
$('.pfiles').fadeIn(400);
$('body').scrollTop(scroll);
$('.big').empty();
$('.frame').height($('.incontent').height());
});
});
// progress();
}
});
});
$('.pfiles').data("installed", true);
}
"HTML" code
<?php
//Profile catch
$path = 'img/profile';
$profiles = scandir($path);
natsort($profiles);
$profiles = array_reverse($profiles);
$profiles = array_diff($profiles, array('.', '..', '.DS_Store', 'txt'));
?>
<div class="incontent" style="background:white">
<div class="progress">
<div class="bardiv">
<div class="bar"></div>
<p class="bartext text"></p>
</div>
</div>
<div class="big"></div>
<div class="pfiles">
<?php
foreach ($profiles as $pfiles) {
echo '<img onclick="" src="img/profile/'.$pfiles.'">';
}
?>
</div>
I already tried the same trick with the .data(), but it keeps console.logging on every click (even true!) and it is to no avail to the multiple XHR load... (On the server it is without the .data() switch!)
Javascript code in your page is parsed and run at the time the page loads and remains in memory in the browser while the page is active. As the user interacts with the page, any event handlers that your code might have installed are then called upon demand as those events happen.
Once you install a .click() handler, it remains in place for the lifetime of that DOM element or until you remove the click handler. Until you remove it, the click handler will get called every time the item is clicked on.
You should ONLY install a .click() handler for a given function one time. If you install it multiple times, it will be called multiple times when the item is clicked. If your click handler is being called more and more times each time you click it, then your code is apparently installing another click handler each time you click on it and you would need to modify your code not to do that.
To help more specifically, we'd need to know which click handler you're having an issue with and probably need to see some of the relevant HTML.
You can simplify your event handling code by having only one constant event handler for the .big img rather than constantly creating a new one. You can do that with delegated event handling like this:
$(".big").on("click", "img", function() {
$(".big").fadeOut(400, function() {
$('.pfiles').fadeIn(400);
$('body').scrollTop(scroll);
$('.big').empty();
$('.frame').height($('.incontent').height());
});
});
Put this code before any of the code you have in your question so it is initialized once and only once.
Here's a potential problem. At the very beginning of your block of code, you have this:
$('.pfiles').data("installed", false);
if (!$('.pfiles').data("installed")) {
That means that you will ALWAYS execute the if block, even if you previously set the data to true. You can just remove the first line because the default value for $('.pfiles').data("installed") will be falsey. You don't need to initialize it. Then, when this is called subsequent times, it will respect the fact that you've set it to true later in your code.
i want to expand a division with data that should be loaded from another server.
the problem is if i start expanding the division (toggleslide) and the load method finishs the height is jumping and the effect is destroyed.
what i want is that jquery starts expanding AFTER the data-transfer finished but my following code does not work:
// divison name = details
details.load("index.php", expandLastResultDetails3(details));
function expandLastResultDetails3(details) {
$(details).slideToggle('slow', function () {
ready();
});
}
the box is jumping because (i guess) the slidetoggle starts to early.
.load() expects a function callback to be called upon the completion of the request. However, instead of passing a callback, you are executing the function. Try the following:
details.load("index.php", function () {
expandLastResultDetails3(details);
});
I populate many parts of my website using
$("#theDivToPopulate").load("/some/api/call.php", callBackToBindClickEventsToNewDiv);
Where /some/api/call.php returns a built list, div, or some other HTML structure to place directly into my target div. The internet has been running slow lately and I've noticed that the time between a button click (which kicks off these API calls) and the div populating is several seconds. Is there an easy way to globally wrap all the load calls so that a div containing "Loading..." is displayed before the call is even made and hidden once the API call is complete.
I can not simply put the code to hide the div into the callBackToBindClickEventsToNewDiv as some load events have different call backs. I would have to copy the code into each function which is ugly and defeats the purpose. I want the flow of any .load to go as follows:
1) dispplayLoadingDiv()
2) Execute API call
3) Hide loading div
4) do callback function.
The loading div must be hidden first as the callback contains some animations to bring the newly loaded div in nicely.
EDIT:
Expanding on jacktheripper's answer:
var ajaxFlag;
$(document).ajaxStart(function(){
ajaxFlag = true;
setTimeout(function (e) {
if(ajaxFlag) {
hideAllDivs();
enableDivs(['loading']);
}
}, 500);
}).ajaxStop(function(){
ajaxFlag = false;
var load = $("#loading");
load.css('visibility','hidden');
load.css('display','none');
load.data('isOn',false);
});
This way loading is only displayed if the page takes more than 500 MS to load. I found the loading flying in and out real fast made things kind of choppy for fast page loads.
Use the following jQuery:
$(document).ajaxStart(function(){
$('#loader').show();
}).ajaxStop(function(){
$('#loader').hide();
});
Where you have an element called #loader that contains what you want to show when an AJAX request is being performed. It could be a span with text, an image (eg a gif), or anything similar. The element should be initially set to display: none
You do not even need to call the function anywhere else.
Try this
$("#someButtonId").click(function(e){
e.preventDefault();
$("#theDivToPopulate").html("Loading...");
$.get("/some/api/call.php",function(data){
$("#theDivToPopulate").fadeOut(100,function(){
$("#theDivToPopulate").html(data).fadeIn(100,function(){
//Do your last call back after showing the content
});
});
});
});
I am trying to hide a result div. Modify it. Then Show it with animation.
I have the following:
$("#SearchButton").button().click(function() {
$("#resultContainer").hide();
$("#resultContainer").empty();
searchResults();
$("#resultContainer").show("slow");
});
Where searchResults() makes an ajax call to load some stuff into the div #resultContainer
However, even if I comment out the line //searchResults(); I still end up with a blank div when I click the button.
However if I switch $("#resultContainer").show("slow"); to $("#resultContainer").show(); It works fine. But I want the animation. .show("slow") works fine elsewhere...
Update: I now have:
$("#SearchButton").button().click(function() {
$("#resultContainer").hide(0);
searchResults();
});
And searchResults does the ajax call with the following callback:
//appending something to the div here
$("#resultContainer").show(600);
alert("test");
I get the alert but the div never shows back up...
You code can be improved, try this:
$(function() {
var $resultContainer = $("#resultContainer");
$("#SearchButton").click(function() {
$resultContainer.hide();
//$resultContainer.empty(); // BTW, no need to empty since the ajax will replace its content anyway!
searchResults();
});
function searchResults() {
$.ajax({
url: "yourRequest.php",
success: function(resp) {
$resultContainer.html(resp);
$resultContainer.show("slow");
}
});
}
});
You don't need the empty the container since it's content will be replaced in the ajax call anyway and it's already hidden anyway!
Remove your show method to the ajax success callback
store the container in a var $resultContainer and use it for faster access.
And here's a live example.
Your code showing the resulting div:
$("#resultContainer").show("slow");
should be chained in the callback of the ajax call; that's the only way you can be sure it will get executed after the ajax result is there. See the optionnal function callback at the end of the load() function. or the callbacks in the ajax functions of jQuery.
You could use something like a jquery queue to queue your events and get that queue paused. Then un-pause the queue in your ajax callback.
Or define some named functions and test that theses callbacks exists before calling them in the ajax callback.
Last thing, please store your selector results var $foo=$("#resultContainer") and use $foo variable after that and avoid calling the $() selector each time you need that div. This can speed up a lot your code.