Open new tab without popup blocker after ajax call on user click - javascript

I have a page that enable user to perform image manipulation via HTML5 canvas, on the page, there's a facebook share button for sharing a generated image of the canvas on facebook.
When the link is clicked, an ajax request is sent to the server (ASP.NET MVC) to perform the image generation, save the image on the server, then generate a url(that links to the image) that is returned as the ajax response. The returned url is what I want to pass as the parameter for facebook to share. The issue is that popup blocker is blocking facebook share dialog when I call "window.open".
Is there any other way to open a new tab without popup blocker. I believe that since the user initiated the action, there should be a way for me to bypass popup blocker. Thanks.

Update Oct 2014:
It was noted correctly in the comments, that Firefox has deprecated the synchronous setting in June 2014, but it is still working in this browser.
Furthermore, Chrome received updates which will only allow this to work as wanted if the ajax call returns in less than a second. Which is rather hard to gurantee. I've created another question devoted to the Chrome timeout:
Synchronous Ajax - does Chrome have a timeout on trusted events?
The linked post contains a JSFiddle demonstrating this concept and the problem.
Original Answer
Short answer: Make the ajax request synchronous.
Full answer:
A browser will only open a tab/popup without the popup blocker warning, if the command to open the tab/popup comes from a trusted event. That means: The user has to actively click somewhere to open a popup.
In your case, the user performs a click so you have the trusted event. You do loose that trusted context however, by performing the Ajax request. Your success handler does not have that event any more.
The only way to circumvent this is to perform a synchronous Ajax request which will block your browser while it runs, but will preserve the event context.
In jQuery this should do the trick:
$.ajax({
url: 'http://yourserver/',
data: 'your image',
success: function(){window.open(someUrl);},
async: false
});

Here's how I got round the issue of my async ajax request losing the trusted context:
I opened the popup directly on the users click, directed the url to about:blank and got a handle on that window. You could probably direct the popup to a 'loading' url while your ajax request is made
var myWindow = window.open("about:blank",'name','height=500,width=550');
Then, when my request is successful, I open my callback url in the window
function showWindow(win, url) {
win.open(url,'name','height=500,width=550');
}

The answer from wsgeorge is the one that got me on the right track. Here is a function that hopefully illustrates the technique more clearly.
function openNewAjaxTab(url) {
var tabOpen = window.open("about:blank", 'newtab'),
xhr = new XMLHttpRequest();
xhr.open("GET", '/get_url?url=' + encodeURIComponent(url), true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
tabOpen.location = xhr.responseText;
}
}
xhr.send(null);
}

Related

convert jquery ajax method to javascript

purpose:When we clicking on a link it opens a new window going to gotopage2.aspx.Please help in understanding the code. what does the data parameter in function() contain? the ajax request settings say that request is synchronous and if success run the function. How is the url parameter being used in this context? How can i write the below function in pure javascript without using jquery/ajax settings?
$.ajax({
url: "page1.aspx?Q=userSess1",
async: false,
success: function(data) {
if(data.substring(0, 1)=="1") {
if(mywindow){
mywindow.focus();
}
else{
mywindow=open('gotopage2.aspx','newwindow home page');
}
}
else {
alert("fail");
}
}
});
If all you want is to open a particular URL in a new window, you don't need any fancy JS. All you need is a hyperlink, with the target attribute set to _blank, like so:
CLick me!
AJAX is used to fetch information from the server and dynamically updating our page without refreshing the entire page and without opening a new window. For example, retrieving some JSON from a WEB API endpoint URL.
The url parameter in your ajax call is used to tell the browser where is should retrieve the data from. This is similar to typing "google.com" in your browser and pressing Enter. "Google.com" becomes the address from where the data is downloaded and displayed in your browser.
There are various alternatives to using $.ajax(). Most browsers nowadays have a function called fetch(), which essentially does the same as $.ajax(). Also, most browsers should support the XMLHttpRequest object which does the same. There are also third party JS libraries that can do AJAX as well, like axios and superagent. But as mentioned, if all you want is to open a new Window with a particular page, an tag should suffice. Hope this helps.

Confirm dialog loses focus on iOS10

