I want to show a revolving loader on ajaxStart. I've used a popup for this so that the background fades out and becomes inactive. That said, if there are other ways to achieve this (instead of using a popup), id be willing to try them out too.
The problem is, while the same function containing the AJAX call is executed on both page-load and a button click, the loader only shows up the first time - on page load. I put some console logs and verified that the ajaxStart and ajaxComplete do get triggered, but the pop-up fails to open when the AJAX call is made following the button click.
JavaScript :
$(document).ready(function(){
$( document ).ajaxStart(function() {
$("#loader").html("<img src='../images/ajax-loader.gif'/>").popup("open");
}).ajaxComplete(function() {
$("#loader").popup("close");
});
// do other stuff
loadData();
$("#button").click(function(){
loadData();
});
});
function loadData(){
//make an ajax call to fetch data
}
HTML:
<div data-role="popup" data-shadow="false" data-corners="false" class="loader1"
id="loader" data-overlay-theme="a" data-theme="none" data-dismissible="false" >
</div>
What could be the issue, or are there other solutions altogether to achieve the desired results?
First, the short answer: jQuery Mobile only supports one active popup at a time (for now). The documentation says:
Note: Chaining of popups not allowed
The framework does not currently
support chaining of popups so it's not possible to embed a link from
one popup to another popup. All links with a data-rel="popup" inside a
popup will not do anything at all.
I bumped against this issue a few times in the past and had to hack my way around it. The following code is the solution I'm currently using and works quite well so far (with jQuery Mobile 1.3.2):
$(document).on("mobileinit", function() {
$.widget("mobile.popup", $.mobile.popup, {
_trigger: function(type, event, data) {
return this._suspended ? undefined : this._super(type, event, data);
},
_openPrereqsComplete: function() {
this._super();
delete this._suspended;
},
open: function(options) {
var activePopup = $.mobile.popup.active;
if (activePopup) {
activePopup._suspended = true;
activePopup._close(true);
this.element.one("popupafterclose", function() {
activePopup.open();
});
}
this._super(options);
}
});
});
In a nutshell, that code extends the popup widget in-place to introduce a "suspended" state. All events are muted if a popup widget is in that state.
Then, the open() method is overloaded to detect if another popup is already active. If that's the case, it suspends and closes that popup (without performing any animation, so it is closed right away), then opens the new one and schedules the un-suspending and re-opening of the previous popup when the new one is closed.
Note that code binds to the mobileinit event, so it has to run after jQuery is included but before jQuery Mobile is included. Otherwise, it will be too late to extend the popup widgets that were instantiated during page initialization.
Related
I know there're a lot of duplicate questions out there, I checked almost all of them, but I just couldn't find a solution in my case. So, here's my problem:
I have a banner which will show on every page of the project, inside the banner there's a close button to close the banner, and a download button which leads user to the app store to download the app. My banner works perfect only except I have to refresh the page to get these two buttons works. Here's my code:
$(document).on("pageinit", function () {
$("#close").on("click", CloseBanner);
$("#download").on("click", SetAppStorePath);
//alert("pageinit");
});
function SetAppStorePath() {
if (isIOS) {
window.location = "https://itunes.apple.com/us/app/myapp/id.....";
}
else if (isAndroid) {
window.location = "https://play.google.com/store/apps/details?id=.....";
}
}
function CloseBanner() {
$('.banner').hide();
}
Here's the simplified html:
<div class="banner">
<div class="container">
<a id="close">×</a>
<a id="download">Download</a>
</div>
</div>
I did a little test, and found something tricky: I added that alert inside pageinit, I noticed that the alert is always executed(means my button on click events are always registered) when I jump from page A to page B. But when the button works, I see page A is gone, blank page shows, alert shows, then page B shows, the buttons work. When it doesn't work, the order is different, I still can see page A, then I see alert(I still can see page A now), then it changes to page B, the buttons don't work.
So seems that when pageinit executed after page jumped, it works,but sometimes pageinit executed before page jumped, then it doesn't work.
I think your elements are dynamically created. You may need event delegation.
$(document).on("pagecreate", function () {
$("body").on("click", "#close", CloseBanner);
$("body").on("click", "#download", SetAppStorePath);
});
Move following outside of the init and change it like following
$(document).on("click","#close", CloseBanner);
$(document).on("click","#download", SetAppStorePath);
when page init executes, DOM is not ready. that is the reason it is not binding to close or download elements. and this is the way to overcome that. you dont need pageinit event here
I'm using this to test if a form is dirty.
It defaults to the standard browser confirmation asking if you are sure you want to navigate away from this page. On the jquery dirtyforms site it has a section that says you can use the jquery ui modal form.
So I tried adding a section (a div) like so:
<div id="unsavedChanges" title="Save Changes?">
<p>You've made changes to this page. Do you want to leave this page without saving?</p>
</div>
And then I added what their code looked like:
$.DirtyForms.dialog = {
selector: '#unsavedChanges',
fire: function(message, dlgTitle) {
$('#unsavedChanges').dialog({ title: dlgTitle, width: 350, modal: true });
$('#unsavedChanges').html(message);
},
bind: function() {
$('#unsavedChanges').dialog('option', 'buttons',
[
{
text: "Stay Here",
click: function(e) {
$.DirtyForms.choiceContinue = false;
$(this).dialog('close');
}
},
{
text: "Leave This Page",
click: function(e) {
$.DirtyForms.choiceContinue = true;
$(this).dialog('close');
}
}
]
).bind('dialogclose', function(e) {
// Execute the choice after the modal dialog closes
$.DirtyForms.choiceCommit(e);
});
},
refire: function(content) {
return false;
},
stash: function() {
return false;
}
};
Although I am not sure where they want me to place that (I originally placed it outside of document.ready. However, after running this and making a change to my form and navigating away I see that it still is using the browser confirmation instead of jquery ui dialog box. What am I doing wrong here?
You can only popup a custom dialog if the user is trying to leave by clicking an anchor or other element on your page.
Then you could just intercept the click on all anchors etc, prevent it, pop up a custom dialog to confirm. In other words, when someone is clicking an element on your page, you're in control and can do pretty much whatever you want.
However, when the user is trying to leave by closing the tab or browser, you can not stop them with javascript, as it would be extraordinary annoying if websites could do that.
The only way to prompt a user that is leaving by closing the tab/browser window is to use the onbeforeunload event, and that event can only be used with the native confirm dialog, there is no way to use a custom dialog or stop the user or do anything else really, as that could lead to certain websites creating systems where you could never really leave the site.
From the README:
Dirty Forms will alert a user when they attempt to leave a page without submitting a form they have entered data into. It alerts them in a modal popup box, and also falls back to the browser's default onBeforeUnload handler for events outside the scope of the document such as, but not limited to, page refreshes and browser navigation buttons.
(emphasis mine)
If you want to show a modal for this kind of things, well, you simply can't. (The reason why is security: it's easy to imagine a page preventing the user to close it whatever they attempt, short of killing the browser instance.)
Additionally, the "but not limited to" bit is intriguing: I would ask the plugin's author for details on what exactly this covers, as it might overlap with your use-case.
After a lot of google'ing and reading forums I've not found a suitable answer.
So far all I have found is something like below:
show loading message
call change page
hide loading message
This would work but I would have to do this every time I call load/change page (which is a lot).
Which would leave me either to make a middle man function like below:
function customLoader(url){
showLoader();
$.mobile.changePage(url);
hideLoader();
}
Is there anyway of binding it to the change page event?
So that it shows from the second changePage is called but hides once changePage is away...
I know the above middle man method would work but would like something more tidy and nicer to implement as there's a lot of html/js files.
Something like this:
$('#index').live('pagebeforeshow',function(e,data){
$('#test-button').live('click', function(e) {
$.mobile.showPageLoadingMsg(true);
setTimeout(function () {
$.mobile.changePage('#second');
}, 1000);
});
});
$("#second").live('pageshow', function () {
$.mobile.hidePageLoadingMsg();
});
Timeout is here only so you can see it's working successfully. This is a light example so transition is fired quickly. Remove it in your real code.
And here's an example: http://jsfiddle.net/Gajotres/arrHd/
Every change page event cycle has a order of events occuring when a page A is transiting to a page B. No matter which action is used to trigger a change page you can always disable it when page B i successfully loaded. If you want to find more about page load order take a look at this link: https://stackoverflow.com/a/14010308/1848600. There you will find a lot about jQM page dynamics.
In case you want to implement this into every page transition use this:
$('[data-role="page"]').live('pageshow', function () {
$.mobile.hidePageLoadingMsg();
});
This will hide a ajax loader (if it is open) every time a different page is successfully loaded and shown.
Maybe it's too much for many, but I found a solution different than the written in the comments of this question.
I use the jquery mobile router and in the 'show' event of a page, I do $.mobile.loading("show");, so when the page appears it does with the loading spinner showing.
I use Jquery Mobile Router for a lot more, but it solved this issue.
Though to hide the spinner, I had to use $('.ui-loader').hide();, which is weird, I know...
(Maybe just listening to the proper event and triggering the spinner would also work, as this is what JQMR does...)
I'm using JQM 1.4.2...
I have an ASP.net page with a link to open a jquery-based modal window (that uses colobox jquery plugin). The content of that window in loaded from another aspx file (it loads an iframe). I want to close that window when the user presses an asp:button and if some condition in my code-behind went well.
I tried many ways to close that window from code-behind like these ways:
Page.RegisterStartupScript("X", #"$(this).dialog('close');");
Page.RegisterStartupScript("X", #"var win = window.open('','_self'); win.close();");
btnDone.Attributes.Add("onclick", #"var win = window.open('','_self'); win.close();");
btnDone.Attributes.Add("onclick", #"window.open('../px/nsk.aspx', '_self', null); window.close(); ");
System.Web.HttpContext.Current.Response.Write("<SCRIPT LANGUAGE='JavaScript'>");
System.Web.HttpContext.Current.Response.Write("self.close();");
System.Web.HttpContext.Current.Response.Write("</SCRIPT>");
but non of them can close that modal window. I'm testing on latest version of firefox.
the code behind can be supposed as sth like this:
// do some database works
if (condition)
{
// close this modal window
}
I also tried methods from jquery but none of them were a success.
Can you please telling me how can I close this window?
The other answers given provide specifics; this 'answer' attempts to be more conceptual/consultative.
Closing the Window
Closing the colorbox window is done on the client side. Both #KennyZ and #Farshid provide details on how to do this. By default, ColorBox is going to close on the press of ESC or its EXIT ui element (if used.) It's also possible to close the box programmatically, which sounds like what you need to do.
Where is the Close Action Invoked?
#KennyZ proposes an Ajax call to determine if "some condition in my code-behind went well"; that presumes you cannot tolerate a full page refresh (which seems reasonable to me) but it's something for you to decide.
If the determination of "went well" can only be done on the server, then you're looking at Ajax or a full page refresh.
Alternatively, if there is a way to make the determination on the client side, you won't need to reach back to the back end at all. Just close the colorbox window using js.
If you can provide more details about what the action is that controls closing/not closing the ColorBox window, maybe the community can help even more.
The problem seams to be solved this way:
Page.ClientScript.RegisterStartupScript(GetType(),
"CloseKey", "parent.$.colorbox.close();", true);
Use jQuery dialog with a div instead of an iframe.
Then you can use an Ajax post to run the serverside code and look at the results to decide what to do with the dialog.
Declare the dialog:
$(document).ready(function () {
jQuery("#MyDialog").dialog(
{
bgiframe: true,
autoOpen: false,
modal: true,
width: 800,
position: ['center', 100]
}
);
});
Populate the dialog and open it:
$('#OpenMyDialog').click(function () {
$.post($('url_for_dialog_contents'), function (data) {
$("#MyDialog").empty();
$("#MyDialog").append(data);
}, null, "html");
$('#MyDialog').dialog('open');
return false;
});
Submit the dialog:
$('#SubmitMyDialog').click(function () {
$.post($('url_for_dialog_action'), function (data) {
if (data.success == true) { $('#MyDialog').dialog('close'); }
}, null, "json");
});
I'm sure you'll need a lot more code in the submit dialog, but this is the general idea.
I want to send an ajax request when a user leaves a page or closes the window.
Here is my code inside :
<script type="text/javascript">
function sendajax(){
$.ajax({
url: "someurl",
data: mydata,
async : false
});
}
</script>
<script type="text/javascript">
window.onbeforeunload=function(){sendajax();};
</script>
When the event occurs the event fires twice.
Why does in happen?
I know I can prevent it by adding a variable var ajaxSent=true; but may be there is a cleaner way to do it?
UPD:
I replaced the sendajax function content with some other code (without sending ajax) and found out that ajax is not the one causing the problem. It still enters the function twice.
Based on the code in your edit and comments, it looks like it could simply be caused by the broken link you are clicking to leave the page.
Given the following code:
<script>
function doSomething() { console.log('onbeforeunload fired'); }
window.onbeforeunload = doSomething;
</script>
link A
link B
If I click on link A, I get two console log entries, if I click on link B I only get one.
It looks like it could be a quirk of how the browsers handle their internal "This web page has not been found" pages, causing your page to be refreshed and closed again before showing the message, leaving you with two occurrences of the onbeforeunload event.
I had the same problem and it took a while to understand and resolve, sharing the case details:
There was a custom JS within our template that manipulated the menu.
It caused the unload to fire twice, only when clicking on the menu links, not on other links, and only in IE/EDGE.
We eventually stopped the propagation on these links and the problem was resolved.
$('.SELECTOR a[href^="http://"]').on('click', function(e){
e.stopPropagation();
});
It's a specific bug in your application, therefore you won't find too much information on google.
You could try the following code:
<script type="text/javascript"><br>
window.onbeforeunload=function sendajax(){<br>
$.ajax({<br>
url: "someurl",<br>
data: mydata,<br>
async : false<br>
});<br>
};<br>
</script>
or you can define sendajax() {} at some place and the use it like onbeforeunload = "sendajax()" not as onbeforeunload = "function () { sendajax() }"
beforeUnload is cancellable
I know this post is quite old but from the Chrome Pagelifecycle API documentation, browsers can occasionally partially unload pages to save resources. https://developers.google.com/web/updates/2018/07/page-lifecycle-api beforeUnload is not reliable to make sure that the page is closed. This especially happens on android devices when the screen is locked.
There is a jsfiddle that I found somebody wrote that you can test out https://jsfiddle.net/ov6b9pdL/. Keep the screen locked for 5-10 minutes on Chrome android and you'll see that beforeUnload is fired without even closing the tab.
$(document).ready(function() {
window.addEventListener('beforeunload', showLoader);
});
var showLoader = function() {
$('#loader').show();
};
Agree with AlonMichaeli's concept.
In my application there was anchor tag wrapped with in a div together with couple of spans. When Anchor was clicked on a dirty page, there was couple of 'Leave site' notifications.
It worked fine if any other part of menuItem (div or spans) are clicked.
So in custom javascript method I've added stopped propagation and preventDefault only if anchor tag is clicked. Somehow in this case preventDefault is necessary.
function menuItemClicked(event: JQueryEventObject) {
var item = $(event.target);
if (item.is(".anchor-item")) {
event.stopPropagation();
event.preventDefault();
}
href = item.closest(".anchor-item").attr("href");
if (!event.ctrlKey && href) {
window.location.href = href;
}
}