Lines of code before AJAX/XMLHttpRequest Call not executed - javascript

Here is the following code I have in Javascript:
document.getElementById("button").disabled = true;
document.getElementById("button").innerHTML = "Please Wait...";
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "MoodInput"+ "?moodValue=" + input, false);
xhttp.send();
When I submit the form to the Servlet, it seems like the xhttp.send() function executes first. However, I would want the the following two lines to be executed first:
document.getElementById("button").disabled = true;
document.getElementById("button").innerHTML = "Please Wait...";
What should I do to solve the problem? It has to be synchronous, because there is a thread.sleep method in the servlet in order for the Arduino to be connected with the Serial Port and set up.

While a JavaScript function is running, browsers won't do very much at all, and that includes repainting the DOM.
Your code is running in the order you want, and the DOM is being updated, the page just isn't being repainted with the changes you made.
It has to be synchronous
Synchronous XMLHttpRequests are deprecated because they cause the browser to lock up while it waits for the response. i.e. because they cause the problem you are experiencing.
because there is a thread.sleep method in the servlet in order for the Arduino to be connected with the Serial Port and set up.
That will not be affected by using a synchronous or asynchronous request.
You are probably wanting to run some other JS that you left out of your question after the response has been received.
If so, the real solution is to take whatever it is you want to do after the request has completed and move it to a function that you assign as the XHR object's load event handler.

button input type="button" does not use innerHTML for the text it uses value:
document.getElementById("button").value = "Please Wait...";
Are you using an input or a button element?

Related

In a node.js API how do I perform tasks that must be synchronous without freezing the browser?

To start off this is what I am trying to accomplish:
I am trying to do file copies to an array of servers. There are several steps that must be completed in a specific order before and after these copies (for example, stopping IIS, backing up and clearing folders, running a bat file, etc) so they are not single operations.
To make this super easy I wrote an API in node.js that does simple tasks like copy files and folders, delete folders, etc. I then wrote a frontend in node.js using an express generator and Pug that uses javascript XMLHhttpRequests to send commands to the API depending on what I needed to do. I have the API written and running as well as the frontend. Now on to the problems:
If I have my XMLHttpRequest run in synchronous mode (example: xhttp.open("POST", url , false);) when the command is sent to the API to copy a folder if the folder takes several minutes to copy the browser freezes. Chrome displays a "Page Frozen" error. However, the job gets done correctly.
If I have my XMLHttpRequest run in asynchronous mode (example: xhttp.open("POST", url , true);) then every command gets sent to the API at once so that the fastest operation completes first and the commands are out of order. The copy will fail.
I've tried searching for a way to make it so that each operation sent from the frontend javascript has to return a SUCCESS (or 200 response) from the API before moving on to the next command but so far all I've seen is "just use synchronous". Right now that's what I'm doing. That doesn't seem like the best solution even though it works. Is there a better way to do this in a way that won't freeze the browser?
I figured this out by writing a function to handle the requests, setting a counter (for the steps of the process), and putting a switch statement in the if statement for the result. It wasn't exactly what I needed but the basics of my solution is in the answers to this question: How can I call ajax synchronously without my web page freezing
Here's what I did in case it helps anyone else who finds this question:
function myFunction (step, params, url) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
switch(step) {
case 2:
//url and params are set here, and step 2 is done here
myFunction(step, params, url);
break;
case 3:
// and so on and so forth
}
}
xhttp.open("POST", url , true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send(params);
step++;
}
//kick off the function
var step = 1;
var url = "my URL to the API with call";
var parameters = "my parameters";
myFunction(step, parameters, url);

URL Redirect in a Loop