In the mobile version of my web site I have a JavaScript confirm dialog that appears under specific circumstances. Using setTimeout I trigger the confirm dialog.
No matter which tab the user is in, he should see the confirm dialog but in iOS 10 loses focus.
In iOS version 8 & 9 works fine when I have two tabs and I am in the 2nd tab, the confirm dialog shows up in front like it should.
Is there any solution or workaround for that?
var cf = confirm("Close?");
if (cf){ do that....} else { do this... }
SafariDriver is implemented in JS so in order to intercept calls to alert, confirm, and prompt, one must override the functions in the context of the web page.
Change the injected script to be injected as a Start script instead of End script - which means the script is injected once the DOM has been loaded, but before it has been parsed (as opposed to being injected after the onload event):
http://developer.apple.com/library/safari/#documentation/Tools/Conceptual/SafariExtensionGuide/InjectingScripts/InjectingScripts.html#//apple_ref/doc/uid/TP40009977-CH6-SW5
Override the global alert functions in the context of the page under test, not the injected script. This is similar to the requirements of the executeScript command. Therefore, the first thing our injected script should do is add a script tag to DOM that sets up the alert overrides. This script tag should be added as the first child of the documentElement to ensure it is executed before any others in the page. This will ensure we set-up our alert handlers before anything in the page has a chance to fire an alert.
Once an alert fires, we must notify the extension that there was an alert, while simultaneously blocking the current JS thread in the page. Normally, our page scripts communicate with the injected script using window.postMessage. postMessage fires a MessageEvent asynchronously. To maintain synchronicity, we can manually fire a MessageEvent:
Use a MessageEvent instead of some other DOM event so we can include a JSON object describing the alert.
var event = document.createEvent('MessageEvent');
event.initMessageEvent('message', false, false, {
type: "alert", // confirm, or prompt
text: "hello"
}, window.location.origin, '0', window, null);
window.dispatchEvent(event);
The injected script must listen for an respond to the page's alert message. To synchronously send the alert to the extension for processing, we can (ab)use the Safari extension's mechanism for blocking content from loading:
http://developer.apple.com/library/safari/#documentation/Tools/Conceptual/SafariExtensionGuide/MessagesandProxies/MessagesandProxies.html#//apple_ref/doc/uid/TP40009977-CH14-SW9
window.addEventListener('message', function(e) {
// Create a beforeload event, which is required by the canLoad method
var e = document.createEvent('Events');
e.initEvent('beforeload', false, false);
// canLoad sends and waits for a response synchronously. It is the only
// synchronous function in the Safari extension messaging API.
var response = safari.self.tab.canLoad(e, e.data);
// Send the response back to the page using another MessageEvent.
var responseEvent = document.createEvent('MessageEvent');
responseEvent.initMessageEvent('message', false, false, {
accepted: response.accepted,
response: response.value
}, window.location.origin, '0', window, null);
window.dispatchEvent(responseEvent);
}, true);
Note, the extension's alert response must be communicated back to the page using another message since we are crossing context boundaries. The only other option is to store the response on the DOM to be read on the other side.
The final step, and this is the open-ended question, is how the extension should handle the alert. Since we're maintaining the blocking behavior of alerts, it's not possible to let anymore commands execute (even if they result in unhandled alert errors).
One possibility is to have the WebDriver client participate in the alert handling. In addition to providing a WebSocket server, the WebDriver client will be expected to also provide an XHR end-point. When an alert is detected, the server will send a synchronous POST XHR to this end-point. The client should respond only once the user has accepted or dismissed the alert (or an unhandled alert error was thrown from another command). When the XHR response is received, the extension completes the chain and sends the response back to the injected script.
You can find more here.

Cancel ajax request from chrome developer tools

I want to cancel the ajax request from chrome developer tools after it has initiated. For example I want to test my fallback message is showing correctly. I can set No throttling to Offline so that all calls will fail, but I just want to test one API to fail, for debugging purposes.
I know I can use abort() methods, (ie I can do it through JavaScript). I dont want to touch the code for just this need.
There's a replay XHR option in right click of the API, It'll be great there is something like abort XHR in same way. But there isn't.
From Chrome 59 you can block specific requests from Network tab of developer tools itself.
https://developers.google.com/web/updates/2017/04/devtools-release-notes#block-requests
Right-click on the request in the Network panel and select Block Request URL. A new Request blocking tab pops up in the Drawer, which lets you manage blocked requests.
So, In my case, I will run the code block that specific API and then re-run. :)
As per the comment, this is not exactly canceling the already started request, but checking how the app behaves if only one request is failed by blocking only one request. Thanks #Ross Ivantsiv for this.
There is a simple trick I use. Pressing F5 while in the tab immediately followed by ESC.
XHR requests still active by chrome are canceled before the new answer is loaded.
If you don't know the exact URL, You can debug all XHR by adding an XHR breakpoint within the Sources tab
Or if you know the name or part of XHR URL which you need to debug you can add it XHR by clicking the ( + ) icon.

