Cannot set innerHTML of variable that is outside of fetch() - javascript

I am looping over querySelectorAll matches using for() and the current match is called meta[i]. Inside the for() function, I'm using fetch() to get some information from another page. The problem is that apparently, I can't set the innerHTML of meta[i] inside the fetch() function. Here is my code:
function variations() {
var meta = item.querySelectorAll('.meta_items tr td:nth-child(1)'), i;
var id = 1;
for (i = 0; i < meta.length; ++i) {
meta[i].querySelector('input').setAttribute('type', 'hidden');
meta[i].querySelector('input').value = id;
fetch('../public/orders.php?id=' + id).then((resp) => resp.text()).then(function(data) {
meta[i].innerHTML = data;
});
}
}
And here's the error I'm getting:
Uncaught (in promise) TypeError: Cannot set property 'innerHTML' of undefinedat test.js:8

Your function having the for cycle adds some AJAX calls which, when answered, their callbacks are called. However, by the time their callbacks are called, your function-scoped i has already reached out of bounds due to your for. An extremely simple fix is as follows:
function variations() {
var meta = item.querySelectorAll('.meta_items tr td:nth-child(1)');
var id = 1;
for (let i = 0; i < meta.length; ++i) {
meta[i].querySelector('input').setAttribute('type', 'hidden');
meta[i].querySelector('input').value = id;
fetch('../public/orders.php?id=' + id).then((resp) => resp.text()).then(function(data) {
meta[i].innerHTML = data;
});
}
}
I didn't change the way you define your id. Is that right to have id = 1 for all the requests and their callbacks?

I think by the time the fetch finished due to ++i, the value of i is meta.length. Therefore you are accessing meta[meta.length] and this is undefined. Try
function variations() {
var meta = item.querySelectorAll('.meta_items tr td:nth-child(1)'), i;
var id = 1;
for (i = 0; i < meta.length; ++i) {
const metaI = meta[i];
metaI.querySelector('input').setAttribute('type', 'hidden');
metaI.querySelector('input').value = id;
fetch('../public/orders.php?id=' + id).then((resp) => resp.text()).then(function(data) {
metaI.innerHTML = data;
});
}
}

Related

Callback is undefined and other stories

I got the following script, which is not working propperly. I know about getJSON's async nature, so I tried to build a callback function (jsonConsoleLog), which is supposed to be executed before getJSON get asigned to var (myJson = json;). After running debug in Chrome, I got two things out: A) debug is highlighting jsonConsoleLogcalls inside getJSON function as undefined.
B) Console is throwing TypeError: Cannot read property '0' of null for var friends = myJSON[0].friends;, which means the whole function doesn't work.
I'm in battle with it since saturday and I really don't know what to do. There's clearly something up with my callback function, but shoot me if I know what. Help?
var myJSON = null;
var main = document.getElementsByClassName('main');
var sec = document.getElementsByClassName('sec');
function getJSON(jsonConsoleLog){
$.getJSON('http://www.json-generator.com/api/json/get/cpldILZRfm? indent=2', function(json){
if (json != null){
console.log('Load Successfull!');
};
if (jsonConsoleLog){
jsonConsoleLog(json[0].friends);
}
myJSON = json;
});
};
function jsonConsoleLog(json) {
for (var i = 0; i < json.length; i++) {
console.log('friend: ' + friends[i]);
};
};
getJSON();
var friends = myJSON[0].friends;
function myFn1(){
for(var i = 0; i < friends.length; i++) {
main[i].innerHTML = friends[i].id;
};
};
function myFn2(){
for(var i = 0; i < friends.length; i++) {
main_div[i].innerHTML = friends[i].name;
};
};
main.innerHTML = myFn1();
sec.innerHTML = myFn2();
The first problem is because your function getJSON is expecting one formal argument, which you've called jsonConsoleLog. But you are not passing any arguments to getJSON. This means that inside getJSON the formal parameter, jsonConsoleLog, will indeed be undefined. Note that because you've named the formal parameter jsonConsoleLog, which is the same name as the function you're hoping to call, inside getJSON you won't have access to the function. What you need to do is pass the function as the parameter:
getJSON(jsonConsoleLog);
The second problem is I think to do with the json variable - it doesn't have a property 0 (i.e. the error is occurring when you try to treat it as an array and access element 0), which suggets that json is coming back empty, or is not an array.
you're calling getJSON without the callback parameter - therefore, the local variable jsonConsoleLog is undefined in getJSON
snip ...
function blah(json) { // changed name to avoid confusion in the answer - you can keep the name you had
for (var i = 0; i < json.length; i++) {
console.log('friend: ' + friends[i]);
};
};
getJSON(blah); // change made here (used the function name blah as changed above
var friends = myJSON[0].friends;
function myFn1(){
for(var i = 0; i < friends.length; i++) {
main[i].innerHTML = friends[i].id;
};
};
snip...
The issue with
var friends = myJSON[0].friends;
is duplicated here many many times ... $.getJSON is asynchronous and you are trying to use it synchronously
i.e. when you assign var friends = myJSON[0].friends; myJson hasn't been assigned in $.getjson ... in fact, $.getjson hasn't even BEGUN to run
here's all your code reorganised and rewritten to hopefully work
var main = document.getElementsByClassName('main');
var sec = document.getElementsByClassName('sec');
function getJSON(callback) {
$.getJSON('http://www.json-generator.com/api/json/get/cpldILZRfm? indent=2', function(json) {
if (json != null) {
console.log('Load Successfull!');
};
if (callback) {
callback(json);
}
});
};
function doThings(json) {
var friends = json[0].friends;
for (var i = 0; i < friends.length; i++) {
console.log('friend: ' + friends[i]);
};
function myFn1() {
for (var i = 0; i < friends.length; i++) {
main[i].innerHTML = friends[i].id;
};
};
function myFn2() {
for (var i = 0; i < friends.length; i++) {
main_div[i].innerHTML = friends[i].name;
};
};
main.innerHTML = myFn1();
sec.innerHTML = myFn2();
}
getJSON(doThings);
Correct, fully working code (basically the same as accepted, correct answer but stylistycally bit different)
var main = document.getElementsByClassName('main');
var sec = document.getElementsByClassName('sec');
var friends = null;
function getJSON(jsonConsoleLog){
$.getJSON('http://www.json-generator.com/api/json/get/cpldILZRfm?indent=2', function(json){
if (json != null){
console.log('Load Successfull!');
};
if (jsonConsoleLog){
jsonConsoleLog(json[0].friends);
}
});
};
function jsonConsoleLog(json) {
for (var i = 0; i < json.length; i++) {
console.log('friend: ' + json[i]);
};
friends = json;
myFn1();
myFn2();
};
function myFn1(){
for(var i = 0; i < friends.length; i++) {
main[i].innerHTML = friends[i].id;
};
};
function myFn2(){
for(var i = 0; i < friends.length; i++) {
main[i].innerHTML += friends[i].name;
};
};
getJSON(jsonConsoleLog);