I am using a java script in php to redirect a URL. This works for me because each time the loop is run, the link opens in a new window and the desired action takes place. However I want to stop the script from opening new windows and run / load within the same page. If I open the link the same page, it redirects to the new page in the first run and the loop does not run further.
I have no control over the next pages as they are part of an API. I do not actually want to navigate to the new page(s) but I just want to run the http:// API, which may even run in the background or something.
Please advise on what would be the best method to handle this ?
This is my current script:
<?php
$x1=$_POST["textfield1"];
$msg = "New Message Alert From $x1. blah blah";
$query = "SELECT * FROM phone_list";
$result = mysql_query($query);
$num=mysql_numrows($result);
$i=0;
while ($i < $num)
{
$f1=mysql_result($result,$i,"phone");
echo'<script> window.open("http://linktonextpage&msg='.$msg.'&num='.$f1'"); </script>';
$i++;
}
?>
Thanks in Advance !
As you're discovering, once you move from one page to another at that point the previous page is gone from the browser. JavaScript won't continue to run from pages that are no longer loaded.
I do not actually want to navigate to the new page(s) but I just want to run the http:// API, which may even run in the background or something.
Then don't navigate to the page. Instead, make an AJAX request to the desired URL. Something as simple as this:
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
// This function is called when the AJAX request completes.
// Here you would check for errors or respond in some way, if needed.
};
xhttp.open('GET', 'http://someurl', true);
xhttp.send();
As long as you're not making too many concurrent requests, you can run that in a loop. Just enclose it in a function:
function sendRequest(url) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
// This function is called when the AJAX request completes.
// Here you would check for errors or respond in some way, if needed.
};
xhttp.open('GET', url, true);
xhttp.send();
}
And call that function in a loop over your urls:
for (var i = 0; i < myUrls.length; i++) {
sendRequest(url);
}
You can get a lot fancier with this pretty easily, passing the callback function into the sendRequest() function or having sendRequest() return the AJAX promise or lots of other things. It's up to you what further features you want to add. The main point here, in response to your statement above, is simply to make AJAX requests in the background rather than navigate the browser to the URLs.
Note: Currently your loop is server-side, which is emitting a lot of repeated code to the browser. You can probably just emit the JSON-encoded values and perform the loop client-side as demonstrated above. Or, if you really want to loop server-side, then just define a function like the one above and emit calls to that function in a loop. It's still a lot of repeated client-side code, but it'll get the job done.
Another solution - less correct than solution with AJAX,
but very simple:
You can add iframes instead of opening popups.
while(...){
echo '<iframe src="http://linktonextpage&msg='.$msg.'&num='.$f1'." width="100%" height="120"></iframe>';
}
In your code it seems like you want to send messages to all the numbers fetched from database so if you want to use JavaScript you can do as previous answer.
Another way of doing the same is without using JavaScript.
You can also make Curl request to the Api Urls. Within your PHP code without loading the page.
While (condition) { $service_url = 'http://linktonextpage&msg='.$msg.'&num='.$f1'';
$curl = curl_init($service_url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$curl_response = curl_exec($curl);
curl_close($curl);}

How do I call a javascript function immediately from the vb code

This is my sciprt, it display a message box with an 'Ok' and 'Cancel' Button
<script type="text/javascript"> function Confirm() {
var confirm_value = document.createElement('INPUT');
confirm_value.type = 'hidden';
confirm_value.name = 'confirm_value';
if (confirm('Continue?')) {
confirm_value.value = 'Yes';
} else {
confirm_value.value = 'No';}
document.forms[0].appendChild(confirm_value);} </script>
On my program i'm running a query, if there are no results then i display this "Dialog" box
I want to call the function immediately after getting the query results but my current code seems to be running it after everything instead of immediately.
If reader.read = false then
If Not Page.ClientScript.IsStartupScriptRegistered(Me.GetType(), "alertscript") Then
Page.ClientScript.RegisterStartupScript(Me.GetType(), "alertscript", "Confirm();", True)
End if
Dim confirmValue As String = Request.Form("confirm_value")
If confirmValue = "Yes" Then
'Do stuff here
End if
End if
To me, this request usually represents a misunderstanding of what's going on. At the time your VB.Net code is running, the javascript doesn't exist. All server event handlers result in a full postback. That means the entire page is recreated from scratch. The VB.Net code here is part of a process that is generating an entirely new HTML document. That will involve the entire page lifecycle, including your server's Page_Load code. When the event was raised, any html already rendered in the browser was destroyed to make way for your response to a whole new HTTP request.
If you want this to respond differently, you need to build your whole HTTP response with that in mind. That means either changing how the event is raised from the outset (calling a WebMethod or other ajax request) or setting your response to call your confirm method in the javascript page load event.

Multiple xhr onload

I have this simple code for get elements from a external source
for(var i=0; i<10; i++)
loadPage(link[i]);
function loadPage(href)
{
var ajax = new XMLHttpRequest();
ajax.open('get',href);
ajax.responseType = 'document';
ajax.onreadystatechange=function()
{
console.log(ajax.responseXML.querySelectorAll("a[href^='magnet']")[0].getAttribute("href"));
}
ajax.send();
}
but when i read the console i get only 2 or 3 result instead of 10. i think is because i can't run multiple onload. How i can fix this?
By onload, you mean multiple ajax.send? that is likely not the problem.
Could is simply be that the returned ajax isn't returning something that matches your selector (magnet) or that your server doesn't answer properly to all requests? replace your console.log with a simple console.log ("Here be dragons");
If you ajax fetch pages from the same server, you should check the logs see how many requests do you have, and if you always reply correctly. Some servers will return at 50x error when too many requests in parallel, or put a breakpoint in your loadPage function, the pause is going to be enough to let the server process everything in time.

Synchronous cross domain javascript call, waiting for response - is it possible?

Disclaimer
Firstly, a disclaimer: I am working within specific boundaries, so whilst it may seem I'm going about something the long way round, I am limited as to what I can do. I know I should be doing this entirely differently, but I cannot. If it's not possible to do what I'm trying to do here, then that's fine, I just need to know.
Background
Basically, this boils down to a cross-domain javascript call. However, I need to wait for the response before returning the method.
Say I have a page - example1.com/host.html. This contains a javascript method of 'ProvideValue()' which returns an int. Edit: This method must be executed where it is found, since it may need to access other resources within that domain, and access global variables set for the current session.
https://example1.com/host.html
function ProvideValue(){
return 8; // In reality, this will be a process that returns a value
}
This host.html page contains an iframe pointing to example2.com/content.html (note the different domain). This content.html page contains a method that needs to display the value from host.html in an alert.
https://example2.com/content.html
function DisplayValue(){
var hostValue = //[get value from ProvideValue() in host.html]
alert(hostValue);
}
That's it.
Limitations
I can run any javascript I like on the host.html, but nothing server-side. On content.html I can run javascript and anything server-side. I have no control over the example1.com domain, but full control over example2.com.
Question
How can I retrieve the value from ProvideValue() on example1.com/host.html within the DisplayValue() method on example2.com/content.html?
Previous Attempts
Now, I've tried many of the cross-domain techniques, but all of them (that I've found) use an asynchronous callback. That won't work in this case, because I need to make the request to the host.html, and receive the value back, all within the scope of a single method on the content.html.
The only solution I got working involved relying on asynchronous cross-domain scripting (using easyXDM), and a server-side list of requests/responses in example2.com. The DisplayValue() method made the request to host.html, then immediately made a synchronous post to the server. The server would then wait until it got notified of the response from the cross-domain callback. Whilst waiting, the callback would make another call to the server to store the response. It worked fine in FireFox and IE, but Chrome wouldn't execute the callback until DisplayValue() completed. If there is no way to address my initial question, and this option has promise, then I will pose this as a new question, but I don't want to clutter this question with multiple topics.
Use XMLHttpRequest with CORS to make synchronous cross-domain requests.
If the server doesn't support cors, use a proxy which adds the appropriate CORS headers, e.g. https://cors-anywhere.herokuapp.com/ (source code at https://github.com/Rob--W/cors-anywhere).
Example 1: Using synchronous XHR with CORS
function getProvidedValue() {
var url = 'http://example.com/';
var xhr = new XMLHttpRequest();
// third param = false = synchronous request
xhr.open('GET', 'https://cors-anywhere.herokuapp.com/' + url, false);
xhr.send();
var result = xhr.responseText;
// do something with response (text manipulation, *whatever*)
return result;
}
Example 2: Use postMessage
If it's important to calculate the values on the fly with session data, use postMessage to continuously update the state:
Top-level document (host.html):
<script src="host.js"></script>
<iframe name="content" src="https://other.example.com/content.html"></iframe>
host.js
(function() {
var cache = {
providedValue: null,
otherValue: ''
};
function sendUpdate() {
if (frames.content) { // "content" is the name of the iframe
frames.content.postMessage(cache, 'https://other.example.com');
}
}
function recalc() {
// Update values
cache.providedValue = provideValue();
cache.otherValue = getOtherValue();
// Send (updated) values to frame
sendUpdate();
}
// Listen for changes using events, pollers, WHATEVER
yourAPI.on('change', recalc);
window.addEventListener('message', function(event) {
if (event.origin !== 'https://other.example.com') return;
if (event.data === 'requestUpdate') sendUpdate();
});
})();
A script in content.html: content.js
var data = {}; // Global
var parentOrigin = 'https://host.example.com';
window.addEventListener('message', function(event) {
if (event.origin !== parentOrigin) return;
data = event.data;
});
parent.postMessage('requestUpdate', parentOrigin);
// To get the value:
function displayValue() {
var hostName = data.providedValue;
}
This snippet is merely a demonstration of the concept. If you want to apply the method, you probably want to split the login in the recalc function, such that the value is only recalculated on the update of that particular value (instead of recalculating everything on every update).

Categories