I have this function
function Overlap() {
setTimeout(function() {
$(".overlap").each(function(index, object) {
var image = $(this).prev().attr('src');
target = $(object);
var xmlhttp
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if(xmlhttp.status == 200 && xmlhttp.readyState == 4) {
xresponse = xmlhttp.responseText.split('-');
$(target).children('a').attr('href', xresponse[0]);
$(target).children('.name').html(xresponse[1]); //Set returned array appropriately
$(target).children('.age').html(xresponse[2]);
$(target).children('.specialization').html(xresponse[3]);
}
}
xmlhttp.open('POST', 'factory/operational.php', true);
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xmlhttp.send('overlap=overlap&image=' + image);
});
}, 1000);
}
Html:
<div class="Divbox" id="Box_three"><img src='<?php ?>' />
<div class="overlap">
<a href='' class='name'></a>
<div class='age'></div>
<div class='specialization'></div>
</div>
</div>
And it is called by this
window.onload = Overlap();
From the page that uses it
The problem is the function works .. it is usually called properly and i put the
window.onload & setTimeout functionality to make sure that the page loads fully before trying to grab the .overlap element.
Now what is wrong is when overlap is called there are about 48 of the .overlap div element on the page and they all send this request to the operational.php page but, on arrival back they do not appropriate properly, they only appropriate on the last element that comes back from operational.php, can someone help me find the right selector instance to pass to make sure that each instance of the overlap and is children receives the response accordlingly
you missed declaring your target variable, making it global.
target = $(object);
should be
var target = $(object);
without var, every iteration of the loop will use the same target, meaning all xhr request complete callbacks will use the same target.
Example:
$.each(["a","b","c"], function(i,val) {
x = val;
console.log(x); // "a", "b", "c"
});
console.log(x); //"c"
After the each is complete, x will be a global var that contains the value from the last iteration. In your code, you're performing an asynchronous action on each iteration, meaning, the callbacks for each action will happen after the each is complete, which is why target points to the last iteration for all of the callbacks.
Related
I am trying to return a peer comparison table for stocks. How it works is I have one script asking what the comparable companies are for AAPL, and another function that takes that group and grabs the quick ratio for that group, however, I can not seem to figure out how to get the second script to use the responses of the first script.
Script 1 to grab peers.
<script>
function peerGroup() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var peerGroup = JSON.parse(this.responseText);
var peer1 = document.getElementById("peer1").innerHTML = peerGroup[0];
document.getElementById("peer2").innerHTML = peerGroup[1];
document.getElementById("peer3").innerHTML = peerGroup[2];
document.getElementById("peer4").innerHTML = peerGroup[3];
}
};
xhttp.open("GET", "https://cloud.iexapis.com/stable/stock/aapl/peers?token=pk_6925213461cb489b8c04a632e18c25dd", true);
xhttp.send();
};
</script>
Script 2, use script 1 return for ratio
<script>
var peer = peerGroup.peer1
function peerAnalysis() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var peerAnalysis = JSON.parse(this.responseText);
document.getElementById("peer1-quickRatio").innerHTML = peerAnalysis[0]["quickRatio"].toFixed(2);
}
};
xhttp.open("GET", "https://fmpcloud.io/api/v3/ratios/"+peer+"?period=quarter&apikey=4a913b138c66a8ba8885339480785676", true);
xhttp.send();
};
</script>
HTML
<div id=peer1>
</div>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
peerGroup();
},true);
</script>
<div id=peer1-quickRatio>
</div>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
peerAnalysis();
},true);
</script>
You need to store peerGroup in a global variable, like:
window.peerGroup = peerGroup
Then access it like
var peer = window.peerGroup.peer1
NOTE: you are loading two scripts that perform async operations. peerGroup may not be available by the time your second script loads. You can patch it by setting a timeout on your second script. Or - the proper solution - emit an event when you get the peerGroup
Your code contains few bad practices. You can easily incur in race conditions and side effects. My suggestion is definitely to declare a state and change the page accordingly, something like react (maybe redux?) do. You can handle async events and predict what's going on. A plain js implementation like that can become a nightmare, you are even handling DOM directly, this mix can definitely be error prone. That's should be avoided when possible, especially if you expect to make your architecture more complex than that.
https://redux.js.org/advanced/async-actions/
I was able to solve the problem. While I am unsure if it is the best practice for such a thing. I have set the peerGroups to be stored in the sessionStorage and then dynamically call them back on an asynchronous load of the peerAnalysis script.
To be clear my JavaScript code works. I use window.onload to call an initial function that gets the time and date and sends it to a remote server via an XMLHttpRequest. At some point, while debugging, I reduced the initial function simply to display the time and date on the screen, and nothing else.
I found when I did the latter a refresh did not always cause a window.onload even to be called. Even using Crtl+F5 rarely changed the time. Finally put the rest of the code back in (calling the server) and every refresh works every time!
Below is the code that does not seem to call the onload event for every refresh. But if you remove the return statement surrounded by comments...every refresh calls window.onload.
While I shouldn't be complaining that my full code works, I would like to find out why the simple version did not?
<script>
window.onload = loadDoc();
function loadDoc() {
var today = new Date();
var date = today.getFullYear()+'-'+
( (today.getMonth()+1)<10 ? "0"+(today.getMonth()+1) : (today.getMonth()+1) ) +'-'+
( (today.getDate() +1)<10 ? "0"+(today.getDate() +1) : (today.getDate() +1) );
var time = ( (today.getHours())<10 ? "0"+(today.getHours()) : (today.getHours()) ) + ":" +
( (today.getMinutes())<10 ? "0"+(today.getMinutes()) : (today.getMinutes()) ) + ":" +
( (today.getSeconds())<10 ? "0"+(today.getSeconds()) : (today.getSeconds()) );
var dateTime = date+' '+time;
document.getElementById("myBanner").value=dateTime;
///////////////////////////////
return; //////remove this return and every refresh calls this function
///////////////////////////////
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("myBanner").value = this.responseText;
}
};
string = "http://example.com/cgi-bin/perly.pl?b=1&d=" + dateTime;
xhttp.open("GET", string, true);
document.getElementById("myBanner").value="sent";
xhttp.send();
}
Your code does not actually attach an event listener to the onload event handler. Instead, you're setting the value of window.onload to the return value of loadDoc() - which means that loadDoc() is run, to calculate the return value; but it is run as soon at is encountered instead of when onload should be called.
I assume adding the HttpRequest delayed the function long enough to run at the correct timing, wheras the simple code was run before it should have been.
To correctly attach the event, use
window.onload = (event) => { loadDoc(); };
See https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event for reference
Example: loadDoc is run immediately, before myBanner is loaded, resulting in Uncaught TypeError: Cannot set property 'innerHTML' of null
<script>
window.onload = loadDoc();
function loadDoc() {
var mesage = "Hello World"
document.getElementById("myBanner").innerHTML=mesage;
return;
}
</script>
<body>
<div id="myBanner"></div>
</body>
Event Handler is attached properly, loadDoc is run after all elements are loaded:
<script>
window.onload = (event) => { loadDoc(); }
function loadDoc() {
var mesage = "Hello World"
document.getElementById("myBanner").innerHTML=mesage;
return;
}
</script>
<body>
<div id="myBanner"></div>
</body>
I guess your code throws an error that's when it proceeds after the return. I don't know if you already declare this part string = "http://example.com/cgi-bin/perly.pl?b=1&d=" + dateTime; It seems you just used this string but you did not declare it.
I'm trying to load contents through ajax and then perform some click events on those contents.
So basically I want to first load the contents(Buttons in this case) and then apply some click events on them .
and hence I'm using callbacks for the purpose to load the contents first and then apply click events , but here I've a problem that the content is loaded after the callback function, and I don't want this, I want to load the content first then execute callback function, how to solve this problem?
To achieve this till now I've the following code.
I've following code in food.php:
<button onclick="findWeek(fun)">week</button> // fun is callback function passed to findWeek()
// findWeek function ------ AJAX request to load buttons ------:
function findWeek(fun)
{
var xhr = new XMLHttpRequest();
xhr.open("GET" ,"start.php",true);
xhr.send(null);
xhr.onreadystatechange = function(){
if( (xhr.readyState == '4') && ( xhr.status == '200') ){
document.getElementById("stats").innerHTML = xhr.responseText;
}
};
fun();
}
// fun function, is a callback function, and I'm assuming that this will come in action when the findWeek() function load the contents,meaning that it will load the required buttons from the page start.php inserting those buttons to the following div which is inside food.php.
<div id = 'stats'>
</div>
And after that I want to be able to click those loaded buttons then which are supposed to be there in the above div.
That's why I've fun() function something like following.
Note: I've defined class .dayBtns for the loaded buttons.
function fun(){
function myfunction(){
alert('just clicked the button');
}
var dayBtns = document.getElementsByClassName('dayBtns');
alert('contents should be loaded');
for(var i = 0; i < dayBtns.length; i++){
console.log(dayBtns[i]);
btns[i].addEventListener('click', myfunction);
}
}
The problem is the content is loading after the fun() function execution, how to restrict fun() function not to execute until the data is not loaded ?
Please help , thanks !
Just place fun() into onreadystatechange like so -
function findWeek(fun) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "start.php", true);
xhr.send(null);
xhr.onreadystatechange = function() {
if ((xhr.readyState == '4') && (xhr.status == '200')) {
document.getElementById("stats").innerHTML = xhr.responseText;
fun();
}
};
}
The innerHTML is set after the function fun is called so there are no elements in the DOM at that point.
You also have a typo on the code here:
for(var i = 0; i < dayBtns.length; i++){
console.log(dayBtns[i]);
btns[i].addEventListener('click', myfunction);
}
Should be:
for(var i = 0; i < dayBtns.length; i++){
console.log(dayBtns[i]);
dayBtns[i].addEventListener('click', myfunction);
}
Notice dayBtns vs btns
I have a problem with javascript in an ajax call
my script looks like this:
<html>
<body>
<div>contains large files to load</div>
<script type="text/javascript">
window.onload = function() {
alert('content is completely loaded');
}
</script>
</body>
</html>
When I reload the page it is working, but when I am dynamically loading this file with an ajax call.
my code to actually load and execute all scripts from the ajax call:
var tmp;
tmp = document.implementation.createHTMLDocument();
tmp.body.innerHTML = xmlhttp.responseText;
var scripts = tmp.getElementsByTagName('script');
var scripts_length = scripts.length;
for(i = 0; i < scripts_length; ++i) {
var script_tag = document.createElement('script');
script_tag.setAttribute('src', scripts[i].getAttribute('src'));
script_tag.setAttribute('type', 'text/javascript');
script_tag.setAttribute('charset', 'utf-8');
document.body.appendChild(script_tag);
}
how can I let all scripts execute when someone refreshes the page and also when the content is loaded with ajax?
so: my scripts are loading but not executing because window.onload, but window.onload can't be removed because then the page refresh does not work anymore
You're lacking an eval function in your code, cause your described method only adds the scripts from the response to the page. You can try with the following function
// this function create an Array that contains the JS code of every <script> tag in parameter
// then apply the eval() to execute the code in every script collected
function parseScript(strcode) {
var scripts = new Array(); // Array which will store the script's code
// Strip out tags
while(strcode.indexOf("<script") > -1 || strcode.indexOf("</script") > -1) {
var s = strcode.indexOf("<script");
var s_e = strcode.indexOf(">", s);
var e = strcode.indexOf("</script", s);
var e_e = strcode.indexOf(">", e);
// Add to scripts array
scripts.push(strcode.substring(s_e+1, e));
// Strip from strcode
strcode = strcode.substring(0, s) + strcode.substring(e_e+1);
}
// Loop through every script collected and eval it
for(var i=0; i<scripts.length; i++) {
try {
eval(scripts[i]);
}
catch(ex) {
// do what you want here when a script fails
}
}
}
the complete article is available here http://coursesweb.net/ajax/execute-javascript-code-ajax-response_t
attach an onload event handler to the body tag like this or otherwise use an eventListner.and to check if when conetent is loaded by ajax.check for the onreadystatechange. for example
function makerequest(serverPage, objID) {
var obj = document.getElementById(objID);
obj.innerHTML = '<b>Loading....</b>';
xmlhttp.open("GET", serverPage);
xmlhttp.onreadystatechange = function() {
//perform mystunts
}
}
xmlhttp.send(null);
}
You can use the status code to check whatever you want to.
see Ref from w3school.com
The onreadystatechange event
When a request to a server is sent, we want to perform some actions based on the response.
The onreadystatechange event is triggered every time the readyState changes.
The readyState property holds the status of the XMLHttpRequest.
Three important properties of the XMLHttpRequest object:
onreadystatechange Stores a function (or the name of a function) to be called automatically each time the readyState property changes
readyState Holds the status of the XMLHttpRequest. Changes from 0 to 4:
0: request not initialized
1: server connection established
2: request received
3: processing request
4: request finished and response is ready
status 200: "OK"
404: Page not found
I currently have a button which has the value "Submit". I would like this text to change to "Submitting" as soon at it is clicked. At the moments, I have this:
<input type="button" id=btnSub name="submitToeNICQ" value="Submit" onclick="do_submission()">
<div id="results"> No submission has been performed yet</>
<script>
function do_submission()
{
var elem = document.getElementById("btnSub");
elem.value="Submitting";
var xhReq = new XMLHttpRequest();
var request = "main.php?pid=21&submiteNICQ=yes "
xhReq.open("GET", request, false); // send a request
xhReq.send(null);
document.getElementByID("results").innerHTML=xhReq.responseText;
}
</script>
I would like the text to change before the XMLHttpRequest is processed, so that the change is immediate for the user. The above code seems to only change the button text once the whole request has been completed (normally about 3 seconds after button press).
Does anyone have a solution to this?
Don't perform synchronous AJAX requests. They're specifically made for asynchronous requests:
function do_submission()
{
var elem = document.getElementById("btnSub");
elem.value="Submitting";
var xhReq = new XMLHttpRequest();
var request = "main.php?pid=21&submiteNICQ=yes "
// Removed third parameter (it's now 'true' by default)
xhReq.open("GET", request);
// Added callback function for handling different states
xhReq.onreadystatechange = function () {
if (xhReq.status == 200 && xhReq.readyState == 4) {
document.getElementByID("results").innerHTML=xhReq.responseText;
}
};
xhReq.send(null);
}
Your current code waits for the request to complete before it can update any UI parts.
The code above fires the request asynchronously, so the function will end before the request has even completed and the browser has time for updating the UI.
jQuery:
function do_submission()
{
$("#btnSub").val("Submitting");
$.get("main.php?pid=21&submiteNICQ=yes", function (data) {
$("#results").html(data);
});
}