After some hard work on the backend of my Web Application I noticed that the GetMeasure Request takes up to 10 seconds to finish. I decided to apply an overlay so a potential user won't get confused because nothing happens on the screen. No matter if the request is successfull or not the overlay should get removed after the call - so using the complete handler should be the best choice - at least I thought. I really don't get why but in opposite to the success handler the complete handler won't get called.
AJAX Request:
$_loadingCircle = $('<img id="loading" src="http://www.obergurgl.com/_images/layout/loading.gif"/>');
PopulateOverlay($_loadingCircle);
$.ajax({
url: 'CoDTracker/Home/GetMeasures',
type: 'POST',
dataType: "html",
data: {
buID: buid,
aID: aid,
lID: lid
},
success: function (data) {
$('#measures').html(data);
},
complete: function () {
$_overlay.remove();
}
});
The request ends with status 200 (successfull) but the overlay won't get removed. I'm sure that the request completed because my measures got filled into the page while the circle spins as crazy instead of disappearing.
Am I doing something wrong?
Edit:
Overlay-definition
function PopulateOverlay($content) {
$_overlay = $('<div class="overlay">');
$content.appendTo($_overlay);
$_overlay.appendTo('body');
}
Your $_overlay is defined incorrectly.
Please use:
$_overlay = $('div.overlay');
And please refer to jQuery Selectors for more information:
https://api.jquery.com/category/selectors/
The way to select a div with a particular class, is not to copy the entire <div class="">, but rather as I did in the example above.
EDIT: in fact, if you make this change, your PopulateOverlay will no longer work, so you should rather just select it without assigning it to a variable:
complete: function () {
$('div.overlay').remove();
}
Because overlay is appended in the DOM, you should remove it with .class:
complete: function () {
$('.overlay').remove();
}
First, if there's no error, and that's all your code, it should work fine.
Let's try to make an example, with a mimic function to mimic the behavior of ajax complete, we can write it like:
var $_overlay = null; // We assume you define it somewhere, and it's visible to all your functions.
function PopulateOverlay($content) {
$_overlay = $('<div class="overlay">');
$content.appendTo($_overlay);
$_overlay.appendTo('body');
}
// See this as an ajax call with 2 sec delay.
function mimic(cb) {
setTimeout(cb, 2000);
}
function theWorks() {
$someEle = $('<div class="example">example</div>');
PopulateOverlay($someEle);
mimic(function() {
$_overlay.remove();
});
}
$(function() {
theWorks();
});
.overlay {
display: block;
width: 100px;
height: 100px;
background-color: black;
}
.example {
color: cyan;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
So I guess, that your codes, is inside another function, and you may call it many times, let's make a button, and click to trigger it:
var $_overlay = null; // We assume you define it somewhere, and it's visible to all your functions.
function PopulateOverlay($content) {
$_overlay = $('<div class="overlay">');
$content.appendTo($_overlay);
$_overlay.appendTo('body');
}
// See this as an ajax call with 2 sec delay.
function mimic(cb) {
setTimeout(cb, 2000);
}
function theWorks() {
$someEle = $('<div class="example">example</div>');
PopulateOverlay($someEle);
mimic(function() {
debugger;
$_overlay.remove();
});
}
$(function() {
$('#click').on('click', theWorks);
});
.overlay {
display: block;
width: 100px;
height: 100px;
background-color: black;
}
.example {
color: cyan;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="click">Click</button>
Now, if click the button before the previous pop out disappear, some popouts last forever.
Why? Because when you click again, your $_overlay will be assign to a newly created element, which means you lost the reference to the previous pop out, and when later the remove works takes action, it only remove the newest one, and all the following removes, are about to remove something that is not on the page, so you won't see effects, and older popouts remains.
We could fix it, by catch the current element in another variable when you're executing your codes. This would work if you expect many pop outs.
var $_overlay = null; // We assume you define it somewhere, and it's visible to all your functions.
function PopulateOverlay($content) {
$_overlay = $('<div class="overlay">');
$content.appendTo($_overlay);
$_overlay.appendTo('body');
}
// See this as an ajax call with 2 sec delay.
function mimic(cb) {
setTimeout(cb, 2000);
}
function theWorks() {
$someEle = $('<div class="example">example</div>');
PopulateOverlay($someEle);
// Cache the current overlay, or simply move $_overlay here, if no other using it.
var $_curOverlay = $_overlay;
mimic(function() {
$_curOverlay.remove();
});
}
$(function() {
$('#click').on('click', theWorks);
});
.overlay {
display: block;
width: 100px;
height: 100px;
background-color: black;
}
.example {
color: cyan;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="click">Click</button>
Or as what Laurens Swart suggest, simply toggle the state if you only need one pop out at a time.
var $_overlay = $('.overlay');
function PopulateOverlay($content) {
$_overlay
.empty() // Clear previous
.append($content) // Append the content
.show(); // Make it visible.
}
// See this as an ajax call with 2 sec delay.
function mimic(cb) {
setTimeout(cb, 2000);
}
function theWorks() {
$someEle = $('<div class="example">example</div>');
PopulateOverlay($someEle);
mimic(function() {
$_overlay.hide(); // Instead of remove, we make it hide, so we can reuse it later.
});
}
$(function() {
$('#click').on('click', theWorks);
});
.overlay {
display: none;
width: 100px;
height: 100px;
background-color: black;
}
.example {
color: cyan;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="click">Click</button>
<div class="overlay"></div>
Related
I have a bunch of functions that calls another function. I want to run those group of functions in an infinite loop and can't really come up with a logic.
My code looks like this:
<script>
function runAnim(x,y) {
//animation code
}
runAnim(a,2);
setTimeout(function() {
$('#a').fadeOut('fast');
}, 3000);
runAnim(b,4);
setTimeout(function() {
$('#b').fadeOut('fast');
}, 3000);
</script>
So I want to run these two 'runAnim' functions in an infinite loop. I tried
while(1) {}
but this hangs up my browser. I tried implementing setInterval method but don't know how I can do this. If you want I can post the runAnim(x,y) function for more clarity.
Change your runAnim method to include a call to runAnim via setTimeout so that you can an infinite loop while ensuring that maximum stack isn't exceeded.
function runAnim(x,y) {
//animation code
if ( y == 2 )
{
setTimeout( () => {
runAnim(x,4);
$('#a').fadeOut('fast'); //call the fadeout here itself
}, 3000 );
}
else
{
setTimeout( () => {
runAnim(x,2);
$('#a').fadeOut('fast');
}, 3000 );
}
}
You don't need an explicit infinite loop, you can just let the functions call the other one over and over again
Here is an example with chaining:
function fadeOutA() {
$('#b').fadeIn('fast');
$('#a').fadeOut('fast', fadeOutB);
}
function fadeOutB() {
$('#a').fadeIn('fast');
$('#b').fadeOut('fast', fadeOutA);
}
function stop() {
$('#a, #b').stop();
}
$('#start').click(fadeOutA);
$('#stop').click(stop);
div {
width: 50px;
height: 50px;
float: left;
margin: 10px;
}
#a {
background-color: green;
}
#b {
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a"></div>
<div id="b"></div>
<button id='start'>START</button>
<button id='stop'>STOP</button>
What i suggest is don't write any logic which run is infinite loop, because it will cause problem for your browser. But event if you want it to be done done something like below
create for loop for(var i=0;;i++){} and then place your function inside this loop which will execute unlimited times.
I am using the FoundationPress theme (Wordpress Theme with the Foundation 6 from Zurb framework), and i'd like to ajaxify it. (using Ajaxify Wordpress Site plugin).
Now my problem is that most of the javascript that's on my website isn't working after an ajax load.
I have found that this is because most of the javascript in the foundation.js file is executed on document.ready, and that this event is not being triggered when loading a page with ajax.
I understand that it is not possible to trigger the document.ready event after page load. And after seeing multiple threads here, it appears the only solution is to create a new function with the code that's needed on document.ready and ajaxComplete.
BUT, Foundation has a lot of javascript files, and most of it is above my level of understanding. Is there any way to create a function that would automate this ?
EDIT I tried this. I need to pass jQuery as an argument or the code inside initialiseSticky will not work. It works for document.ready but not for ajaxComplete, any idea ?
jQuery(function($) {
console.log('document ready- sticky');
initialiseSticky($);
});
$(document).ajaxComplete(function ($) {
console.log('ajax complete- sticky');
initialiseSticky($);
}(jQuery));
function initialiseSticky($) {
//my code
}
Not sure about foundation.js but if you can make a variable, FooBar for example, assign the function() in $(document).ready() to that variable, and then on ajaxComplete call the variable/function again to "re-trigger" it, like below:
jsFiddle
var res = $('#result'),
bg = $('#bg-div'),
btn = $('#btnTest'),
i = 0, // just for demo to illustrate that it is changing
FooBar;
$(document).ready(FooBar = function() {
bg.delay(200).fadeIn(2000);
console.log('document is ready ' + i++);
});
// simulate ajaxComplete
btn.on('click', function() {
res.text('just dummy text here ' + i);
bg.fadeOut(500);
FooBar();
});
body { margin: 0; padding: 0 }
#bg-div { background-color: orange; width: 100%; height: 100%; position: fixed; z-index: -1; display: none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="bg-div"></div>
<button id="btnTest">Click Me</button>
<div id="result"></div>
I have this code:
document.getElementById('auth-button').addEventListener('click', authorize);
When my page load I want to trigger that without clicking the button.
This is my view
When authorized button clicked this is the output
I want to auto click that button when my page load.
You can use addEventListener to the DOMContentLoaded event:
document.addEventListener('DOMContentLoaded', function() {
authButton.click();
}, false);
Full example:
https://jsfiddle.net/7q0gxehk/1/
you can use Document ready in jQuery, try this..
$( document ).ready(function() {
authorize();
});
or this in javaScript..
window.onload = authorize;
NOTE: The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images, scripts, links and sub-frames have finished loading.
You could call the function authorize() on load of page using below code :
document.addEventListener("DOMContentLoaded", function(event) {
authorize();
});
You can register authorize as handler to be called when the page is fully loaded:
$(document).ready(authorize);
This requires jQuery. The same can be achieved without jQuery this way:
window.addEventListener('load', authorize);
It would be easier to tigger authorize function directly on page load using window.onload which is better than document.onload, see window.onload vs document.onload
window.onload = authorize;
However, if you are thinking about triggering click programmatically which is not suggested since it won't work properly across browsers e.g. Safari doesn't work at all
None of the other answers offered thus far seem to take something into account - that the registered handler may in fact need to be aware of it's place in the DOM.
We could for instance, have a number of buttons that all call the same handler, with that handler manipulating the surrounding DOM. Simply calling authorize when the page loads will not be sufficient.
I've chosen to use DIVs instead of BUTTONs to demonstrate that the .click() method still works.
A far better way is to actually click the button, using javascript.
#1 Not working
function byId(id){return document.getElementById(id)}
function allByClass(clss){return document.getElementsByClassName(clss)}
// useful for HtmlCollection, NodeList, String types
function forEach(array, callback, scope){for (var i=0,n=array.length; i<n; i++)callback.call(scope, array[i], i, array);} // passes back stuff we need
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
forEach(allByClass('mBtn'), addHandler);
function addHandler(elem)
{
elem.addEventListener('click', authorize, false);
}
alert('hit a okay to call authorize');
authorize(); // wont return from this call, since authorize relies on a valid 'this' value
}
function authorize(evt)
{
this.classList.add('clicked');
this.textContent = 'clicked';
}
.mBtn
{
border: solid 1px #555;
border-radius: 2px;
display: inline-block;
}
.clicked
{
color: #dddddd;
pointer-events: none;
}
<div class='mBtn'>Try me</div><div id='btn2' class='mBtn'>Or me</div><div class='mBtn'>Or even, me</div>
#2 - Does work
function byId(id){return document.getElementById(id)}
function allByClass(clss){return document.getElementsByClassName(clss)}
// useful for HtmlCollection, NodeList, String types
function forEach(array, callback, scope){for (var i=0,n=array.length; i<n; i++)callback.call(scope, array[i], i, array);} // passes back stuff we need
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
forEach(allByClass('mBtn'), addHandler);
function addHandler(elem)
{
elem.addEventListener('click', authorize, false);
}
alert('hit okay to click the 2nd button with javascript');
byId('btn2').click(); // will return from this call, since authorize relies on a valid 'this' value, and the btn gives it one.
}
function authorize(evt)
{
this.classList.add('clicked');
this.textContent = 'clicked';
}
.mBtn
{
border: solid 1px #555;
border-radius: 2px;
display: inline-block;
}
.clicked
{
color: #dddddd;
pointer-events: none;
}
<div class='mBtn'>Try me</div><div id='btn2' class='mBtn'>Or me</div><div class='mBtn'>Or even, me</div>
Use one of the following:
<body onload="script();">
or
document.onload = function ...
or
window.onload = function ...
I got a javascript problem. I'm building a website which communicates with a MovieDB-API which will sometimes return broken URLs.
Is there any way to detect whether the URL returned by the API is going to lead to an empty page? Perhaps by checking retroactively if the image defaulted to the "alt"-attribute? Obviously, since the alt-text is showing, the program is "aware" of the fact that the URL fails.
In case the URL is broken, I want to have the IMG-variable replaced by the path to a local default-image.
CSS with javascript enabled
<img src="image.jpg" onerror="this.src='alternative.jpg';">
OR
jquery
// Replace source
$('img').error(function(){
$(this).attr('src', 'missing.png');
});
// Or, hide them
$("img").error(function(){
$(this).hide();
});
Edit
$(document).ready(function () {
$('img').error(function () {
$(this).addClass('noImg');
});
});
.noImg {
position: relative;
background: url() no-repeat center center; // or simple background color
height: 100px;
width: 100px;
content: "Your content";
margin: 0 10px 10px 0;
}
You can use the onerror event to check the URL and see if the image can be loaded.
var url = 'http://www.somesite.com/image.jpg';
var img = new Image();
img.onerror = function() {
console.log('image could not be loaded, setting default placeholder');
image_tag.src = '/my_default_placeholder.gif';
}
img.src = url;
without any posted code, it's just a general example of how it would work,
You could try to do an Ajax request for every image. If it does exist it will return success. Otherwise it throw an error and you can put the desired image in this place.
jQuery Ajax snippet:
$.ajax({
type: "GET",
url: url_to_img,
success: function(result) {
console.log("SUCCESS");
$('#img-1234').attr('src', url);
},
error: function(result) {
console.log("ERROR");
// url broken
$('#img-1234').attr('src', '/img/noImg.png');
}
});
Hope it helps
I have the following snippet of code that loops through the jQuery animate function endlessly. It works fine on Chrome, but fails after the first animate call on IE. My questions are:
How can I make this work in IE (9)?
How can I add a delay after the first loop? I want there to be a delay between consecutive pulses.
#container {
position : relative;
width : 500px;
height : 200px;
overflow : hidden;
opacity: 1;
}
.
#container > img {
position : absolute;
top : 0;
left : 0;
}
.
$(window).load(function(){
$(function () {
var $image = $('#container').children('img');
function animate_img() {
if ($image.css('opacity') == '1') {
$image.animate({opacity: '0.4'}, 2000, function () {
animate_img();
});
} else {console.log('2');
$image.animate({opacity: '1'}, 2000, function () {
animate_img();
});
}
}
animate_img();
});
});
.
<div id="container">
<img src="blah.jpg" width="500" height="375" />
</div>
Remove the console.log() statement from the else branch and it should work in IE - IE doesn't like console.log() unless the console is actually open, whereas (most) other browsers either ignore it or log in a way you can see if you open the console later. (I don't have IE9, but that's all it took to fix it when I tested it in IE8.)
Also it doesn't make sense to have a document ready handler inside a $(window).load() handler, so you should remove one or the other.
As far as adding a delay between consecutive pulses, just use jQuery's .delay() function before calling .animate() in the else branch, like this:
$(function () {
var $image = $('#container').children('img');
function animate_img() {
if ($image.css('opacity') == '1') {
$image.animate({opacity: '0.4'}, 2000, function () {
animate_img();
});
} else { // console.log removed from this spot
$image.delay(500).animate({opacity: '1'}, 2000, function () {
animate_img();
});
}
}
animate_img();
});
P.S. Given that the anonymous functions you've got for the .animate() complete callbacks don't do anything except call animate_img() you can remove the anonymous functions and just pass animate_img directly. So you can make the function much shorter if you wish:
$(function () {
var $image = $('#container').children('img');
function animate_img() {
var fade = $image.css('opacity') == '1';
$image.delay(fade?1:500).animate({opacity:fade?'0.4':'1'},2000,animate_img);
}
animate_img();
});
After a deleted discussion about if setTimeout() or setInterval() should be used, a different solution using setInterval()
$(function () {
var $image = $('#container').children('img');
function animate_img() {
if ($image.css('opacity') == 1) {
$image.animate({opacity: 0.4},{ queue:false, duration:2000});
} else {
$image.animate({opacity: 1},{ queue:false, duration:2000});
}
}
setInterval(animate_img, 4000);
});
Notice that interval time should have a minimum of 4000ms, which the sum of the animation time (2000ms each) back and forth. If the interval is less than that, the animations won't be completed.
I insisted in the previous (deleted) discussion that the correct syntax for setInterval should be setInterval("animate_img()", 4000) ... my bad, because I missed that setInterval was within a function ... so the function animate_img should be called as a pointer rather than a string.
The advantage of this solution (I think) is less lines of code but also that we don't need to call the function animate_img() 3 times in the loop and from within itself.
This should work fine in Chrome as well as in IE.