'Uncaught TypeError: undefined is not a function' keeps showing up for different lines of code

I am trying to take a set of text, and when I hit a button have it change to a different set of text. I have been trying a lot of different methods, and cannot seem to get it to work. Here is a working Jsfiddle.
I keep getting 'Uncaught TypeError: undefined is not a function' for the line
var $rep = $update.textContent.substring(1);
I have changed this line of code, but will the get the same error on a different line of code within the same function.
function createAnswers() {
var i;
for (i = 0; i < 4; i++) {
var $update = $(".answers p")[i];
var $rep = $update.textContent.substring(1);
console.log($rep);
var answerText = document.createTextNode(randomImage.randomAnswers[i]);
if (usedImages.length >= 1) {
$rep.replaceWith(answerText);
}
$update.appendChild(answerText);
}
}
I am still pretty new at Javascript, so I may be missing something very obvious. Any constructive criticism will be helpful.
Your function should look like:
function createAnswers() {
var i,
$answers = $(".answers p");
for (i = 0; i < 4; i++) {
var $update = $answers[i];
var $rep = $update.textContent.substring(1);
var answerText = document.createTextNode(randomImage.randomAnswers[i]);
if (usedImages.length >= 1) {
$update.textContent = $update.textContent.replace($rep, answerText.textContent);
}
$update.appendChild(answerText);
}
}
You do not need to use jQuery functions after var $update = $(".answers p")[i];, because $update becomes an DOM node.
I figured it out. Thanks everybody for the help. I realized I needed to specify the use of text nodes, and updating the text node directly. Here is my final code:
function createAnswers() {
var i,
$update;
for (i = 0; i < 4; i++) {
$update = $(".answers p")[i];
console.log($update);
var answerText = document.createTextNode(randomImage.randomAnswers[i]);
if (usedImages.length === 0) {
$update.appendChild(answerText);
}
else {
$update.childNodes[1].nodeValue = randomImage.randomAnswers[i];
}
}
}

Why does the second loop execute before the first loop?

