Await function not working with jQuery event handler - javascript

I have a SweetAlert2 popup that's verifying images uploaded by users. After the user decides I need to continue/stop the main function.
But it just ignores the .then function appended to Swal.
So if the img have good resolution, it returns true. And else it just returns false. Even if the popup shows. It already ran the rest of the main function code.
Img verify function:
function verifyimage(imgurl) {
return new Promise((resolve) => {
var tmpImg = new Image();
tmpImg.src = imgurl;
$(tmpImg).on("load", function () {
var orgWidth = tmpImg.width; //w
var orgHeight = tmpImg.height; //h
if (orgHeight <= 720 || orgWidth <= 1500) {
Swal.fire({
position: "center",
icon: "error",
title: `title`,
showConfirmButton: true,
showCancelButton: true
}).then((result) => {
if (result.isConfirmed) {
resolve(true); //img ok
} else {
resolve(false); //dont upload
}
});
} else {
resolve(true); //upload, good resolution
}
});
});
}
Main function:
$(document).on("click", "#upload-it", async function() {
var valueimg = geturl();
var imgvefify = await verifyimage(valueimg);
if (!imgvefify) {
console.log("nope, invalid img");
return false;
}
//upload to server etc..
});

You've phrased this question as if SweetAlert2 is not respecting your then, but I think it's actually the case that jQuery is not waiting for or respecting your return false; you're issuing it in an async function and jQuery simply doesn't know how to await Promises in event handlers.
Your function passed to on returns a Promise, because all async functions return a Promise in all cases. It seems like you want the return false to cancel the default behavior of the #upload-it button that presumably submits a form, but JavaScript event handlers don't understand when event handlers return Promises, and jQuery doesn't either. This makes it impossible to use return false to cancel the default behavior in an async function event handler.
Instead, make sure to immediately prevent the default behavior and stop propagation before awaiting anything, which you can do by calling methods on the event object. Having prevented the default behavior, you won't be able to "continue" it once the async function completes, but you can still programmatically submit the form.
$(document).on("click", "#upload-it", async function(event) {
event.preventDefault();
event.stopPropagation();
// validate the form
// upload to server etc..
});

Related

beforeinstallprompt triggers on every load

Beforeinstallprompt triggers on every load.
I have used the code here: https://developers.google.com/web/fundamentals/app-install-banners/
I am not using the The mini-info bar which i have dissabled by calling e.preventDefault();
The problem is that the showAddToHomeScreen(); is called on every load if the user does not click addToHomeScreen.
I want the showAddToHomeScreen(); function to be called only every month or so by storing information about the last "canceled" click in sessions or something similar. Isn't google suppose to do this on it's own?
This i found on the following link:
https://developers.google.com/web/updates/2018/06/a2hs-updates
You can only call prompt() on the deferred event once, if the user clicks cancel on the dialog, you'll need to wait until the beforeinstallprompt event is fired on the next page navigation. Unlike traditional permission requests, clicking cancel will not block future calls to prompt() because it call must be called within a user gesture.
window.addEventListener('beforeinstallprompt', function (e) {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = e;
showAddToHomeScreen();
});
function showAddToHomeScreen() {
var prompt = document.querySelector(".a2hs-prompt");
prompt.style.display = "flex";
var open = document.querySelector(".a2hsBtn");
open.addEventListener("click", addToHomeScreen);
var close = document.querySelector(".a2hsBtn-close");
close.addEventListener("click", function() {
prompt.style.display = "none";
});
}
function addToHomeScreen() {
var prompt = document.querySelector(".a2hs-prompt");
// hide our user interface that shows our A2HS button
prompt.style.display = 'none';
if (deferredPrompt) {
// Show the prompt
deferredPrompt.prompt();
// Wait for the user to respond to the prompt
deferredPrompt.userChoice.then(
function (choiceResult) {
if (choiceResult.outcome === 'accepted') {
show_ad2hs_success_message();
}
deferredPrompt = null;
});
}
}
You have to define your own session and add expire date. This is simple with ajax. This is how i did:
Javascript:
$(document).ready(function() {
$.ajax({
url: '/update_session_addtohomescreen',
success: function (session_expired) {
if(session_expired=='True'){
showAddToHomeScreen();
}
},
error: function () {
alert("it didn't work");
}
});
});
This is wrapping the showAddToHomeScreen(); function
View
#csrf_exempt
def update_session_addtohomescreen(request):
if request.is_ajax():
number_of_days_till_expire = 1
now_in_secs = time.time()
if not 'last_session_coockie' in request.session or now_in_secs > request.session['last_session_coockie']+60:#number_of_days_till_expire*86400:
session_expired = True
request.session['last_session_coockie'] = now_in_secs
else:
session_expired = False
return HttpResponse(session_expired)
return None
You should though include csrf token in your request and also add the url to urls.py

