This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I'm making a password generator. Trying to implement pass-phrases.
The function loadFile(); won't return a value to my main function, generate();
I think I'm too close to the problem and can't logic it out. I could use some help. Thank you.
Test site: https://jf0.000webhostapp.com/passWordGenerator/
test.js source: https://jf0.000webhostapp.com/passWordGenerator/test.js
The source is getting kind of long, sorry.
//Main generate password function
function generatePassword(){
var x = document.getElementById("passOutput");
var p = document.getElementById("testP");
x.value = generate();
//Make sure they aren't using an insecure number of characters
checkMaxChars();
p.innerText = x.value;
}
//Generate a password. 3 passSets for customization, one for passphrase
function generate(){
var nL = document.getElementById("noLetters");
var nN = document.getElementById("noNumbers");
var nS = document.getElementById("noSymbols");
var pPK = document.getElementById("passWordPhrase");
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var numbers = "0123456789";
var symbols = "!##$%^&*()_+~`|}{[]:;?,.-='";
var maxChars = document.getElementById("maxCharControl").value;
var generatedPass = "";
var holdPass = "";
//Main loop
for(var i = 0;i < maxChars;i++){
//Pick random value for each passSet
var passSet1 = chars.charAt(Math.random() * chars.length);
var passSet2 = numbers.charAt(Math.random() * numbers.length);
var passSet3 = symbols.charAt(Math.random() * symbols.length);
//if a checkbox is selected, clear out that value
if(nL.checked == true){passSet1 = "";}
if(nN.checked == true){passSet2 = "";}
if(nS.checked == true){passSet3 = "";}
//Randomly select a set to be added to holdPass, or not if it is empty.
var r = Math.floor((Math.random() * 4) + 1);
if(r == 1){if (passSet1 == ""){i--}else{holdPass += passSet1;}}
if(r == 2){if (passSet2 == ""){i--}else{holdPass += passSet2;}}
if(r == 3){if (passSet3 == ""){i--}else{holdPass += passSet3;}}
if(r == 4){
if(pPK.checked == true){
//get the value from loadFile(); and apply it to passSet4, add that to holdPass.
}}
}
generatedPass = holdPass;
console.log("Max Characters:" + maxChars);
console.log("passSet1:" + passSet1);
console.log("passSet2:" + passSet2);
console.log("passSet3:" + passSet3);
console.log("Iteration:" + i);
console.log("Random Position:" + r);
console.log("Password:" + holdPass + "::::" + holdPass.length);
//return password
return generatedPass;
}
//Make sure they didn't select all the checkboxes
function checkBoxes(){
var nL = document.getElementById("noLetters");
var nN = document.getElementById("noNumbers");
var nS = document.getElementById("noSymbols");
var pP = document.getElementById("passWordPhrase");
var nA = document.getElementById("noticeArea");
var nT = document.getElementById("noticeAreaText");
if(nL.checked == true && nN.checked == true && nS.checked == true){
nL.checked = false;
nN.checked = false;
nS.checked = false;
nA.style.display = "block";
nT.innerHTML = "You cannot select all checkboxes at once.";
window.setTimeout(hideNotice,5000);
}
else{
nA.style.display = "none";
nT.innerHTML = "";
}
}
//make sure the max characters is greater than 8
function checkMaxChars(){
var maxChars = document.getElementById("maxCharControl").value;
var nA = document.getElementById("noticeArea");
var nT = document.getElementById("noticeAreaText");
var x = document.getElementById("passOutput");
console.log(maxChars);
if (maxChars < 8){
x.value = "";
nA.style.display = "block";
nT.innerHTML = "You cannot generate a password less than 8 characters in length for security reasons.";
window.setTimeout(hideNotice,7000);
}
}
//hides the notice area div once the message is completed
function hideNotice(){
var nA = document.getElementById("noticeArea");
var nT = document.getElementById("noticeAreaText");
nA.style.display = "none";
nT.innerHTML = "";
}
//Load file
function loadFile() {
var xhttp = new XMLHttpRequest();
var x;
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
x = this.responseText;
parseResponse(x);
}
}
xhttp.open("GET", "wordList.csv", true);
xhttp.send();
return x;
}
//Format response
function parseResponse(x){
console.log("MADE IT HERE!");
var dS,sV1,rPos;
dS = x.split(",");
for(var i =0;i < dS.length;i++){
sV1 = dS[i];
}
x = sV1;
}
The results of an AJAX request will never be available until after the function that initiated it completes. You are attempting to return x before at the end of the function that initiates the request, which is before the AJAX request has finished.
You need to move that line into your AJAX success handler.
function loadFile() {
var xhttp = new XMLHttpRequest();
var x;
// The onreadystatechange callback function will execute
// at some future point after loadFile has completed, so
// you can only gain access to the AJAX result from within
// that function.
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
x = this.responseText;
parseResponse(x);
return x;
}
}
xhttp.open("GET", "wordList.csv", true);
xhttp.send();
}
Your xhttp request is opened asynchronously with the true in xhttp.open("GET", "wordList.csv", true); so x is returned before a value is assigned to it.
Edit: said synchronously instead of asynchronously because I am dumb
Related
I want to write a piece of code which requests some cryptocurrency prices by ajax, it will request a FIAT currency price as well.
So, I want to add "increased" class when the price goes up & "decreased" class when the price goes down. The script runs every 3 seconds to check the new prices.
I've tried to define a variable on the innerHTML of the price element, and an if/else on what should the script do when the price changes. Here is a sample code:
var btn = document.querySelector("#refreshprice");
var price = document.querySelector("#price-text");
var btcirr = document.querySelector("#btcirrrealtime");
var currency_symbol = document.querySelector("#currency-symbol");
var usdirrinner = usdirr.innerHTML;
var priceinner = price.innerHTML;
window.onload = function(){
var USDIRR = getUSDIRRRequest();
USDIRR.send();
var XHR = getXHRRequest();
XHR.send();
var BTCIRR = realtimeirr();
};
setInterval(function(){
var USDIRR = getUSDIRRRequest();
USDIRR.send();
var XHR = getXHRRequest();
XHR.send();
var BTCIRR = realtimeirr();
},3000);
function getUSDIRRRequest(){
var USDIRR = new XMLHttpRequest();
USDIRR.open("GET","http://call2.tgju.org/ajax.json");
USDIRR.onreadystatechange = function(){
if(USDIRR.readyState == 4 && USDIRR.status == 200){
var parsedData = JSON.parse(USDIRR.responseText);
dollarrealtimeprice = parsedData.current.price_dollar_realtime.p.replace(",", "");
var dollarrealtimepricetoman = dollarrealtimeprice/10;
usdirr.innerHTML = dollarrealtimepricetoman;
if(usdirrinner >= dollarrealtimepricetoman){
usdirr.classList.add("increased");
}
else {
usdirr.classList.add("decreased");
}
}
}
return USDIRR;
}
function getXHRRequest(){
var XHR = new XMLHttpRequest();
XHR.open("GET","https://api.coindesk.com/v1/bpi/currentprice.json");
XHR.onreadystatechange = function(){
if(XHR.readyState == 4 && XHR.status == 200){
var parsedData = JSON.parse(XHR.responseText);
price.innerHTML = parseFloat(parsedData.bpi.USD.rate_float).toFixed(2);
if(priceinner >= parseFloat(parsedData.bpi.USD.rate_float).toFixed(2)){
price.classList.add("increased");
}
else {
price.classList.add("decreased");
}
currency_symbol.innerHTML = parsedData.bpi.USD.symbol;
}
}
return XHR;
}
It was expected to change the class to "increased" when the price goes up. but it just remains decreased.
I am running into an issue with splitting a string into an array. To help myself troubleshoot the problem, I included two alert() functions, but only one gets called. Therefore, I know that there is an issue splitting a string into an array (for a basic username/password check). Here is my JS code:
function check() {
var user = document.loginform.usr.value;
var pass = document.loginform.psw.value;
var valid = false;
var txt = new XMLHttpRequest();
var alltext = "";
var allLines = [];
var usrn = [];
var pswd = [];
txt.open("GET", "/c.txt", true);
alltext = txt.responseText;
allLines = alltext.split(/\r\n|\n/);
usrn = allLines[0].split(',');
alert("usrn split");
pswd = allLines[1].split(',');
alert("pswd split");
for (var i=0; i <usrn.length; i++) {
if ((user == usrn[i]) && (pass == pswd[i])) {
valid = true;
break;
}
}
if(valid) {
window.location = "test.html";
return false;
}else{
var div = document.getElementById("login");
div.innerHTML = '<font color="red" size=2><i>Invalid Username/Password!</i></font><br>' + div.innerHTML;
}
}
The file that contains the login credentials (c.txt) is as follows:
User1,User2
pass,password
When User1 enters his/her name into the form, the password should be "pass". However, the script gets stopped at "pswd = allLines[1].split(',');". Am I misunderstanding the lines array?
Any help is appreciated - thanks!
You need to either use a synchronous call by changing the line to
txt.open("GET", "/c.txt", false);
Or use the "onreadystatechange" event to get the response when the server returns it
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
alltext = txt.responseText;
allLines = alltext.split(/\r\n|\n/);
usrn = allLines[0].split(',');
alert("usrn split");
pswd = allLines[1].split(',');
alert("pswd split");
for (var i=0; i <usrn.length; i++) {
if ((user == usrn[i]) && (pass == pswd[i])) {
valid = true;
break;
}
}
if(valid) {
window.location = "test.html";
return false;
}else{
var div = document.getElementById("login");
div.innerHTML = '<font color="red" size=2><i>Invalid Username/Password!</i></font><br>' + div.innerHTML;
}
}
}
You need to call txt.send(). Also it is async so txt.responseText will most likely be null.
You can use onreadystatechanged like so to ensure that txt.responseText has a value:
txt.onreadystatechange = function() {
if (txt.readyState == 4) { // 4 = DONE
alert(txt.responseText);
}
}
Okay - after fiddling with the code and doing some more research, I got a working script. This script takes data from a form and checks it against a file (c.txt). If the form entries match a username/password combination in c.txt, it takes you to another webpage.
function check() {
var user = document.loginform.usr.value;
var pass = document.loginform.psw.value;
var valid = false;
var txt;
if(window.XMLHttpRequest){
txt = new XMLHttpRequest();
}else{
txt = new ActiveXObject("Microsoft.XMLHTTP");
}
var allLines = [];
var usrn = [];
var pswd = [];
txt.onreadystatechange=function() {
if(txt.readyState==4 && txt.status==200){
var alltext = txt.responseText;
allLines = alltext.split(/\r\n|\n/);
usrn = allLines[0].split(',');
pswd = allLines[1].split(',');
for (var i=0; i <usrn.length; i++) {
if ((user == usrn[i]) && (pass == pswd[i])) {
valid = true;
break;
}
}
if(valid) {
window.location = "test.html";
return false;
}else{
var div = document.getElementById("login");
div.innerHTML = '<font color="red" size=2><i>Invalid Username/Password!</i></font><br>' + div.innerHTML;
}
}
}
txt.open("GET", "c.txt", false);
txt.send();
}
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I have a for loop that call a ajax method
function viderTableauConteneur()
{
var caf = document.getElementById('CAF').value;
var tabConteneurAjouter = caf.split("#");
for (var i = 0; i < tabConteneurAjouter.length; i++) {
if(!verifierConteneurAppartienClient(tabConteneurAjouter[i]));
removeConteneur(tabConteneurAjouter[i]);
};
}
function verifierConteneurAppartienClient(serialNumber)
{
var e = document.getElementById("id_client");
var idClient = e.options[e.selectedIndex].value;
var xhr = getXhr();
var res = 12;
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4 && xhr.status == 200)
{
if(xhr.responseText == "0")
return false;
else if(xhr.responseText == "1")
return true;
}
}
xhr.open("GET","index.php?option=com_tkcontrack&controller=facture&task=verifierConteneurAppartienClient&refConteneur="+serialNumber+"&id_client="+idClient,true);
xhr.send();
}
Well if I alert the xhr.responseText I got "1", but when I alert the result in the viderTableauConteneur method I always got "Undifined"
Any help please
You could modify your code this way :
function viderTableauConteneur()
{
var caf = document.getElementById('CAF').value;
var tabConteneurAjouter = caf.split("#");
for (var i = 0; i < tabConteneurAjouter.length; i++) {
verifierConteneurAppartienClient(tabConteneurAjouter[i],
function()
{
alert('true');
},
function()
{
alert('false');
removeConteneur(tabConteneurAjouter[i])
}
);
}
}
/* callbcakIfTrue and callbackIfFalse have to be 2 functions
that will be called respectiveley if the return of the
ajax call is true or false.
*/
function verifierConteneurAppartienClient(serialNumber, callbackIfTrue, callbackIfFalse)
{
var e = document.getElementById("id_client");
var idClient = e.options[e.selectedIndex].value;
var xhr = getXhr();
var res = 12;
xhr.onreadystatechange = function()
{
if(xhr.readyState == 4 && xhr.status == 200)
{
if(xhr.responseText == "1")
callbackIfTrue();
else
callbackIfFalse();
}
}
xhr.open("GET","index.php?option=com_tkcontrack&controller=facture&task=verifierConteneurAppartienClient&refConteneur="+serialNumber+"&id_client="+idClient,true);
xhr.send();
}
I am trying to write a OBJMesh model reader and I've got the OBJMesh class setted up, but when I try to retrieve the stored data in the array by creating the OBJMesh object and call the get function, it doesn't do it.
Here's the code
OBJMesh.js
function OBJMesh(file)
{
this.modelVertex = [];
this.modelColor = [];
this.init = false;
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, true);
var objmesh = this;
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState == 4)
{
if(rawFile.status === 200 || rawFile.status === 0)
{
var allText = rawFile.responseText;
var lines = allText.split("\n");
for(var i = 0; i < lines.length; i ++)
{
var lineData = lines[i];
var lineString = lineData.split(" ");
if(lineString[0] === "v")
{
var x = parseFloat(lineString[1]);
var y = parseFloat(lineString[2]);
var z = parseFloat(lineString[3]);
objmesh.modelVertex.push(x);
objmesh.modelVertex.push(y);
objmesh.modelVertex.push(z);
objmesh.modelColor.push(0.0);
objmesh.modelColor.push(0.0);
objmesh.modelColor.push(0.0);
objmesh.modelColor.push(1.0);
//document.getElementById("textSection").innerHTML = objmesh.modelVertex[0];
}
}
}
}
objmesh.init = true;
}
rawFile.send();
}
OBJMesh.prototype.getModelVertex = function ()
{
return this.modelVertex;
};
OBJMesh.prototype.getModelColor = function ()
{
return this.modelColor;
};
OBJMesh.prototype.getInit = function ()
{
return this.init;
};
main.js
var cubeModel;
function main()
{
cubeModel = new OBJMesh("file:///Users/DannyChen/Desktop/3DHTMLGame/cube.obj");
while(cubeModel.getInit() === false)
{
//wait for it
}
var cubeVertex = cubeModel.getModelVertex();
document.getElementById("textSection").innerHTML = cubeVertex[0];
}
it just keeps printing out "undefined". Why's that? and how can I fix it??
but it seems that onreadystatechange is an async-Call so,
this.init = true;
will be set before the function onreadystatechange is called.
May be you could set at the end of the onreadystatechange function
objmesh.init = true;
i hope this helps
I am studying javascript and json but I've some problems: I have a script that works with json but the performances of what I wrote aren't that good. The code works only if I do a debug step by step with firebug or other tools and that makes me think that the execution of the code (or a part of it ... the one that creates the table as you'll see) requires too much time so the browser stops it.
The code is:
var arrayCarte = [];
var arrayEntita = [];
var arraycardbyuser = [];
function displayArrayCards() {
var richiestaEntity = new XMLHttpRequest();
richiestaEntity.onreadystatechange = function() {
if(richiestaEntity.readyState == 4) {
var objectentityjson = {};
objectentityjson = JSON.parse(richiestaEntity.responseText);
arrayEntita = objectentityjson.cards;
}
}
richiestaEntity.open("GET", "danielericerca.json", true);
richiestaEntity.send(null);
for(i = 0; i < arrayEntita.length; i++) {
var vanityurla = arrayEntita[i].vanity_urls[0] + ".json";
var urlrichiesta = "http://m.airpim.com/public/vurl/";
var richiestaCards = new XMLHttpRequest();
richiestaCards.onreadystatechange = function() {
if(richiestaCards.readyState == 4) {
var objectcardjson = {};
objectcardjson = JSON.parse(richiestaCards.responseText);
for(j = 0; j < objectcardjson.cards.length; j++)
arrayCarte[j] = objectcardjson.cards[j].__guid__; //vettore che contiene i guid delle card
arraycardbyuser[i] = arrayCarte;
arrayCarte = [];
}
}
richiestaCards.open("GET", vanityurla, true);
richiestaCards.send(null);
}
var wrapper = document.getElementById('contenitoro');
wrapper.innerHTML = "";
var userTable = document.createElement('table');
for(u = 0; u < arrayEntita.length; u++) {
var userTr = document.createElement('tr');
var userTdcard = document.createElement('td');
var userTdinfo = document.createElement('td');
var br = document.createElement('br');
for(c = 0; c < arraycardbyuser[u].length; c++) {
var cardImg = document.createElement('img');
cardImg.src = "http://www.airpim.com/png/public/card/" + arraycardbyuser[u][c] + "?width=292";
cardImg.id = "immaginecard";
userTdcard.appendChild(br);
userTdcard.appendChild(cardImg);
}
var userdivNome = document.createElement('div');
userdivNome.id = "diverso";
userTdinfo.appendChild(userdivNome);
var userdivVanity = document.createElement('div');
userdivVanity.id = "diverso";
userTdinfo.appendChild(userdivVanity);
var nome = "Nome: ";
var vanityurl = "Vanity Url: ";
userdivNome.innerHTML = nome + arrayEntita[u].__title__;
userdivVanity.innerHTML = vanityurl + arrayEntita[u].vanity_urls[0];
userTr.appendChild(userTdcard);
userTr.appendChild(userTdinfo);
userTable.appendChild(userTr);
}
wrapper.appendChild(userTable);
}
The problem is that the code that should make the table doesn't wait for the complete execution of the code that works with the json files. How can I fix it? I would prefer,if possible, to solve that problem with something easy, without jquery and callbacks (I am a beginner).
You'll have to move som code around to make that work. at first, split it up in some functions, then it is easier to work with. I dont know if it works, but the idea is that first it loads the arrayEntita. When that is done, it fills the other 2 arrays. And when the last array has been filled, it builds the table.
var arrayCarte = [];
var arrayEntita = [];
var arraycardbyuser = [];
function displayArrayCards() {
var richiestaEntity = new XMLHttpRequest();
richiestaEntity.onreadystatechange = function () {
if (richiestaEntity.readyState == 4) {
var objectentityjson = {};
objectentityjson = JSON.parse(richiestaEntity.responseText);
arrayEntita = objectentityjson.cards;
BuildArrayEntita();
}
}
richiestaEntity.open("GET", "danielericerca.json", true);
richiestaEntity.send(null);
}
function BuildArrayEntita() {
for (i = 0; i < arrayEntita.length; i++) {
var vanityurla = arrayEntita[i].vanity_urls[0] + ".json";
var urlrichiesta = "http://m.airpim.com/public/vurl/";
var richiestaCards = new XMLHttpRequest();
richiestaCards.onreadystatechange = function () {
if (richiestaCards.readyState == 4) {
var objectcardjson = {};
objectcardjson = JSON.parse(richiestaCards.responseText);
for (j = 0; j < objectcardjson.cards.length; j++)
arrayCarte[j] = objectcardjson.cards[j].__guid__; //vettore che contiene i guid delle card
arraycardbyuser[i] = arrayCarte;
arrayCarte = [];
//If it is the last call to populate arraycardbyuser, build the table:
if (i + 1 == arrayEntita.length)
BuildTable();
}
}
richiestaCards.open("GET", vanityurla, true);
richiestaCards.send(null);
}
}
function BuildTable() {
var wrapper = document.getElementById('contenitoro');
wrapper.innerHTML = "";
var userTable = document.createElement('table');
for (u = 0; u < arrayEntita.length; u++) {
var userTr = document.createElement('tr');
var userTdcard = document.createElement('td');
var userTdinfo = document.createElement('td');
var br = document.createElement('br');
for (c = 0; c < arraycardbyuser[u].length; c++) {
var cardImg = document.createElement('img');
cardImg.src = "http://www.airpim.com/png/public/card/" + arraycardbyuser[u][c] + "?width=292";
cardImg.id = "immaginecard";
userTdcard.appendChild(br);
userTdcard.appendChild(cardImg);
}
var userdivNome = document.createElement('div');
userdivNome.id = "diverso";
userTdinfo.appendChild(userdivNome);
var userdivVanity = document.createElement('div');
userdivVanity.id = "diverso";
userTdinfo.appendChild(userdivVanity);
var nome = "Nome: ";
var vanityurl = "Vanity Url: ";
userdivNome.innerHTML = nome + arrayEntita[u].__title__;
userdivVanity.innerHTML = vanityurl + arrayEntita[u].vanity_urls[0];
userTr.appendChild(userTdcard);
userTr.appendChild(userTdinfo);
userTable.appendChild(userTr);
}
wrapper.appendChild(userTable);
}
i dont know if this check:
if (i + 1 == arrayEntita.length)
BuildTable();
but else you have to check if alle responseses have returned before executing buildtable();
AJAX requests are asynchronous. They arrive at an unknown period during execution and JavaScript does not wait for the server to reply before proceeding. There is synchronous XHR but it's not for ideal use. You'd lose the whole idea of AJAX if you do so.
What is usually done is to pass in a "callback" - a function that is executed sometime later, depending on when you want it executed. In your case, you want the table to be generated after you receive the data:
function getData(callback){
//AJAX setup
var richiestaEntity = new XMLHttpRequest();
//listen for readystatechange
richiestaEntity.onreadystatechange = function() {
//listen for state 4 and ok status (200)
if (richiestaEntity.readyState === 4 && richiestaEntity.status === 200) {
//execute callback when data is received passing it
//what "this" is in the callback function, as well as
//the returned data
callback.call(this,richiestaEntity.responseText);
}
}
richiestaEntity.open("GET", "danielericerca.json"); //third parameter defaults to true
richiestaEntity.send();
}
function displayArrayCards() {
//this function passed to getData will be executed
//when data arrives
getData(function(returnedData){
//put here what you want to execute when getData receives the data
//"returnedData" variable inside this function is the JSON returned
});
}
As soon as you have made the ajax call, put all of the rest of the code inside the readystatechange function. This way, it will execute everything in order.
Edit: #Dappergoat has explained it better than I can.