I have the following code setup on a webpage(private at this time):
function DoRequest(httpReq,url,param){
httpReq.open("POST",url,false);
httpReq.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
httpReq.send(param);
httpReq.onreadystatechange = function() {
if (httpReq.readyState==4) {alert(httpReq.responseText);}
}
if(httpReq.status==200){
return httpReq.responseText;
} else {
return httpReq.status;
}
}
When I run a request through this, via firefox, safari, ie 7-9, chrome etc on the pc I get a 200 status and the text back correctly.
When I run this same exact page on my iphone, or ipad, I get a status of 0, response text of nothing, and an alert from that callbackfunction of the correct response text afterword. Which seems like it is not waiting for the request to finish before proceeding through the code for the mobile safari browsers, is there anyway to better force it to wait, or a flag I'm blind to see?
I also only get the onreadystate callback on safari, it doesn't do it in any other browser, I tried removing the function in case that was somehow triggering it to run async instead of of not but no dice there it still runs async despite the 3rd parameter being false.
I also just tried httpRq.open("POST",url); without the 3rd parameter and without the onreadystatechange function and still runs async.
The url is an absolute path.
Mobile Safari does not support synchronous use of XMLHttpRequest (third parameter to open is false in your code, which is unsupported).
Anything that depends on the results of the request should get moved into a callback function, and called in your onreadystatechange function right where you have the alert() call.
Related
I have an Angular SPA I'm running with Angular Loading Bar and AngularJS v1.4.9.
For some time now, it has been so happening that after the app gets loaded, the bar has been getting stuck after a while, indicating that not all requests are done with. Additionally, one of the console.log()s I have in our code have been firing continuously, around 1-2 times every second. The bar completes and the console.log works normally when the user reloads the page(but doesn't stop on its own).
The console.log() is set inside a function attached to a ng-disabled directive, so I know it's an indicator of a digest cycle in progress.
I use Chrome as my browser and I recently did a profiling run.
Here's some screenshots of what I see:
This is a broad view. As is shown here, it's first happening at 100ms, then at 400, then at 600, and so on(I did a 3s run).
This is the very first vertical strip. Not all of them look exactly the same as this one, but the completeOutstandingRequest, timeout and Browser.self.defer methods are always there. The searchDisable and log methods are ours, the log is the one I'm talking about above.
Here's another one for comparison, but this is slightly different - it has another Browser method: self.url. I'm not sure what it does.
Here are some issues I found which could be related:
Timeout callback can occur in the middle of a digest cycle in Firefox
$browser.defer ends up triggering changeDetection in zonejs through settimeout
P.S. I think this issue first started when we added some interceptors to our code to do some automatic redirects - e.g. when the session has timed out and the user clicks on something, he's automatically returned to the login page to relogin.
This is the interceptor:
interceptor.$inject = ['$rootScope', '$q'];
function interceptor($rootScope, $q) {
return {
responseError: function (rejection) {
var config = rejection.config || {};
if (!config.ignoreAuthModule) {
switch (rejection.status) {
case 401:
var deferred = $q.defer();
$rootScope.$broadcast('event:auth-loginRequired', rejection);
return deferred.promise;
case 403:
$rootScope.$broadcast('event:auth-forbidden', rejection);
break;
}
}
return $q.reject(rejection);
}
};
}
$httpProvider.interceptors.push(interceptor);
This issue has been solved.
It turns out that in case of any Unauthorized requests, the promise that is returned on line 11 above was remaining pending forever, because there was no call to .resolve() or .reject() in the deferred object.
As a result, the loading bar's interceptor was blocked.
I ended up removing the custom promise entirely and that solved the problem.
All:
I have an Iframe tag on a simple HTML page and inside this Iframe tag is a HTML form - lets call it a widget. Its a form where the user can enter search criteria and click on a button to obtain the search results. I have decided to use Angularjs to make the necessary DB calls to a REST service that returns the search results back to the widget for display.
In testing this I enter a value in a textbox on the widget, that value being a value that I know exists in a particular table I'm testing against.
Here is my $http get call:
$http
.get('http://localhost/XXXXService/folder/getfolders/' +
$scope.formData.srchterm **==>** mapped to search textbox
).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
//$scope.formData = response;
//$scope.nrdFolderDataArray = response;
console.log('Success retrieving data.');
console.log(response.length);
console.log('response:');
console.log(response);
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
console.log('Error occurred retrieving data.');
console.log(response.status);
console.log('returned data count:');
console.log(response.size);
console.log('response:');
console.log(response);
});
This call is inside a function called "submitForm" that is mapped to the widget with a "ng-submit="submitForm()" attribute on the submit button. And yes there are several log statements so I can try and figure out what is going on here. And what is happening is this: after entering a value in the textbox, THE FIRST TIME the search button is clicked the .get command does not work. I does not make the call to the REST service. I know this because I wrote the REST service and made sure I put in plenty of log statements while doing so and there are no log statements in the log file from the REST service. Instead the errorCallback block runs and I see all those log statements in the console. The "response" (object?) after THE FIRST call looks like this:
Object {data: null, status: 0, config: Object, statusText: ""} Method = GET Status = (canceled) type xhr
Further, in FF there is no response data to view in the Net tab of Firebug upon THE FIRST call, but there is response data to view in all subsequent calls.
So, interestingly enough each subsequent invocation of that $http.get call works! I see log statements in the log file from the REST service method and the successCallback block runs and I can see my data via those console.log messages.
Also, if I were to change the search value in the text box, which would then be THE FIRST TIME we would be searching for data for that new key, once again, the call does not work, but does work on subsequent clicks on the "search" button for that new key value.
I really am not sure if I have a CORS issue here since, other than THE FIRST calls each subsequent $http.get call works like a champ. Its just that very first call or first call after the search key has changed that the $http.get does not want to work.
I have tried setting headers in the .get call and I have tried using
#CrossOrigin(origins = "http://localhost/7001") as per
https://spring.io/guides/gs/rest-service-cors/ but I continue to have this issue on the first time invoking this .get call.
I've been dealing with this issue for way too many hours now and would sure appreciate some input as to why this is happening.
I'm sorry for being verbose here. I wanted to explain my issue thoroughly.
Please help.
Thank you
-g
I have a function in an angular factory that gets invoked when my page is loaded. There's a controller which invokes this factory method.
Looks something that looks like this.
factory.getData = $http.post('/LocationOfData/Here').
then(function(response) {
// stuff happens here when successful
}, function (response) {
console.log('an error has occurred');
});
I noticed that my page works correctly as in //stuff happens here when successful gets hit... but only when the page fully loads.
If I load my page and then very quickly click on a link taking me to a different page within my app, an error occurs. (as in the console.log.)
This only seems to happen in FireFox. everything works ok in Chrome.
Any suggestions on what I should change or look out for?
EDIT: The response Object is
Object { data: null, status: 0, headers: headersGetter/<(), config: Object, statusText: "" }
Normally in JavaScript while when the page is loading if you are injecting any scripts it will consider it as one of the parallel process,if you disabled the cache of the browser it will not consider the parallel process and it will kill the process,in your case while the page load you are doing a service call and the call will be treated as a separate thread or process in chrome if you are not disabled the cache,you may get the service to fail in Chrome as well if you disabled the cache
Its an assumption only,may help:)
In my AngularJS application, for any page to load, there are two things which are loading
First the content of the page and secondly some back-end resources.
While back-end resources are loading, a spinner comes in the front and user is not able to do anything on the page contents.
Now while I am writing the automation test suites of the application using Protractor, I am not able to find a technique, to wait for the spinner to disappear from the screen before starting the test.
Please help me in this.
IsDisplayed as you mentioned in Andres D's comment should be the right one to use for your situation. However, it returns a promise so you cant just use
return !$('.spinner').isDisplayed()
since that will just always return false.
Try the below and see if it works.
browser.wait(function() {
return $('.spinner').isDisplayed().then(function(result){return !result});
}, 20000);
If you are waiting for something to happen you can use browsser.wait()
For example, if the spinner has the class name "spinner"
browser.wait(function() {
// return a boolean here. Wait for spinner to be gone.
return !browser.isElementPresent(by.css(".spinner"));
}, 20000);
The 20000 is the timeout in milliseconds.
Your test will wait until the condition is met.
For those dealing with non-angular apps:
browser.wait(
EC.invisibilityOf(element(by.css(selector))),
5000,
`Timed out waiting for ${selector} to not be visible.`
)
https://www.protractortest.org/#/api?view=ProtractorExpectedConditions.prototype.invisibilityOf
I'm trying to write a restartless add-on for Firefox Mobile that will insert content onto specific web pages. It all seems to work OK until I try disabling then re-enabling the add-on, at which point I get multiple responses to the page load event, and I can't figure out a way to sort them out.
Since Fennec uses the Electrolysis multi-process platform, I know that I need to split my code into chrome and content scripts. My bootstrap.js looks something like this (trimmed for clarity):
function startup(data, reason) {
mm = Cc["#mozilla.org/globalmessagemanager;1"].getService(Ci.nsIChromeFrameMessageManager);
mm.loadFrameScript(getResourceURISpec('content.js'), true);
}
function shutdown(data, reason) {
let mm = Cc["#mozilla.org/globalmessagemanager;1"].getService(Ci.nsIChromeFrameMessageManager);
mm.sendAsyncMessage("GeoMapEnh:Disable", {reason: reason});
}
function install(data, reason) {}
function uninstall(data, reason) {}
Basically, the bootstrap.js just launches a content script, and sends a message to tell it to clean up on shutdown. The content.js sets up an eventListener to watch for page loads, that looks a bit like this:
addMessageListener("GeoMapEnh:Disable", disableScript);
addEventListener("DOMContentLoaded", loadHandler, false );
function loadHandler(e) {
LOG("Page loaded");
// Do something cool with the web page.
}
function disableScript(aMessage) {
if (aMessage.name != "GeoMapEnh:Disable") {
return;
}
LOG("Disabling content script: " + aMessage.json.reason);
try {
removeEventListener("DOMContentLoaded", loadHandler, false );
removeMessageListener("GeoMapEnh:Disable", disableScript);
} catch(e) {
LOG("Remove failed: " + e);
}
}
function LOG(msg) {
dump(msg + "\n");
var consoleService = Cc["#mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
consoleService.logStringMessage(msg);
}
When I first run the extension, everything works fine. An instance of content.js is executed for each browser tab (and any new tabs I open) and my eventListener detects the page loads it is supposed to via the DOMContentLoaded event. When I disable the extension, everything still seems OK: page loads stop being detected.
When I re-enable the extension, it all goes wrong. I still get an instance of content.js executing for each open tab, but now, if I open new tabs, DOMContentLoaded triggers mutiple eventListeners and I can't distinguish which one should handle the event. Worse yet, some of the eventListeners are active, but do not give debug info via my LOG function, and do not all of them get removed if I disable the extension a second time.
I do want to watch all browser tabs, including any new ones, but I only want my extension to insert content on the page that triggers it, and only once per page load. I've tried the following without success:
Calling e.stopPropagation() to stop the event being passed to other listeners. No effect.
Calling e.preventDefault() and testing e.defaultPrevented to see if the event has already been handled. It never has.
Testing if (this === content.document) to see if the eventListener has been triggered by its own page content. Doesn't work, as I get multiple "true" responses.
Making the eventListener capturing. No effect.
Using the load event rather than DOMContentLoaded.
I can't set a shared variable to say the event has been handled as under Electrolysis, the different eventListeners will be executing in different contexts. Also, I wouldn't be able to distinguish between multiple tabs loading the same page and one page load being detected multiple times. I could do this via IPC message passing back to the chrome bootstrap script, but I then I wouldn't know how to address the response back to the correct browser tab.
Any ideas? Is this a Firefox bug, or am I doing something silly in my code? I am using Fennec Desktop v4 for development, and will target Fennec Android v6 for production.