so this might be a repost, but I don't really know how to explain my second problem.
I have this code:
var paragraphsArray = new Array();
function setParagraphs(offSet)
{
offSet = offSet * 12;
for (var i = 1; i < 13; i++)
{
var parX = i + offSet;
var testASd = $.get('php/entryParagraphs.php', {idd: parX}).done(function(paragraph)
{
//clear paragraph1 div
document.getElementById("paragraph1").innerHTML = "";
//create p elements
var pElem = document.createElement("p");
pElem.setAttribute("id", "pEntry"+i);
document.getElementById("paragraph1").appendChild(pElem);
$("pEntry"+i).text(paragraph);
});
}
}
edited: I removed the second loop because it was unnecessary, for some reason the p element creation starts on i==13, which is the extra one that shouldn't even do.
for some reason the second loop executes first, so the paragraphArray is printed out as undefined. I managed to "fix" the order with the setTimeout() function, BUT I still get the undefined message, instead of the value. In the first loop the value is printed out fine, but if I try and put it in a $("p").text(paragraph); I also get undefined. So although I was right about the execution order, the problem is still there!
Because first is in ajax call, declare paragraphsArray in global space and use a callback function, try this:
*Updated
var paragraphsArray = [];
function setParagraphs(offSet) {
offSet = offSet * 12;
var request = 0;
for (var i = 1; i < 13; i++) {
var parX = i + offSet;
var testASd = $.get('php/entryParagraphs.php', {idd: parX}).done(function(paragraph) {
request++;
paragraphsArray[request] = paragraph;
console.log(paragraphsArray[request]);
if (request === 12) {
alert('first');
callback();
}
});
}
}
function callback() {
for (var i = 1; i < 13; i++) {
console.log(paragraphsArray[i]);
}
alert('second');
}
Run the second loop inside of the first loop.
function setParagraphs (offSet) {
//paragraphs
var testing = 0;
var paragraphsArray = new Array();
offSet = offSet * 12;
for (var i=1;i<13;i++) {
var parX = i + offSet;
var testASd = $.get('php/entryParagraphs.php', { idd: parX }).done(function(paragraph) {
paragraphsArray[i] = paragraph;
console.log(paragraphsArray[i]);
alert('first');
for (var i=1;i<13;i++) {
console.log(paragraphsArray[i]);
alert('second');
}
});
}
}
$.get is async function. 1st cycle will just send requests and wouldn't wait for response, so 2nd cycle will start right after first, without getting response of $.get function. Thats why console.log(paragraphsArray[i]); in 2nd cycle shows undefined.
You only can handle response in first cylce.
You can use $("p").text(paragraph); only like in this example:
var testASd = $.get('php/entryParagraphs.php', { idd: parX }).done(function(paragraph) {
paragraphsArray[i] = paragraph;
console.log(paragraphsArray[i]);
alert('first');
$("p").text(paragraph);
});
You can't use variables, which are assigned in function
function(paragraph) {
paragraphsArray[i] = paragraph;
console.log(paragraphsArray[i]);
alert('first');
$("p").text(paragraph);
}
outside of this function.
To achieve what you want you have to use another approach.
HTML will be:
<div id='paragraphs'>
</div>
JS code:
var testASd = $.get('php/entryParagraphs.php', { idd: parX }).done(function(paragraph) {
$("#results").append("<p>"+paragraph+"</p>")
});
You should use ~ this code. I just show you approach.

How do I use variables in document.getElementById

I have this code which I've been trying to fix for hours.
<script language="JavaScript">
<!--
function generate(){
var titels = new Array();
var i = 0;
for(i;i<9;i++){
var test = 'h1-0'+ i;
titels[i] = document.getElementById(test).textContent;
}
document.getElementById("uitkomst").value = titels[1];
}
-->
</script>
This gives me the error
TypeError: document.getElementById(...) is null
titels[i] = document.getElementById(test).textContent;
But when I change 'h1-0'+i by 'h1-0'+5 it does work and I don't get an error, so how do I fix this? Why is Javascript so annoying when using variables?
Add another variable:
var element;
and use it in the loop to hold on to the result of fetching (or trying to fetch) the element:
for (i; i < 9; i++) {
element = document.getElementById('h1-0' + i);
if (element) {
titles[i] = element.textContent;
}
else {
console.log("Element " + i + " not found.");
}
}
Then check the console to see which one is missing.
There are a couple ways you can fix this issue - you can test for a missing object and skip that case or you can catch the exception that is thrown and act accordingly in the exception handler.
Here's how you could handle missing objects in your code:
function generate(){
var titels = [];
var i, item, test;
for (i = 0; i < 9; i++) {
test = 'h1-0'+ i;
item = document.getElementById(test);
if (item) {
titels[i] = item.textContent;
}
}
document.getElementById("uitkomst").value = titels[1];
}
If, this is really all your code is doing, then you don't need the for loop because you're only using the [1] item from the array and you can do this:
function generate() {
var item = document.getElementById("h1-01");
if (item) {
document.getElementById("uitkomst").value = item.textContent;
}
}