Browser refresh sends the last $http call made

AngularJS 1.2.13
var httpdelete = $http.delete("/api/categories/" + id);
httpdelete.success(function(data){
alert("Success");
});
httpdelete.error(function(data, status, header, config){
alert("Error!");
});
I do an asynchronous $http.delete request
The success callback function is executed and the alert box "success" appears.
I hit the browser refresh button
The $http.delete line is not executed (debugged with break points). Instead the error callback function is immedialy executed. The alert box "error" appears. No request made it to the server after clicking on the browser's refresh button
I was expecting the entire page to reload when I hit the browser's refresh button.
Instead, AngularJS seems to attempt to resend my last delete query without having to execute $http.delete and goes straight to the error callback.
How can I restore the natural behaviour of the browser's refresh button? I want it to reload the entire page and not attempt to resend the last asynchronous http request.
Open the network tab of the chrome dev tools. Load your page and hit F5. If you don't see a get to your index.html (or whatever your base url is), it's because angular handled it. If you do see the get, the you have rebooted the app for real.
Once you know which one it is, you can investigate further. Setting a breakpoint in the httpdelete callback and inspecting the callstack might also help.
Okay so here is what happened, my backend Nodejs+Express+MongoDB delete action was not returning anything to the client (browser). I didn't think it was necessary to return any information after deleting the document from mongodb.
The side effect of that is as I described in the original post. After deleting the document on the server, if a user refreshes the page using the browser refresh button then the page is not refreshed. Instead the $http.delete request is resent to the server and on top of it the error callback is executed.
After modifying my server side action and make it return a json document such as { success: true, message: "" } after a delete request, the browser's refresh button behaves as it should have which is to reload the entire single application page index.html.

Is there any possibility how to send an AJAX after close the browser window? [duplicate]

This question already has answers here:
JavaScript, browsers, window close - send an AJAX request or run a script on window closing
(9 answers)
Closed 6 years ago.
Is there any possibility how to send AJAX after close the browser window?
I have a browser game with movement in JavaScript (jQuery) and if I send Ajax after each movement it would be difficult for the server. So I want to send one AJAX when user close the window (or bookmark).
It must be functional in all modern browsers.
Thank you for answers
I'd suggest you update the server on some sort of timer so the server never gets too far behind in knowing what state the client is in (perhaps every 60 seconds when the client is active), pausing server updates when the client is not active.
Then, in your user interface, put some obvious user interface elements for Close or Stop that encourages the user to shut-down that way and then update the server when either of those buttons are hit.
Then, you can also hook the unload event for the page and send one last ajax call then. But, this is not called in every case or supported in all browsers so this would be done in addition to the two previous techniques.
I don't think there is a practical way to do it... but there is definitely a solution to your problem.
You can send your request either at some time interval or when the game arrives at a particular stage.
We're not seeing the complete scenario so please evaluate a bit more so I or someone else can help.
If possible.. I would add a "Save State" or just "Save" button. So the user knows that if he doesn't hit "Save" nothing will be "Saved".
You can try window.onbeforeunload e.g.:
function saveGame(e) {
if (!e) e = window.event;
//Ajax here
}
window.onbeforeunload = saveGame;
You can't send any ajax request after closing browser window. But you can use onUnload event for send ajax request when user click close button of the window.
I can suggest this:
invoke window.onunload (pay attention to firefox!) and store the current location in the server. important: make this async call.
in the server save the state of the user (leaving a page)
write a code in the global request event handler and query this state.
you can launch threads in the server to invoke the final unload (say, after 5 sec) no new request from the client
I know these steps are hard to implement, but they address your problem and solves it.

Categories