First of all I'm sorry for the really vague title, but I have no clue how to name the title. So if someone has a better name, please let me know and I'll edit it.
I have made some sort of a calculator, where the cost of ownership gets calculated. The input of values comes from the user or a preset from a database. The presets can be chosen with a select, and I use the onchange-event to change input data.
<select id="myID" onchange="getPreset(this.value)">
<option>Some options...</option>
</select>
In the getPreset() function I do some stuff + I call another function which I use to get the data from a database via JSON.
function getInfo(name){
var xmlhttp;
if(window.XMLHttpRequest)
{
xmlhttp = new XMLHttpRequest();
}
xmlhttp.onreadystatechange = function()
{
if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
var info = JSON.parse(xmlhttp.responseText);
//process data
calculate();
}
}
xmlhttp.open("GET", "myphppage.php?name="+name, true);
xmlhttp.send();
}
This is how my code is now and it works fine and as it should. But before I had placed calculate(); after xmlhttp.send();, which didn't work as it should have. The data got calculated only AFTER I chose another option. For example: first time I chose option 1 - nothing happens. Second time I chose option 2 - data gets calculated like option 1 is chosen.
I get that it was just the wrong place to put the function, but here's what I found strange: if I put an alert before the calling of the function, the data did get calculated. So my code was as following (so you can see it visually):
xmlhttp.onreadystatechange = function()
{
if(xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
var info = JSON.parse(xmlhttp.responseText);
//process data
}
}
xmlhttp.open("GET", "myphppage.php?name="+name, true);
xmlhttp.send();
alert("make it work.");
calculate();
}
As I have no idea why this is and I'm curious to know, I'm asking it here. I hope someone can help me explain.
It's because of everything is asynchronous. While the alert pops up you (eventually) get the data and it's calculated correctly. That's why it works. If the connection is veeeery slow or you click 'ok' on the alert button extremely fast, it might fail. That's why you should put it in the correct place :)
Related
Came here again with lame questions as I am in process of learning/coding.
I would like to change a property of a disable value on button: During function performing its job, button should be disabled, once function finishes and return the values, button should be enabled again.
In function which creates a buttons I am calling update() function which loading php file via XMLHttpRequest. Then running the php code and return values on page. I want to have button disabled during this time. But everytime I call the function the button will not change. Or if changed it was so fast that I didnt even saw it.
here is a code:
global_button = document.createElement("button");
// let btn1 = document.createElement("button");
global_button.innerHTML = "UPDATE";
global_button.id = "update";
global_button.disabled = false;
document.body.appendChild(global_button);
document.getElementsByClassName("two")[0].append(global_button);
global_button.addEventListener("click", function () {
console.log("After CLICKED");
global_button.disabled = true;
update();
global_button.disabled = false;
console.log("AFTER FUNCTION RETURN VALUES");
update function:
var xmlhttp;
function loadFile(file, func){
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = func;
xmlhttp.open("GET", file, true);
xmlhttp.send();
}
function update(){
loadFile("update.php", function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("content").innerHTML = xmlhttp.responseText;
}
});
}
When I checked the console, it shows both console logs immediately: "After CLICKED" and "AFTER FUNCTION RETURN VALUES" messages. And couples seconds later, result of the function appear. But button wont change whatsoever.
I am suspecting the sync/async functions ? I read something for the .open method and vale true/false, but nothing changed if I switched from true to false. Also thinking if I should put it on the loop or something which will check the button clicked ? But I thought that listener would do the job.
Can anybody check and give me an advice ? or correct my thinking if it's wrong?
many thanks all of you. :)
The problem is indeed due to the asynchronous nature of the send method of XMLHttpRequest - and therefore of your update, which calls it.
When you call update(), which itself calls this:
loadFile("update.php", function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("content").innerHTML = xmlhttp.responseText;
}
});
all that happens is that you set up an XMLHttpRequest object and use its send method to send a request, telling it to call this function:
function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("content").innerHTML = xmlhttp.responseText;
}
});
as a "callback" when the readyState changes. (And in particular, when the request is complete and a response received.) But calling update does not wait for that state change to happen and block your code from running - hence the next lines of code, which set the disabled state of the button to false and log to the console - are executed straight away. So the button gets disabled but then instantly un-disabled, and therefore you never see it disabled. (In fact the browser will never even "paint" the screen with a disabled button, since it doesn't get a chance to do this while your code is running, so even if you could in theory do a freeze-frame here you would never see a disabled button.)
To fix it, you have to work with the asynchronous code you're using. Anything you want to happen after the state change has to take place in the callback function you pass it. So you can simply fix your problem by changing the update definition to this:
function update(){
loadFile("update.php", function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("content").innerHTML = xmlhttp.responseText;
global_button.disabled = false;
console.log("AFTER FUNCTION RETURN VALUES");
}
});
}
and delete those two lines of code from the place you've currently got them, after the update call.
Although note that this will only work if global_button is in scope inside update, which it might not be depending on how your code is structured (it probably shouldn't be to be honest). And even if it does, it's not good to hardcode your update to always undisable the button afterwards, with no guarantee the button will even be disabled first.
It's therefore better to define update to itself take a callback function:
function update(callback){
loadFile("update.php", function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("content").innerHTML = xmlhttp.responseText;
callback();
}
});
}
and then call it like this in your main code:
global_button.disabled = true;
update(function() {
global_button.disabled = false;
console.log("AFTER FUNCTION RETURN VALUES");
});
because this separates the concerns of update itself ("make this request and set the content inner HTML to the response"), from whatever you might want to do afterwards, which could be different each time.
Finally, I can't not mention that this callback-based asynchronous code is very old-fashioned now. XMLHTTPRequest itself is quite a cumbersome API. I highly recommend you look into its modern equivalent, fetch, which is based on Promises - which while not without their mental gotchas are a much more understandable way to write asynchronous code. In particular with async and await you can write code that looks much like what you originally had: putting await update(); would actually do what you are waiting, and have the rest of your code wait for update to complete. But you can't just make that change to your original code because that only works if update returns a Promise, which in turns would mean completely rewriting your loadFile to use a more modern, Promise-based approach.
My project is on JSF2 and I am trying to pull some reference data from the Server to be used in an Input (text) field on the front end.
Using the following link as the starting point
https://www.w3schools.com/howto/howto_js_autocomplete.asp
Instead of using the Array of fixed values (Strings), I want to fetch the data dynamically from the Server. Here is my code that attempts to achieve the purpose:
var constituencies;
function retrieveConstituencies(){
/* Load constituencies dynamically */
var mde=document.getElementById("mode").value;
alert("mode is "+mde);
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
constituencies = this.responseText;
alert(constituencies);
}
};
xhttp.open("GET", "/NominateServlet?mode="+mde, true);
xhttp.send();
}
And here is my final code that calls the autocomplete function (similar to the example in the link provided above)
autocomplete(document.getElementById("vsInput"), constituencies);
I am badly stuck on this problem from last 3 days and the autocomplete method just does not takes the AJAX values. If anyone has solution for this, kindly share.
PS: I am not using PrimeFaces or JQuery because I want to use vanilla technologies.
Many Thanks
XMLHttpRequest makes an asynchronous request. The "autocomplete" function is called before the request completed and the "constituencies" variable is set. You should call the "autocomplete" function after request to API is completed. Try like this:
if (this.readyState === 4 && this.status === 200) {
const items = JSON.parse(this.responseText);
const input = document.getElementById("vsInput");
autocomplete(input, items);
}
I managed to get an autocomplete function to a form input with Maptiler API (OSMNames) (since I find Google Maps API even more confusing).
So here comes the actual problem, I would like to get the driving distance between two places I entered with the help of the autocomplete functions in the two inputs I have created.
I am trying to do so with the OSRM (Open Source Routing Machine) API
Here are my current scripts:
<!--AUTOCOMPLETE-->
<script>
var autocomplete = new kt.OsmNamesAutocomplete(
'search1', 'https://geocoder.tilehosting.com/', '#My_Maptiler_API_Code');
</script>
<script>
var autocomplete = new kt.OsmNamesAutocomplete(
'search2', 'https://geocoder.tilehosting.com/', '#My_Maptiler_API_Code');
</script>
<!--GET INFO-->
<script>
function loadXMLDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("result").innerHTML =
this.responseText;
}
if (this.readyState == 4 && this.status == 429) {
document.getElementById("result").innerHTML =
"Servidor sobrecargado, inténtelo más tarde."
}
};
xhttp.open("GET", "http://router.project-osrm.org/table/v1/driving/{longitude1},{latitude1};{longitude2},{latitude2}", true);
xhttp.send();
}
</script>
First, I need to get the coordinates of the places from the inputs with the help of the autocomplete function.
Currently, when the user clicks on one of the suggested places on the list, just the name item gets written in the input box. Instead, I would like to get the GPS coordinates written, not the name, so that I can use them to send the HTTP request (next step).
What is being written when I click:
What I need for the next step:
Btw, I have seen some answers in other related questions inviting to use "Nominatim". As I said, I am currently using "OSMNames", is there any difference? Should I change my geocoder?
Then, I would also need to get these coordinates in the HTTP GET request, as shown on the code.
And finally, I would like to get just one of the items from the OSRM response, the distance. Since otherwise, I would just get the entire response.
I have literally no idea on how to do any of the stated steps since I am a student that is still getting started on this area.
If only you could lend me a hand here it would be excellent.
I try to avoid putting all the code here because I find it confusing when reading but should you need the rest of the code for any reason, please let me know!
Thanks for your help! :)
This is my first question here so I will start by saying: Hello to everyone!
I am trying to make a live data "presentation" in the form of a fancy table using straight JavaScript and Ajax, backend is PHP. In order to refresh the table I need to make requests at every, lets say 3 seconds, 4 is ok to. The database is RedisDB. I made the php script to fetch the data and its ok. I made a single JS file to request and handle/process the data and it's sort of ok.
The presentation looks great and the algorithm that is written in JS works excellent, it's about 600 lines, some simple if-else's and switches other a little more complex.
It now gets nasty. I can't get the freaking thing to do this continuously, I tried ways with setTimeout() and setInterval(), I made timers and infinite loops with sleep-like functions and so on, but it just can't survive that next request after the initial when the page loads.
The code for Ajax request is pretty straightforward for pure JS. I get my JSON string data parse it with jsonParse() and then do my processing of the data.
This all works, it's the next request that fails, no matter how it's initiated (user action or something else).
AJAX code:
window.onload = function(){
getEventdataFromDB();
}
function getEventdataFromDB(){
var xmlhttp;
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
}
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
var dbData = xmlhttp.responseText;
if(dbData != ''){
processEvents(dbData); //function for data processing
}
}
}
xmlhttp.open('GET','getEvents.php?dataRequest=true',true);
xmlhttp.send();
}
I know that it's a bit of a sin these days not to follow the flow and use jQuery and other frameworks but I'm just not big on the latest and greatest simplification of stuff that works just fine, to begin with.
What is the best way to do this, how should I proceed, what to use. I did some researched and things point to chaining callbacks and Promise objects.
There is obviously no way that I am the first one to do this so what is the way forward here.
The only way to ensure the previous request is over before starting the next one is so start the next call from the onreadystatechanged event of the previous one. Because ajax runs asynchronously, there's no guarantee whether any other code you run will execute before or after the ajax call finishes.
So you need to re-organise your script a bit:
var xmlhttp;
window.onload = function(){
setupAjaxObject();
getEventdataFromDB();
}
function setupAjaxObject()
{
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
}
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4){
if(xmlhttp.status == 200){
var dbData = xmlhttp.responseText;
if(dbData != ''){
processEvents(dbData); //function for data processing
}
}
getEventdataFromDB(); //run the next request
}
}
}
function getEventdataFromDB(){
xmlhttp.open('GET','getEvents.php?dataRequest=true',true);
xmlhttp.send();
}
If you wanted a little delay between the requests, you could wrap the call to the next request inside a timeout.
i have been trying very unsuccessfully to download a binary file from my server using jquery-ajax, which i finally gave up. so now i am trying to use XMLHttpRequest instead. however, i cannot even get a simple example working.
strangely enough, this code does not appear to do anything. i copy/pasted this from w3schools and this example is near identical to many other examples. it does not work for me in either chrome or FF:
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
// Action to be performed when the document is read;
}
};
xhttp.open("GET", '/blah/blah/output.png', true);
xhttp.send();
we go into the onreadystatechange function only once, on the open() statement with an xhttp.readyState equal to one, but not on the send() step. i should think it would at least throw some kind of error rather than do nothing at all.
also, as an experiment, i purposely fed the open() a bad url - but again no reply.
can anybody tell me what i might be doing wrong?
thank you very much.
Your code looks correct to me, which points to some external cause.
Is your code flowing all the way through to the end of the execution context? Browsers will hold onto network requests until the engine yields back to the browser.
For instance:
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
// Action to be performed when the document is read;
}
};
xhttp.open("GET", '/blah/blah/output.png', true);
xhttp.send();
while(true){}
will never send the call.