Targeting dom element with jQuery not working

I am using a JS Promise to asynchronously get the user's location inside getLocation(). And then I'm making an Ajax request to the server inside postLocation().
$('#add_location_btn').on('click', function () {
if ($('#code').val().length === 0) {
window.alert('Enter a valid code!');
} else {
getLocation().then(function (pos) {
$('#addlocation_loader').attr('hidden', false); // Show loading sign
return pos;
}).then(function (pos) {
postLocation(pos);
});
}
$('#addlocation_loader').attr('hidden', true); // Hide loading sign
});
However, eventually changing addlocation_loader 'hidden' attribute to true is not working, meaning that the attribute is properly set to false but never turns true.
Edit
It's worth noting that I want to hide the loading sign after postLocation() is executed.
I have tried setting 'hidden' to true in a third then() statement, but the sign now never shows up. It seems that the show and hide statements are quickly executed after one another, which is confusing (When I comment out the hide statement the sign is normally shown, which means that both execute).
getLocation().then(function (pos) {
$('#addlocation_loader').attr('hidden', false); // Show loading sign
return pos;
}).then(function (pos) {
postLocation(pos);
}).then(function () {
$('#addlocation_loader').attr('hidden', true); // Hide loading sign
});
You are using an asynchronous function to the attribute to false. That means that probably
$('#addlocation_loader').attr('hidden', true);
is executed before
$('#addlocation_loader').attr('hidden', false);
You may have your hide/show loader backwards. Looks Like you set hidden to false when the location is returned and to true when the button is pressed.
Perhaps something like this would work:
$("#add_location_btn").on("click", function() {
const $loader = $("#addlocation_loader");
if ($("#code").val().length === 0) {
window.alert("Enter a valid code!");
} else {
$loader.attr("hidden", false); // Show when requested
getLocation()
.then(function(pos) {
$loader.attr("hidden", true); // Hide when returned
postLocation(pos);
});
}
});
If you want to hide the loader, you should do it within the .then() callback, because that is when the promise has been resolved. So what you want to do is:
Show loader before executing postLocation()
Remember to return the promise from postLocation() (which you didn't do in the code)
Hide the loader when the promise is resolved (after posting the position has succeeded)
Here is your fixed code:
// Perform async operation
getLocation().then(function (pos) {
// Show loader
$('#addlocation_loader').attr('hidden', false);
// Post location. Remember to return the promise to chain it!
return postLocation(pos);
}).then(function() {
// Hide loader when position is successfully posted
$('#addlocation_loader').attr('hidden', true);
});

protractor wait on condition should not fail after timeout

Is it possible to wait on a ExpectedConditions.visibilityOf without getting a failure if the element has not become visible? I want to handle a situation, where a button might has become visible through an animation and click it away.
browser.wait(conditions.visibilityOf(button), 500).then(function (visible) {
if (visible) {
return button.click().then(function () {/*...*/});
}
});
I found out, that I can handle the rejected promise returned by wait to suppress the timeout error:
browser.wait(conditions.visibilityOf(button), 500).then(function () {
// It is visible
return button.click().then(function () {/*...*/});
}, function() {
// It is not visible
if (shouldExpectVisibility) {
// If I want to fail, I could reject again
return protractor.promise.rejected('No such button');
}
else {
// If I don't want to fail, I do nothing
}
});

How to identify a browser close event in javascript [duplicate]

I want to capture the browser window/tab close event.
I have tried the following with jQuery:
jQuery(window).bind(
"beforeunload",
function() {
return confirm("Do you really want to close?")
}
)
But it works on form submission as well, which is not what I want. I want an event that triggers only when the user closes the window.
The beforeunload event fires whenever the user leaves your page for any reason.
For example, it will be fired if the user submits a form, clicks a link, closes the window (or tab), or goes to a new page using the address bar, search box, or a bookmark.
You could exclude form submissions and hyperlinks (except from other frames) with the following code:
var inFormOrLink;
$('a').on('click', function() { inFormOrLink = true; });
$('form').on('submit', function() { inFormOrLink = true; });
$(window).on("beforeunload", function() {
return inFormOrLink ? "Do you really want to close?" : null;
})
For jQuery versions older than 1.7, try this:
var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });
$(window).bind("beforeunload", function() {
return inFormOrLink ? "Do you really want to close?" : null;
})
The live method doesn't work with the submit event, so if you add a new form, you'll need to bind the handler to it as well.
Note that if a different event handler cancels the submit or navigation, you will lose the confirmation prompt if the window is actually closed later. You could fix that by recording the time in the submit and click events, and checking if the beforeunload happens more than a couple of seconds later.
Maybe just unbind the beforeunload event handler within the form's submit event handler:
jQuery('form').submit(function() {
jQuery(window).unbind("beforeunload");
...
});
For a cross-browser solution (tested in Chrome 21, IE9, FF15), consider using the following code, which is a slightly tweaked version of Slaks' code:
var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });
$(window).bind('beforeunload', function(eventObject) {
var returnValue = undefined;
if (! inFormOrLink) {
returnValue = "Do you really want to close?";
}
eventObject.returnValue = returnValue;
return returnValue;
});
Note that since Firefox 4, the message "Do you really want to close?" is not displayed. FF just displays a generic message. See note in https://developer.mozilla.org/en-US/docs/DOM/window.onbeforeunload
window.onbeforeunload = function () {
return "Do you really want to close?";
};
My answer is aimed at providing simple benchmarks.
HOW TO
See #SLaks answer.
$(window).on("beforeunload", function() {
return inFormOrLink ? "Do you really want to close?" : null;
})
How long does the browser take to finally shut your page down?
Whenever an user closes the page (x button or CTRL + W), the browser executes the given beforeunload code, but not indefinitely. The only exception is the confirmation box (return 'Do you really want to close?) which will wait until for the user's response.
Chrome: 2 seconds.
Firefox: ∞ (or double click, or force on close)
Edge: ∞ (or double click)
Explorer 11: 0 seconds.
Safari: TODO
What we used to test this out:
A Node.js Express server with requests log
The following short HTML file
What it does is to send as many requests as it can before the browser shut downs its page (synchronously).
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
function request() {
return $.ajax({
type: "GET",
url: "http://localhost:3030/" + Date.now(),
async: true
}).responseText;
}
window.onbeforeunload = () => {
while (true) {
request();
}
return null;
}
</script>
</body>
</html>
Chrome output:
GET /1480451321041 404 0.389 ms - 32
GET /1480451321052 404 0.219 ms - 32
...
GET /hello/1480451322998 404 0.328 ms - 32
1957ms ≈ 2 seconds // we assume it's 2 seconds since requests can take few milliseconds to be sent.
For a solution that worked well with third party controls like Telerik (ex.: RadComboBox) and DevExpress that use the Anchor tags for various reasons, consider using the following code, which is a slightly tweaked version of desm's code with a better selector for self targeting anchor tags:
var inFormOrLink;
$('a[href]:not([target]), a[href][target=_self]').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });
$(window).bind('beforeunload', function(eventObject) {
var returnValue = undefined;
if (! inFormOrLink) {
returnValue = "Do you really want to close?";
}
eventObject.returnValue = returnValue;
return returnValue;
});
I used Slaks answer but that wasn't working as is, since the onbeforeunload returnValue is parsed as a string and then displayed in the confirmations box of the browser. So the value true was displayed, like "true".
Just using return worked.
Here is my code
var preventUnloadPrompt;
var messageBeforeUnload = "my message here - Are you sure you want to leave this page?";
//var redirectAfterPrompt = "http://www.google.co.in";
$('a').live('click', function() { preventUnloadPrompt = true; });
$('form').live('submit', function() { preventUnloadPrompt = true; });
$(window).bind("beforeunload", function(e) {
var rval;
if(preventUnloadPrompt) {
return;
} else {
//location.replace(redirectAfterPrompt);
return messageBeforeUnload;
}
return rval;
})
Perhaps you could handle OnSubmit and set a flag that you later check in your OnBeforeUnload handler.
Unfortunately, whether it is a reload, new page redirect, or browser close the event will be triggered. An alternative is catch the id triggering the event and if it is form dont trigger any function and if it is not the id of the form then do what you want to do when the page closes. I am not sure if that is also possible directly and is tedious.
You can do some small things before the customer closes the tab. javascript detect browser close tab/close browser but if your list of actions are big and the tab closes before it is finished you are helpless. You can try it but with my experience donot depend on it.
window.addEventListener("beforeunload", function (e) {
var confirmationMessage = "\o/";
/* Do you small action code here */
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Webkit, Safari, Chrome
});
https://developer.mozilla.org/en-US/docs/Web/Reference/Events/beforeunload?redirectlocale=en-US&redirectslug=DOM/Mozilla_event_reference/beforeunload
jQuery(window).bind("beforeunload", function (e) {
var activeElementTagName = e.target.activeElement.tagName;
if (activeElementTagName != "A" && activeElementTagName != "INPUT") {
return "Do you really want to close?";
}
})
If your form submission takes them to another page (as I assume it does, hence the triggering of beforeunload), you could try to change your form submission to an ajax call. This way, they won't leave your page when they submit the form and you can use your beforeunload binding code as you wish.
As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live()
$(window).bind("beforeunload", function() {
return true || confirm("Do you really want to close?");
});
on complete or link
$(window).unbind();
Try this also
window.onbeforeunload = function ()
{
if (pasteEditorChange) {
var btn = confirm('Do You Want to Save the Changess?');
if(btn === true ){
SavetoEdit();//your function call
}
else{
windowClose();//your function call
}
} else {
windowClose();//your function call
}
};
My Issue: The 'onbeforeunload' event would only be triggered if there were odd number of submits(clicks). I had a combination of solutions from similar threads in SO to have my solution work. well my code will speak.
<!--The definition of event and initializing the trigger flag--->
$(document).ready(function() {
updatefgallowPrompt(true);
window.onbeforeunload = WarnUser;
}
function WarnUser() {
var allowPrompt = getfgallowPrompt();
if(allowPrompt) {
saveIndexedDataAlert();
return null;
} else {
updatefgallowPrompt(true);
event.stopPropagation
}
}
<!--The method responsible for deciding weather the unload event is triggered from submit or not--->
function saveIndexedDataAlert() {
var allowPrompt = getfgallowPrompt();
var lenIndexedDocs = parseInt($('#sortable3 > li').size()) + parseInt($('#sortable3 > ul').size());
if(allowPrompt && $.trim(lenIndexedDocs) > 0) {
event.returnValue = "Your message";
} else {
event.returnValue = " ";
updatefgallowPrompt(true);
}
}
<!---Function responsible to reset the trigger flag---->
$(document).click(function(event) {
$('a').live('click', function() { updatefgallowPrompt(false); });
});
<!--getter and setter for the flag---->
function updatefgallowPrompt (allowPrompt){ //exit msg dfds
$('body').data('allowPrompt', allowPrompt);
}
function getfgallowPrompt(){
return $('body').data('allowPrompt');
}
Just verify...
function wopen_close(){
var w = window.open($url, '_blank', 'width=600, height=400, scrollbars=no, status=no, resizable=no, screenx=0, screeny=0');
w.onunload = function(){
if (window.closed) {
alert("window closed");
}else{
alert("just refreshed");
}
}
}
var validNavigation = false;
jQuery(document).ready(function () {
wireUpEvents();
});
function endSession() {
// Browser or broswer tab is closed
// Do sth here ...
alert("bye");
}
function wireUpEvents() {
/*
* For a list of events that triggers onbeforeunload on IE
* check http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx
*/
window.onbeforeunload = function () {
debugger
if (!validNavigation) {
endSession();
}
}
// Attach the event keypress to exclude the F5 refresh
$(document).bind('keypress', function (e) {
debugger
if (e.keyCode == 116) {
validNavigation = true;
}
});
// Attach the event click for all links in the page
$("a").bind("click", function () {
debugger
validNavigation = true;
});
// Attach the event submit for all forms in the page
$("form").bind("submit", function () {
debugger
validNavigation = true;
});
// Attach the event click for all inputs in the page
$("input[type=submit]").bind("click", function () {
debugger
validNavigation = true;
});
}`enter code here`
Following worked for me;
$(window).unload(function(event) {
if(event.clientY < 0) {
//do whatever you want when closing the window..
}
});

issue with an asynchronous while in WinJS

I have an app which invokes a WebService (callPathsToMultiTiffWS) which have two possibilities:
complete = true
complete = false
in the case complete = false I want to show a dialog which notifies to user than webService failed and two buttons:
retry action (reinvoke WS)
Exit
this is my code so far:
callPathsToMultiTiffWS(UID_KEY[9], stringCapturePaths, UID_KEY[1], UID_KEY[2], UID_KEY[3], UID_KEY[4], UID_KEY[5], UID_KEY[6]).then(
function (complete) {
if (complete == true) {//if true, it stores the id of the picture to delete
Windows.UI.Popups.MessageDialog("WS executed successfully", "Info").showAsync().then(function (complete) {window.close();});
} else {
var messageDialogPopup = new Windows.UI.Popups.MessageDialog("An error occur while calling WS, retry??", "Info");
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Retry', function () { /*code for recall element*/ }));
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Exit', function () { /*code for exit*/ }));
messageDialogPopup.showAsync();
_divInput.innerHTML = "";
}
},
function (error) { console.log("function error"); });
This works good so far, but I want the recall feature working
so I thought to embedd my code inside a loop like this
var ban = true;
while (true) {
callPathsToMultiTiffWS(UID_KEY[9], stringCapturePaths, UID_KEY[1], UID_KEY[2], UID_KEY[3], UID_KEY[4], UID_KEY[5], UID_KEY[6]).then(
function (complete) {
if (complete == true) {//if true, it stores the id of the picture to delete
Windows.UI.Popups.MessageDialog("WS executed successfully", "Info").showAsync().then(function (complete) { window.close(); });
} else {
var messageDialogPopup = new Windows.UI.Popups.MessageDialog("An error occur while calling WS, retry??", "Info");
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Retry', function () { ban == true; }));
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Exit', function () { ban == false; }));
messageDialogPopup.showAsync().then(function (complete) {
console.log("no ps no");
});
}
},
function (error) { console.log("function error"); });
if (ban == false) break;
}
this loop executes the webService, but it doesn't wait for user interaction to trigger the webservice by touching one of the buttons, it is an endless loop with calls to my webService, how to fix this??
thanks in advance for the support
If I'm not missing something, it looks like the error is caused because your code isn't designed to run the next set of tasks after the asynchronous call to showAsync returns. Because the call to showAsync is non-blocking, the while loop will start over again and make another call to the Web service. And because THAT call (callPathsToMultiTiffWS) is also non-blocking, the loop will start over again, triggering another call to callPathsToMultiTiffWS. And over again, and again.
My recommendation is to break out the next call to the Web service so that it will only be triggered when the user makes a selection. If you separate your concerns (move the calls to the Web service into different function or module than the UI that informs the user of an issue), then you can probably fix this.
Kraig BrockSchmidt has a great blog post about the finer details of Promises:
http://blogs.msdn.com/b/windowsappdev/archive/2013/06/11/all-about-promises-for-windows-store-apps-written-in-javascript.aspx
-edit-
Here's some code that I wrote to try to demonstrate how you might accomplish what you're trying:
function tryWebServiceCall(/* args */) {
var url = "some Web service URL";
return new WinJS.xhr({ url: url }).then(
function (complete) {
if (complete) {
return new Windows.UI.Popups.MessageDialog("WS executed successfully", "Info").showAsync().then(
function () { /*do something */ });
} else {
var messageDialogPopup = new Windows.UI.Popups.MessageDialog("An error occur while calling WS, retry??", "Info");
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Retry', function () {
return tryWebServiceCall( /* args */);
}));
messageDialogPopup.commands.append(new Windows.UI.Popups.UICommand('Exit', function () { return; }));
return messageDialogPopup.showAsync();
}
});
}

Categories

Resources