Javascript array results returning undefined

I have been working on a simple math game and am having problems getting the overall answer results to return after the end of the game.
Here is what my return function looks like
function pShowResults() {
var pNumResults = document.getElementById("results");
for (var i = 0; i <= 10; i++) {
pNumStore.push(pNumGuess[i]);
var pNumTable = document.createElement("div");
pNumTable.innerHTML = (pNumGuess[i]);
pNumResults.appendChild(pNumTable);
}
}
Here is the full script
Pretty much need debugging help. I new to this so I'm guessing there is a ton that's off, but as long as I can get the results fed back I should be fine.
You are not passing the value of x in many placess
$(document).ready(function () {
//declare arrays and variables for use below
var pNum1 = [];
var pNum2 = [];
var pNumAns = [];
var pNumGuess = [];
var pNumStore = [];
var pNumCarry = 0;
var pNumTrack = 0;
var pNumMessageRight = ['Awesome Job!', 'Correct!', 'Great Job!'];
var pNumMessageWrong = ['Oh No! That Was Wrong!', 'Incorrect!', 'That\'s Wrong'];
$(".Play").click(function () {
$("#popup").attr("class", "on");
pNumTrack = 0;
pNumGen(pNumTrack);
});
$(".pNumSubmit").click(function () {
pNumCalc(pNumTrack-1);
});
$(".pNumNext").click(function () {
pNumGen(pNumTrack);
});
function pNumGen(x) {
pNum1[x] = (Math.round(Math.random() * 51));
pNum2[x] = (Math.round(Math.random() * 51));
pNumAns[x] = pNum1[x] + pNum2[x];
$(".pNum1").html(pNum1[x]);
$(".pNum2").html(pNum2[x]);
$(".pNumGuess").val("");
$(".pNum1").html(pNumTrack[x]);
if (pNumTrack == 2) {
$(".pNumNext").html("");
$(".pNumSubmit").html("Close");
pShowResults();
}
pNumTrack++;
}
function pNumCalc(x) {
pNumGuess[x] = $(".pNumGuess").val();
if (pNumGuess[x] == pNumAns[x]) {
$(".message").html(pNumMessageRight[Math.floor(Math.random() * pNumMessageRight.length)]);
$(".pNumNext").html("Next Question >")
} else {
$(".message").html(pNumMessageWrong[Math.floor(Math.random() * pNumMessageWrong.length)]);
$(".pNumNext").html("Maybe The Next Question >")
}
}
function pShowResults() {
var pNumResults = document.getElementById("results");
for (var i = 0; i < pNumGuess.length; i++) {
pNumStore.push(pNumGuess[i]);
var pNumTable = document.createElement("div");
pNumTable.innerHTML = (pNumGuess[i]);
pNumResults.appendChild(pNumTable);
}
}
});
Demo: Fiddle
There is a function called pNumCalc in your code which you have set to take in an argument, but you never pass one in. You use the argument to store the results in the pNumGuess array, but since the argument is never passed in, the guesses are never stored, and you end up with undefined as the answers the user gave.
Updated fiddle: http://jsfiddle.net/dwdX9/2/. Not sure how close this is to what you actually want though, but hopefully it gets you on the right track.
Because StackOverflow wants code to to be included when JSFiddle is...:
pNumCalc(pNumTrack)
You forget to define array before use it.
function pShowResults() {
var pNumStore = new Array();
var pNumResults = document.getElementById("results");
for (var i = 0; i <= 10; i++) {
pNumStore.push(pNumGuess[i]);
var pNumTable = document.createElement("div");
pNumTable.innerHTML = (pNumGuess[i]);
pNumResults.appendChild(pNumTable);
}
}
I must suggest you should use jquery instead.
After visiting your Fiddle seems like there are many problems with the code. and also your question is unclear.
for e.g.
$(".pNumSubmit").click(function () {
//why x value not passed?
pNumCalc();
});
function pNumCalc(x) {
pNumGuess[x] = $(".pNumGuess").val();
if (pNumGuess[x] == pNumAns[x]) {
$(".message").html(pNumMessageRight[Math.floor(Math.random() * pNumMessageRight.length)]);
$(".pNumNext").html("Next Question >")
} else {
$(".message").html(pNumMessageWrong[Math.floor(Math.random() * pNumMessageWrong.length)]);
$(".pNumNext").html("Maybe The Next Question >")
}
}
Please clear which array is returning undefined so that others can help you.

Categories