I have an endpoint that expects a POST request and produces a file. On the front end I need to redirect the page using a form submittal. However, I need to generate the form dynamically (for a variety of reasons on the front end).
Here is my attempt (bear in mind, I had to edit the code a bunch since it sits across various http related components):
sendRedirect(options) {
options.form = this.createForm(options.body);
options.form.setAttribute('method', 'post');
options.form.setAttribute('action', redirectTo);
options.form.submit();
}
createForm(body) {
let form = window.document.createElement('form');
return Object.keys(body).reduce((_form, key) => {
let i = document.createElement('input');
i.setAttribute('type', 'hidden');
i.setAttribute('name', key);
i.setAttribute('value', body[key]);
_form.appendChild(i);
return _form;
}, form);
}
The above works fine in google chrome. However, in firefox, nothing happens (i.e. no network request is sent after the form.submit() executes). I have stepped through the code in firefox and it seems to be executing just fine (i.e. all the variables are set to what they are supposed to be). The code reaches its end of execution at form.submit() and then... nothing.
Thanks in advance.
Edit: Thanks to Quentin for the answer. Here is the code that I added to make it work:
options.form.style.visibility = 'hidden';
window.document.getElementsByTagName('body')[0].appendChild(options.form);
The form needs to be part of the document for Firefox to submit it.
Append it to (for example) document.body before calling submit.
Related
Recently when i did some adventofcode, i came across a bug:
The bug happens in firefox except for if you run the code as multiple chunks, but doesnt happen in chrome.
When i run this code in the firefox console, in a tab with url https://www.google.com/robots.txt :
// Fetch input
var input = await fetch("https://www.google.com/robots.txt").then(r => r.text());
var lines = input.split("\n");
// Iterate
while(lines.length > 0) console.log(lines.shift());
It prints nothing, but when i run the code as two pieces (separated by // Iterate) it works. Note that you can change the fetch url and url of the tab, i chose robots.txt and made them the same to avoid CORS errors.
Does anyone know why this happens or how to fix this?
Edit: The code works if you wrap the code in an async function and call it, but it should work regardless.
I have some strange behavior on my window.location redirects in IE and Firefox as part of my angular application. When calling window.location = xyz the first time it works fine in IE/FF/Chrome. On the second call which is supposed to go to google.com, Chrome does what it's supposed to, but IE and FF don't do anything. In the IE web console I can see that the navigation was triggered but the page and URL hasn't changed in my window. Now if I press F5 on this page it goes to the page it's supposed to even though the URL at the top is not pointing there (both in IE and FF).
Has anyone ever encountered this problem and knows how to solve it? I've tried all versions of redirecting (window.location, window.location.href, windows.location.assign(), window.location.replace() and also the angular service $window) with no luck.
First call triggered from a button press (working fine in all browsers):
$scope.pressButton = function() {
var url = 'xyz/index.html';
$window.location = url;
};
Second call triggered by a keypress (only works in Chrome):
function exitModule() {
$window.location = 'http://www.google.com';
console.log('window.location'); // still pointing to the old page
}
Update with code calling the exitModule() function:
Note: The application is built with angularjs.
The exitModule() function gets called in all browsers, it's just the redirect which doesn't happen in IE/FF.
HTML:
<body ng-app="myModule" ng-controller="MainCtrl" ng-keydown="keyPress($event);">
JS:
// Handle global key press
$scope.keyPress = function(event){
if(event.which === 27) { // EscapeKey
exitModule();
} else {
$scope.$broadcast('keyPress', event);
}
};
Alright I found the issue and I'm aware that it was almost impossible to figure this out without having the full code available. The above code was a bit simplified therefore it was missing the problem. The function exitModule gets called as soon as a promise is resolved. The call looks like this:
Correct
dataService.saveModule().then(exitModule);
My code was as shown below with the brackets after exitModule which is wrong. I don't quite understand the behavior of FF/IE compared to Chrome though ...but that's for another day.
Wrong
dataService.saveModule().then(exitModule());
I am trying to start 3 applications from a browser by use of custom protocol names associated with these applications. This might look familiar to other threads started on stackoverflow, I believe that they do not help in resolving this issue so please dont close this thread just yet, it needs a different approach than those suggested in other threads.
example:
ts3server://a.b.c?property1=value1&property2=value2
...
...
to start these applications I would do
location.href = ts3server://a.b.c?property1=value1&property2=value2
location.href = ...
location.href = ...
which would work in FF but not in Chrome
I figured that it might by optimizing the number of writes when there will be effectively only the last change present.
So i did this:
function a ()
{
var apps = ['ts3server://...', 'anotherapp://...', '...'];
b(apps);
}
function b (apps)
{
if (apps.length == 0) return;
location.href = apps[0]; alert(apps[0]);
setTimeout(function (rest) {return function () {b(rest);};} (apps.slice(1)), 1);
}
But it didn't solve my problem (actually only the first location.href assignment is taken into account and even though the other calls happen long enough after the first one (thanks to changing the timeout delay to lets say 10000) the applications do not get started (the alerts are displayed).
If I try accessing each of the URIs separately the apps get started (first I call location.href = uri1 by clicking on one button, then I call location.href = uri2 by clicking again on another button).
Replacing:
location.href = ...
with:
var form = document.createElement('form');
form.action = ...
document.body.appendChild(form);
form.submit();
does not help either, nor does:
var frame = document.createElement('iframe');
frame.src = ...
document.body.appendChild(frame);
Is it possible to do what I am trying to do? How would it be done?
EDIT:
a reworded summary
i want to start MULTIPLE applications after one click on a link or a button like element. I want to achieve that with starting applications associated to custom protocols ... i would hold a list of links (in each link there is one protocol used) and i would try to do "location.src = link" for all items of the list. Which when used with 'for' does optimize to assigning only once (the last value) so i make the function something like recursive function with delay (which eliminates the optimization and really forces 3 distinct calls of location.src = list[head] when the list gets sliced before each call so that all the links are taken into account and they are assigned to the location.src. This all works just fine in Mozilla Firefox, but in google, after the first assignment the rest of the assignments lose effect (they are probably performed but dont trigger the associated application launch))
Are you having trouble looping through the elements? if so try the for..in statement here
Or are you having trouble navigating? if so try window.location.assign(new_location);
[edit]
You can also use window.location = "...";
[edit]
Ok so I did some work, and here is what I got. in the example I open a random ace of spades link. which is a custom protocol. click here and then click on the "click me". The comments show where the JSFiddle debugger found errors.
I'm writing a Rails 2.3.8 app, and using the standard link_to helper. I have a reasonable number of links that user methods other than GET, so I pass a :method => :whatever option to link_to, and it generates a link with an onclick handler like so (indentation added for readability):
<a
onclick="
var f = document.createElement('form');
f.style.display = 'none';
this.parentNode.appendChild(f);
f.method = 'POST';
f.action = this.href;
var s = document.createElement('input');
s.setAttribute('type', 'hidden');
s.setAttribute('name', 'authenticity_token');
s.setAttribute('value', '31M3q8SJkRz7f0R80l42Z2W7O2N7ZrzufhWQYql/Zd8=');
f.appendChild(s);
f.submit();
return false;"
href="/transactions/1015/transcribe"
>
Enter Data
</a>
Now, for whatever reason, IE (both 7 & 8 - the two I've tested) has decided that the return false; at the end there isn't enough to stop it from following the link, and I end up getting two requests to my server: The POST request from the onclick handler, which I want, and the GET request from the link itself, which I don't. In fact, that route doesn't exist for anything other than a POST request, so when the browser follows the GET request, the user gets dumped on a 'Bad URL' error screen. Not good.
Has anyone seen this before, and can tell me what's causing it? Or, better yet, does anyone know a good workaround?
PS: I'd prefer NOT to
Monkey-patch link-to, or
Write my own version of link_to
but if that's what it takes, that's what it takes. And I'm using jQuery 1.5.something, if that helps.
In general, when IE decides to "ignore" a return false; from an onclick handler, it is because one of the lines before the return false; threw an exception. This will cause a silent failure of the onclick handler, and the browser will then attempt to access the href link. This applies to all browsers, not just IE, but it's often the case that IE will throw exceptions in cases where other browsers will not, hence why it seems that only IE is ignoring the return false;.
One quick patch for this is to set href="#", which will keep the browser on the page even if the onclick handler fails. The proper way to debug it, however, is to wrap your onclick code in something like try { ... } catch (ex) { alert(ex); } to see what the exception is, and then fix the onclick code so that it no longer throws the exception.
To prevent form submission in JQuery, we often use
event.preventDefault();
So in your example, you could use this (as discussed in comments) :
$('a[onclick]').click(function(e) {e.preventDefault();});
Hope that helps!
I have had this problem with IE before, and found that a solution that works (which I believe is what jQuery's event.preventDefault() does under the covers), is to do BOTH return false; for normal browsers, but also event.returnValue = false; (before the actual return, obviously) for IE. IE will respect that.
Unfortunately though, I don't know how to slip that into the link_to helper without hacking it. That's actually what I came here looking for. :)
I believe that the problem that you are submiting your new form:
f.submit();
and you are submiting it right to your link href
f.action = this.href;
so you are folowing to this address. Your link returns false, but submited form leads you to this location.
So your link_to is ok. Problem is inside of your strange javascript.
I have a page with a dropdown. The onchange event calls a Javascript function (below) that includes an Ajax block that retrieves data and populates a TEXTAREA. On the surface, everything works.
I can select any item in the list with no problems. However, if I select an item that has previously been selected, the Ajax call appears to hang. It looks like maybe some weird caching issue or something. If I close the browser and reload the page, all items work again until I re-select.
I've tested for the readyState and status properties when it's hanging, but I get nothing. Am I missing something?
The page is a client project behind authentication so I can't post a URL, but here's the Ajax code. This is in a PHP page, but there's no PHP script related to this.
function getText( id ) {
var txt = document.getElementById( "MyText" );
txt.disabled = "disabled";
txt.innerText = "";
txt.className = "busy";
var oRequest = zXmlHttp.createRequest();
oRequest.open( "get", "get_text.php?id=" + id, true );
oRequest.send( null );
oRequest.onreadystatechange = function() {
if( oRequest.readyState == 4 ) {
if( oRequest.status == 200 ) {
txt.innerText = oRequest.responseText;
} else {
txt.innerText = oRequest.status + ": " + oRequest.statusText;
}
txt.disabled = "";
txt.className = "";
oRequest = null;
}
}}
Edit: The code block seems a little quirky; it won't let me include the final } unless it's on the same line as the previous.
You're setting the onreadystatechange function after you're sending the request. If it takes a long time (ie if it goes to the server), this will probably work, since there will be a delay before it tries to call the callback.
If the page is cached, though, the browser is probably trying to call onreadystatechange immediately in the send method. Move your assignment to onreadystatechange to before the open/send code.
HI,
The caching is due to the same url thats being called repeatedly. If you change the URl dynamically then this issue can be rsolved. Something like by adding a querystring with the current time with the request ( or any random renerated number ) you can change the url without affecting the result
I would guess that you are running into a caching issue. I have noticed that Internet Explorer is more aggressive at caching ajax calls than Firefox is. One way to be sure of what is happening is to use Fiddler2. This application monitors your web traffic, and you would be able to see if the browser is making a request or not, and what cache headers are coming back on the responses that you do get.
You can download fiddler2 from http://www.fiddlertool.com/fiddler/