I have a jQuery dialog that appears and loads an external page. In that page i am running a setInterval() function that queries my server continuously every 1 second (AJAX). The problem is that when i close the dialog, the setInterval doesn't stop running.
here is the code for the dialog:
var theUrl = 'someUrl';
var popUp = document.createElement('div');
$(popUp).dialog({
width: 400,
height: 270,
title: "Some Title",
autoOpen: true,
resizable:false,
close: function(ev, ui) {
$(this).dialog('destroy');
},
modal: true,
open: function() {
$(this).load(theUrl);
}
});
I tried calling $(this).dialog('destroy') and $(this).remove() and document.body.removeChild(popUp) on close. nothing worked. is there anyway to 'unload' the loaded page?
setInterval returns a handler that you can pass to clearInterval to stop the function from running. Here's a basic example of how it works.
var handler = setInterval(function() {}, 2000);
clearInterval(handler);
For your example you'd want to call clearInterval in the close method of the ui.dialog.
Docs:
setInterval - https://developer.mozilla.org/en/window.setInterval
clearInterval - https://developer.mozilla.org/en/DOM/window.clearInterval
Edit
You will not be able to call clearInterval without the stored handler from setInterval, therefore if the call to setInterval is in another script the only way you're going to capture the handler is to override window.setInterval itself.
$(function() {
var originalSetInterval = window.setInterval;
var handlers = [];
window.setInterval = function() {
handlers.push(arguments[0]);
originalSetInterval(arguments);
};
$('whatever').dialog({
close: function() {
for (var i = 0; i < handlers.length; i++) {
clearInterval(handlers[i]);
}
handlers = [];
}
});
});
Note that the code to override window.setInterval must come before including the <script> tag to bring in the external file. Also this approach will clear all interval functions whenever clearInterval is called, therefore this is not ideal, but it's the only way you're going to accomplish this.
Related
I have below code that I have written in JavaScript and the script is referenced on the webpage. When the page loads, a call JavaScript happens and the logic's action should be rendered on the webpage.
Right now the script is firing on the webpage, but the action is not getting rendered on the webpage. However, if I execute the script on page console, changes happen.
<script>
function bannerLoad() {
var delayAddOn = setInterval(function() {
if ($(".add-ons").hasClass("current")) {
if ($('.addons-sidebar.clearfix img').length < 1) {
$(".addons-container :last").append($('<img>', {
class: 'img-responsive',
src: 'https://www.abc.in/content/dam/abc/6e-website/banner/target/2018/06/abc.png'
}));
}
clearInterval(delayAddOn);
}
}, 100);
};
window.onload = function() {
bannerLoad();
};
window.onclick = function() {
bannerLoad();
};
</script>
Can anyone check if there is any issue?
You need to call the script when the page is fully loaded, else the function will be called and can't find the DOM elements.
You should wrap your code inside the ready function:
<script>
//OPEN THE READY FUNCTION
$(function(){
bannerLoad(); //Call of your function when the page is fully loaded
$(window).click(bannerLoad);
});
//CLOSE THE READY FUNCTION
function bannerLoad() {
var delayAddOn = setInterval(function()
{
if($(".add-ons").hasClass("current"))
{
if($('.addons-sidebar.clearfix img').length < 1)
{
$(".addons-container :last").append($('<img>',{class:'img-responsive',src:'https://www.abc.in/content/dam/abc/6e-website/banner/target/2018/06/abc.png'}));
}
clearInterval(delayAddOn);
}
}, 100);
};
</script>
A page can't be manipulated safely until the document is "ready." jQuery detects this state of readiness for you. Code included inside $( document ).ready() will only run once the page Document Object Model (DOM) is ready for JavaScript code to execute. Code included inside $( window ).on( "load", function() { ... }) will run once the entire page , not just the DOM, is ready.
// A $( document ).ready() block.
$( document ).ready(function() {
console.log( "ready!" );
bannerLoad();
$(window).click(bannerLoad);
});
function bannerLoad() {
if($(".add-ons").hasClass("current"))
{
if($('.addons-sidebar.clearfix img').length < 1)
{
$(".addons-container :last").append($('<img>',{class:'img-responsive',src:'https://www.abc.in/content/dam/abc/6e-website/banner/target/2018/06/abc.png'}));
}
clearInterval(delayAddOn);
}
}, 100);
};
Your script has some little issues. I will try to evaluate them.
As bannerLoad is a function you don't need a ; at the end. Not an issue, just a hint.
As told before, bannerLoad is a function. So why would you wrap the function again in a function for your events? Just pass the function name directly, like window.click = bannerLoad;. Note that there are no bracers at the end, you just pass the name.
You function will always create a new delayAddOn variable with a new interval. So every time you click, another interval will be started and run in background. If you will do it like this, you need to put the variable on the outside of your function, to keep only one interval running at a time.
There is nothing wrong with using onload instead of a ready state from jQuery. But this belongs to you page setup and what you do. It would be more safe to rely on a ready state here, as told by others before. Because you already have a function, you could use it directly by $(bannerLoad);.
var delayAddOn;
function bannerLoad() {
delayAddOn = setInterval(function() {
if ($('.add-ons').hasClass('current')) {
if ($('.addons-sidebar.clearfix img').length < 1) {
$('.addons-container :last').append($('<img>', {
class: 'img-responsive',
src: 'https://www.abc.in/content/dam/abc/6e-website/banner/target/2018/06/abc.png'
}));
}
clearInterval(delayAddOn);
}
}, 100);
}
$(bannerLoad);
window.onclick = bannerLoad;
I am using JQuery idleTimeout plugin from here :
http://www.erichynds.com/examples/jquery-idle-timeout/example-mint.htm
I'm using it in an mvc 4 application.
Below is the code snippet where i set the session timer.
<script type="text/javascript">
var sessionTimer = 60;
$(document).ready(function ()
{
// setup the dialog
$("#dialog").dialog({
autoOpen: false,
modal: true,
width: 400,
height: 210,
closeOnEscape: false,
draggable: false,
resizable: false,
buttons: {
'Yes, Keep Working': function () {
$(this).dialog('close');
},
'No, Logoff': function () {
// fire whatever the configured onTimeout callback is.
// using .call(this) keeps the default behavior of "this" being the warning
// element (the dialog in this case) inside the callback.
$.idleTimeout.options.onTimeout.call(this);
}
}
});
var $countdown = $("#dialog-countdown");
#* start the idle timer plugin *#
$.idleTimeout('#dialog', '#dialog-button-yes', {
idleAfter: (sessionTimer - 30),
keepAliveURL: '#Url.Action("KeepAlive", "Home")',
pollingInterval: 5,
serverResponseEquals: 'OK',
AJAXTimeout: 250 * 60,
onTimeout: function () {
window.location = '#Url.Action("Logout", "Login")';
},
onIdle: function () {
$(this).dialog("open");
},
onCountdown: function (counter) {
$countdown.html(counter); #* update the counter *#
}
});
});
This code is placed in the outermost/shared view. All my pages are loaded using partial views using jquery $.ajax. The above code is loaded only once, the sessionTimer gets set to 60 seconds. So the timer does not resets when a new page gets loaded calling ajax post. Even though the user is active, the timer is ticking between the posts.
Is there a way for me to reset the counter every time an ajax post takes place.
I can reset this on every inner views $.ajax success condition. But there are too many places. I would like to know if there is a common code I can write on this master page of mine, that will let me know that an ajax call has been placed and to reset the counter.
Try using the .ajaxSuccess() event handler from jQuery. You can check the documentation on how to use it here: http://api.jquery.com/ajaxsuccess/ .
I am learning JavaScript and I got stuck creating a function to minimize a window. The problem is that this functions seems to stack in itself so many times.
Gere is my principal function :
function displayChatWindow(user, status, avatar, id){
var template = _.template($("#windowTemplate").html(), {userName: user, userStatus: status, userAvatar: avatar, userId: id});
stackingWidth = stackingWidth - boxWidth;
console.log(stackingWidth);
$("body").prepend(template);
$(".messages-container").slimScroll({
height: '200',
size: '10px',
position: 'right',
color: '#535a61',
alwaysVisible: false,
distance: '0',
railVisible: true,
railColor: '#222',
railOpacity: 0.3,
wheelStep: 10,
disableFadeOut: false,
start: "bottom"
});
$("#" + id).css({
top: absoluteY,
left: stackingWidth
});
$(".minimize-others").on("click", displayOthersChat);
$(".chat input, .chat textarea").on("focus", cleanInputs);
$(".chat input, .chat textarea").on("blur", setInputs);
}
This function receives some parameters and with a template creates the chat window. At the end it applies the function to minimize the window (displayOthersChat) and load plugins and stuff for each window.
My displayOtherChats function:
function displayOthersChat(e){
/*e.preventDefault();*/
var This = $(this).parent().parent();
var minimize = This;
if(!This.hasClass("draggable")){
This.animate({
top: windowHeight - boxHeight - 20
});
This.addClass("draggable");
This.draggable({handle: ".header"});
var timeOut = setTimeout(function() {
This.find(".minimize").toggleClass("rotate");
}, 500);
}else{
This.draggable("destroy");
This.removeClass("draggable");
var timeOut = setTimeout(function() {
This.find(".minimize").toggleClass("rotate");
}, 500);
This.animate({
top: absoluteY
});
}
/*return false;*/
}
This seems to work really well. If I open my first window it displays and also minimizing the window works. When I open another window, the last window works correctly but the first window opens when I try to minimize it.
It seems that it calls the function twice, and if I open a third window, the first window calls the function three times.
I actually don't know whats going on, I will appreciate if you guys could help me. I also leave a link so you guys can see whats going on: http://s3.enigmind.com/jgonzalez/nodeChat.
The problem seems to be that you are binding the same event handler to the same elements over and over again.
$(".minimize-others").on("click", displayOthersChat); will bind displayOthersChat to all existing elements with class minimize-others. .on always adds event handlers, it does not replace them. So if you call displayChatWindow multiple times, you are binding the event handler to the .minimize-others elements multiple times.
You only want to bind the handler to the window that was just created, for example:
// create reusable jQuery object from HTML string.
var $template = $(template).prependTo('body');
// instead of $("body").prepend(template);
// ...
$template.find('.minimize-others').on('click', displayOthersChat);
Same goes for the other event handlers.
Alternatively, you could bind the event handler once, outside of the function and use event delegation to capture the event:
$(document.body).on('click', '.minimize-others', displayOthersChat);
I wanted to add a "loading" class to the body element on every ajax call that takes more than 300ms.
so I added the following script to my common.js file:
$(document).ready(function ()
{
var timer;
$("body").on({
ajaxStart: function ()
{
var body = $(this)
var timer = setTimeout(function ()
{
body.addClass("loading");
}, 300)
},
ajaxStop: function ()
{
$(this).removeClass("loading");
clearTimeout(timer);
}
});
});
Now this works if i make the ajax calls at leas 1sec long.
When they are immediate the loading class remains on the body element.
I suspect that the first the ajax call ends before 300ms expires that calls for removing the class and clearing the timer, lets say this takes 10ms, but then the timer the fires after 290ms more...
I wonder how could i test for that?
and weather I'm doing something wrong to achieve the described above task.
P.S
I'm using ASP.NET MVC.
You're redeclaring the variable, loosing the higher scope of the previously declared variable:
$(document).ready(function () {
var timer;
$(document).on({
ajaxStart: function () {
var body = $(document.body);
timer = setTimeout(function () { //don't use the "var" keyword
body.addClass("loading");
}, 300)
},
ajaxStop: function () {
clearTimeout(timer);
$(this).removeClass("loading");
}
});
});
I'm using some jQuery code to create tabs in which the page's content is broken up into (navigable from the top of the tab block) and am looking to do the following when a "next" or "previous" link (placed at the bottom of each tab's content) is clicked:
The page to scroll up to the top of the tab block (successfully implemented using ".scrollTo" plugin) over 750ms
Once scrolled, the tab to change to the corresponding "previous" or "next" tab (identified by a hashtag url) - 250ms later.
Using the following code:
$(".external_link").click(function() {
$.scrollTo(515, 750, {easing:'easeInOutQuad'});
setTimeout(changeTab($(this).attr("href")), 1000);
return false;
});
the two happen at the same time at the mo. If anyone could shed some light on what I'm doing wrong I'd be really appreciative.
The code in full:
$(document).ready(function() {
$(".tab_content").hide();
$("ul.content_tabs li:first").addClass("active").show();
$(".tab_content:first").show();
$('.content_tabs li').each(function(i) {
var thisId = $(this).find("a").attr("href");
thisId = thisId.substring(1,thisId.length) + '_top';
$(this).attr("id",thisId);
});
function changeTab(activeTab) {
$("ul.content_tabs li").removeClass("active");
$(activeTab + '_top').addClass("active");
$(".tab_content").hide();
$(activeTab).fadeIn();
}
//check to see if a tab is called onload
if (location.hash!=""){changeTab(location.hash);}
//if you call the page and want to show a tab other than the first, for instance index.html#tab4
$("ul.content_tabs li").click(function() {
if ($(this).hasClass("active"))
return false;
changeTab($(this).find("a").attr("href"));
return false;
});
$(".external_link").click(function() {
$.scrollTo(515, 750, {easing:'easeInOutQuad'});
setTimeout(changeTab($(this).attr("href")), 1000);
return false;
});
});
Am I right to be attempting to do this with setTimeout? My knowledge is incredibly limited.
setTimeout(changeTab($(this).attr("href")), 1000);
That's the wrong one, you have to put in a function, not the result of executing a function, and 250 ms makes more sense. changeTab is a function, changeTab(argument) is executing a function. So try
var that = $(this);
setTimeout(function() {changeTab(that.attr("href"))}, 250);
I think the reason they execute at the same time is because you call the changeTab-function directly when you set the timeout, and the previous function waits for 750ms before proceding.
You are passing a function call to setTimeout(). You need to pass a function reference. The call will get executed immediately, but a function reference will be executed when the timeout expires. Call setTimeout() like this:
setTimeout(function() { changeTab($(this).attr("href")); }, 1000);
Also, you should consider taking advantage of the onAfter option of the .scrollTo() plugin which indicates a function to be called when the scrolling is completed. It may make more sense to go:
$.scrollTo(515, 750, {
easing: 'easeInOutQuad',
onAfter: function () {
setTimeout(function() { changeTab($(this).attr("href")); }, 250);
}
});