debug json javascript - Cannot set property 'innerHTML' of null - javascript

so I can not understand for the life of me why I keep getting
Uncaught TypeError: Cannot set property 'innerHTML' of null starting from line 29 where it says "var stats4". I am trying to apply it to an ID but only stats1,2,3 work. I tried copying and pasting the first part and changing things around. I dont get it.
my entire code is here -- jsfiddle.net/kx4s5egk
var request;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
request.open('GET', 'stats.json');
request.onreadystatechange = function() {
if ((request.readyState===4) && (request.status===200)) {
var items = JSON.parse(request.responseText);
var stats1 = items[0][0];
document.getElementById("stats1").innerHTML =
"<p>" + stats1.countTxt + "</p><p>" + stats1.participantsTxt + "</p><p class='count-blue1'>" + stats1.participantCount + "</p>";
var stats2 = items[0][1];
document.getElementById("stats2").innerHTML =
"<p>" + stats2.countTxt + "</p><p>" + stats2.participantsTxt + "</p><p class='count-blue2'>" + stats2.participantCount + "</p>";
var stats3 = items[0][2];
document.getElementById("stats3").innerHTML =
"<p>" + stats3.countTxt + "</p><p>" + stats3.participantsTxt + "</p><p class='count-blue3'>" + stats3.participantCount + "</p>";
var stats4 = items[1][0];
document.getElementById("stats4").innerHTML =
"<p>" + stats4.countTxt + "</p><p>" + stats4.participantsTxt + "</p><p class='count-blue1'>" + stats4.participantCount + "</p>";
var stats5 = items[1][1];
document.getElementById("stats5").innerHTML =
"<p>" + stats5.countTxt + "</p><p>" + stats5.participantsTxt + "</p><p class='count-blue2'>" + stats5.participantCount + "</p>";
var stats6 = items[1][2];
document.getElementById("stats3").innerHTML =
"<p>" + stats6.countTxt + "</p><p>" + stats6.participantsTxt + "</p><p class='count-blue3'>" + stats6.participantCount + "</p>";
}
}
request.send();

The reason for the error message is that you are trying to address a DOM element that doesn't exist. You have coded HTML enough for three items and try to address six.
Something like this is more easily (though probably less efficiently) coded with jQuery.
Sticking with hard-coded HTML, you could do something like this :
$.getJSON('stats.json').then(function(data) {
var i, j, n, stats;
for(i=0, n=1; i<data.length; i++) {
for(j=0; j<data[i].length; j++, n++) {
stats = data[i][j];
$("#stats" + n).html("<p>" + stats.countTxt + "</p><p>" + stats.participantsTxt + "</p><p class='count-blue'" + (j+1) + ">" + stats.participantCount + "</p>");
}
}
});
DEMO
However, you could do better by creating more of the HTML (DOM nodes) dynamically :
//First, a tempate for your item entries
var tpl = '<div class="grid1-3">' +
'<div class="%icon"></div>' +
'<div class="number_style %count-blue"></div>' +
'<div class="stats">%stats</div>' +
'</div>';
$.getJSON('stats.json').then(function(data) {
var i, j, jj, stats, _tpl;
for(i=0; i<data.length; i++) {
for(j=0, jj=1; j<data[i].length; j++, jj++) {
stats = data[i][j];
_tpl = tpl
.replace('%icon', 'icon' + jj)
.replace('%count-blue', 'count-blue' + jj)
.replace('%stats', "<p>" + stats.countTxt + "</p><p>" + stats.participantsTxt + "</p><p class='count-blue'" + jj + ">" + stats.participantCount + "</p>");
$("#items").append(_tpl);
}
}
});
DEMO
I'm sure I haven't addressed every aspect so there's undoubtedly still some work to do.

There are a couple of things I notice in your javascript code which are a bit unorthodox and are probably messing things up.
You have everything inside a window.onload() function, that's ok.
But inside the onload function you have two separate calls to the jquery function $(document).ready (which is equivalent, but probably more reliable, than window.onload).
One of your calls is the bit that starts with
$(document).ready
and the other begins with
jQuery(document).ready
Try reduce everything (including the window.onload() function) into a single $(document).ready function.
You can pull some stuff out into separate functions, but call them from inside $(document).ready

Related

Table in jQuery with toggable row

I have a table with the list of orders in my ecommerce site. I would like another line to appear with the order details by clicking on each line.
I don't understand how to write the function.
Here is how i wrote the table row:
$("#tbody").append("<tr id='riga" + i + "'><th scope='row'>" + idordine
+ "</th><td>" + data + "</td><td>" + prezzoTotale
+ "€</td><td> <button id='button_" + i
+ "')>Dettagli</button></tr><tr id='orderdetail_" + i
+ "' style='display:none;'>"
+ "<th scope='row'> ciao </th><td>ciao2</td><td>ciao2</td><td>ciao2</td></tr>"
);
and the function i wrote is:
for (var i = 0; i < ordini.length; i++) {
$("#button_" + i).click(function(i) {
$("#orderdetail_" + i).toggle("slow");
});
}
the variable i in $("#orderdetail_"+i) doesn't work. How can i do it?
Thanks all.
There's no need to link button_i with orderdetail_i, you can use relative navigation, in this case a relatively simple:
$(this).closest("tr").next()
To facilitate the event handler, I've added togglebutton class to each button and used that in a single selector.
Updated code:
// setup some example data
for (var i = 1;i<10; ++i) {
$("tbody").append("<tr id='riga" + i + "'><th scope='row'>" + "idordine"
+ "</th><td>" + "data" + "</td><td>" + "prezzoTotale"
+ "€</td><td> <button class='togglebutton' id='button_" + i
+ "')>Dettagli</button></tr><tr id='orderdetail_" + i
+ "' style='display:none;'>"
+ "<th scope='row'> ciao </th><td>ciao" + i + "</td><td>ciao" + i + "</td><td>ciao" + i + "</td></tr>"
);
}
// handle toggle
$("button.togglebutton").click(function() {
$(this).closest("tr").next().toggle();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tbody>
</tbody>
<table>

Javascript Append Function, Need to build a loop

I have a .php file where I am using both HTML and JavaScript to display items from my database. I have a JavaScript append function that is creating cards where each item is display. On my cards, I have a button that will expand the card to show product history. Some products have more history than others so the expansion needs to be dynamic. The historical data is being pulled from database and is initially in a php array. I originally was going to institute php into the javascript append function but I could not figure out how to set the JavaScript index variable 'I' to my php index. So I want to just stay with JavaScript. But I don't know how to write a loop in the middle of this append function that will loop through the historical array and populate the expansion. Below is what I am attempting. I took out a lot of the lines in the append function but you can see what I am trying to do.
function get_products() {
clear_cards();
$.each(productNumbers,
function(i, value) {
$('.main_card_shell').append(
"<div class='card_content card_style' id='card" + i + "'>" +
"<div id='card_tab2" + i + "' class='tabcontent' data-tab='tab-name2'>" +
"<div class='details_tables'>" +
"<table>" +
"<tr>" +
"<th>Item Type</th>" +
"<th>Painted</th>" +
"<th>Last Sold" +
"<a id='_close_tab" + i + "' class='tablinks tab_override' onclick=\"openCity(event,'card_tab4" + i + "')\">" +
"<i class='large angle up icon'></i>" +
"</a>" +
"</th>" +
"</tr>" +
"<tr>" +
var itemdatesplit = itemdate[i].split("$$");
var itemtypesplit = itermtype[i].split("$$");
var itemsplit = item[i].split("$$");
var arraylength = itemsplit.length;
var counter = 0;
while(counter < arraylength)
{
+ "<td>" + itemtypesplit[counter] + "</td>" +
+ "<td>" + itemdatesplit[counter] + "</td>" +
counter = counter + 1;
}
+
"</tr>" +
"</table>" +
"</div>" +
"</div>" +
Please help. I had it working with PHP inserted in, but I just couldn't figure out how to set it to a PHP variable.
Place this code into a function:
function getSomething(i) {
var html = '';
var itemdatesplit = itemdate[i].split("$$");
var itemtypesplit = itermtype[i].split("$$");
var itemsplit = item[i].split("$$");
var arraylength = itemsplit.length;
var counter = 0;
while(counter < arraylength) {
html += "<td>" + itemtypesplit[counter] + "</td>";
html += "<td>" + itemdatesplit[counter] + "</td>";
counter = counter + 1;
}
return html;
}
And then use it in your HTML building block:
'<some html>' + getSomething(i) + '<some other html>'

$.getJSON and for loop with an array and how to get them to work together - for loop completes before JSON is returned

I am trying to cycle through an array and with each value in the array, use $.getJSON to return some JSON and populate an HTML table with the return values.
I have been following this post, but seem not get this to work:
$.getJSON calls misbehaving inside a for loop
Here is my function:
$("#selectProviderTop").click(function() {
var restURL = window.location.protocol + "//" + window.location.hostname + (window.location.port == "" ? "" : (":" + window.location.port)) + "/restGetProvider/";
var selected = [];
var providerKey;
var providerID;
var providerLegacyID;
var providerName;
var finalURL;
var tr;
// First, create an array from the User Provider Keys...
var userProviderKeys = $("#hiddenUserProviderKeys").val();
selected = userProviderKeys.split(",");
console.log("selected: " + selected);
var tableHTML = "";
var focus = $("<div></div>"); // either match an existing element or create one: '<div />'
var arrayLength = selected.length;
for (var i = 0; i < arrayLength; i++) {
(function(i) {
console.log("i: " + i);
providerKey = selected[i];
console.log("providerKey: " + providerKey);
// Get that provider and populate the table...
finalURL = restURL + providerKey;
console.log("finalURL: " + finalURL);
focus.queue('apicalls', function(next) {
$.getJSON(finalURL, function(jsonObject) {
tableHTML += "<tr>";
tableHTML += "<td><a href=\"#\" onclick='selectProvider(\"" + providerKey + "\")'>" + jsonObject["providerName"] + "</a></td>";
tableHTML += "<td>" + jsonObject["providerID"] + "</td>";
tableHTML += "<td>" + jsonObject["providerLegacyID"] + "</td>";
tableHTML += "</tr>";
console.log("tableHTML: " + tableHTML);
next();
});
});
})(i);
}
// Replace table’s tbody html with tableHTML...
console.log("final tableHTML: " + tableHTML);
$("#tableProviderSelect tbody").html(tableHTML);
$('#modalSelectProviderForPTP').modal('show');
});
The userProviderKeys value is 0be32d8057924e718a8b6b4186254756,2dc5f826601e4cc5a9a3424caea4115f
The code never makes the $.getJSON call it just completes the for loop.
How do I update this code to get the first value in the array, grab the JSON, create the HTML, and then cycle through the loop?
I have tried setTimeout but that didn't help me out.
If you have some ideas, could you update my existing code - I understand better when I see the code itself. Thanks.
I don't know why you're doing this using queues. But you are, so I'm not going to rewrite your code to do it some other way.
The last few lines need to be called after all the queued functions have run, which means they should be called asynchronously. (Yes, you could make the whole thing synchronous as Marcus Höglund suggested, but that's no way to write scalable applications in javascript.) You could do this by adding another function to the queue containing these lines. Like this:
$("#selectProviderTop").click(function() {
var restURL = window.location.protocol + "//" + window.location.hostname + (window.location.port == "" ? "" : (":" + window.location.port)) + "/restGetProvider/";
var selected = [];
var providerKey;
var providerID;
var providerLegacyID;
var providerName;
var finalURL;
var tr;
// First, create an array from the User Provider Keys...
var userProviderKeys = $("#hiddenUserProviderKeys").val();
selected = userProviderKeys.split(",");
console.log("selected: " + selected);
var tableHTML = "";
var focus = $("<div></div>"); // either match an existing element or create one: '<div />'
var arrayLength = selected.length;
for (var i = 0; i < arrayLength; i++) {
(function(i) {
console.log("i: " + i);
providerKey = selected[i];
console.log("providerKey: " + providerKey);
// Get that provider and populate the table...
finalURL = restURL + providerKey;
console.log("finalURL: " + finalURL);
focus.queue('apicalls', function(next) {
$.getJSON(finalURL, function(jsonObject) {
tableHTML += "<tr>";
tableHTML += "<td><a href=\"#\" onclick='selectProvider(\"" + providerKey + "\")'>" + jsonObject["providerName"] + "</a></td>";
tableHTML += "<td>" + jsonObject["providerID"] + "</td>";
tableHTML += "<td>" + jsonObject["providerLegacyID"] + "</td>";
tableHTML += "</tr>";
console.log("tableHTML: " + tableHTML);
next();
});
});
})(i);
}
focus.queue('apicalls', function(next) {
// Replace table’s tbody html with tableHTML...
console.log("final tableHTML: " + tableHTML);
$("#tableProviderSelect tbody").html(tableHTML);
$('#modalSelectProviderForPTP').modal('show');
next();
});
});
Edit: Sunshine has pointed out that the linked stackoverflow post has mysterious references to the .dequeue method. In the accepted answer, this method is called explicitly after the tasks have been queued. I don't know whether this was necessary or not. I had thought that the problem was that the $.json bit wasn't happening until after the $("#tableProviderSelect tbody").html(tableHTML); part. But now I realise you wrote: "The code never makes the $.getJSON call it just completes the for loop." In that caseSunshine may have been right, and you need to add focus.dequeue('apicalls'); just after the last focus.queue(...);.

Best Way to make one section of a LI editable

What is the best way to make JUST card.price editable? I've futzed around with several different ways that seemed stupid simple, but it just isn't producing the right results. Does anyone out there have some suggestions?
html += "<li class='list-item ui-state-default' id=" + i + ">" +
card.card_name + ' - ' + card.price +
"<button class='removeThis'>" +
"X" + "</button>" + "</li>";
Here's a simple way to do that with input elements. Simplified example to illustrate it:
var card = {};
card.card_name = "Card Name";
card.price = "4.00";
var inputBeg = "<input size=8 style='border: none;' value='$";
var inputEnd = "'>";
var html = "";
for (var i = 0; i < 3; i++) {
html += "<li class='list-item ui-state-default' id=" + i + ">" +
card.card_name + ' - ' + inputBeg + card.price + inputEnd + "<button class='removeThis'>" +
"X" + "</button>" + "</li>";
}
document.body.innerHTML = html;
You could get much fancier with the styling if you wanted to.

How to add event handlers to dynamically created buttons in jQuery?

I used AJAX to dynamically create the HTML but I've encountered a problem
<script>
function page_loaded(){
jQuery.ajax({
method: "GET",
url: "get_data_dashboard.php",
success: function(data){
var markers = JSON.parse(data);
for(var i = 0; i < markers.length; i++){
var m = markers[i];
var markerHTML = "<div class='marker'>" +
"<span id='naziv'>Naziv zahtjeva: " + m.naziv + "</span></br>" +
"<span id='ulica'>Ulica: " + m.ulica + "</span></br>" +
"<p id='opis'>Opis:</br>" + m.opis + "</p></br>" +
"<span id='email'>Email: " + m.email + "</span></br>" +
"<img id='slika' src='" + m.link_slike + "' />" + "</br>" +
"<textarea rows='5' cols='30' maxlength='500' id='t" + m.marker_id + "' placeholder='Komentar'>" + "</textarea></br>"
+ "<div class='buttons'><a href='odobri_prijavu.php?id=" + m.marker_id + "'>Odobri</a>" +
"<a href='izbrisi_prijavu.php?id=" + m.marker_id + "'>Izbriši</a>" + "</div>" +
"</div><hr>";
$('#content').append(markerHTML);
}
}
})
}
$(document).ready(page_loaded());
</script>
I tried to use buttons first instead of anchor tags but I couldn't figure how to add event handlers to dynamically created buttons that will post a request via AJAX to some php script with the proper id as the value and the value of the textarea. So I used the anchor tag and I was able to send the id, but I can't send the value of the textarea because I don't know how to reference it and even if I referenced it, it will be NULL because its value is set to the anchor tag at the very beginning and I want to type in text in the textarea.
Instead of listening to individual "elements", you can actually listen to a parent of a specific element (You'll need to supply another parameter to on()). A popular pattern is to listen to "body" (because body is a parent to all, technically), but any non-dynamic parent element will work! Here's an example:
//notice the second parameter supplied
$("body").on("click", ".my-dynamic-element", function(e){
//awesome code that makes the world a better place goes here
//this code triggers when .my-dynamic-element is clicked, wootz
});
Event delegation is your friend.
I don`t see any actions that actually do event handling, but a simple solution would be something like:
$(document).on('click', '.your-button-class', function(){
// do your thing
});
<script>
function page_loaded(){
jQuery.ajax({
method: "GET",
url: "get_data_dashboard.php",
success: function(data){
var markers = JSON.parse(data);
for(var i = 0; i < markers.length; i++){
var m = markers[i];
var markerHTML = "<div class='marker'>" +
"<span id='naziv'>Naziv zahtjeva: " + m.naziv + "</span></br>" +
"<span id='ulica'>Ulica: " + m.ulica + "</span></br>" +
"<p id='opis'>Opis:</br>" + m.opis + "</p></br>" +
"<span id='email'>Email: " + m.email + "</span></br>" +
"<img id='slika' src='" + m.link_slike + "' />" + "</br>" +
"<textarea rows='5' cols='30' maxlength='500' id='t" + m.marker_id + "' placeholder='Komentar'>" + "</textarea></br>"
+ "<div class='buttons'>Odobri" +
"<a href='izbrisi_prijavu.php?id=" + m.marker_id + "'>Izbriši</a>" + "</div>" +
"</div><hr>";
$('#content').append(markerHTML);
}
}
})
}
$(document).ready(page_loaded());
function clickHandler(id){
$('#'+id) // selects the button
$('#t'+id) // selects the text area
}
</script>

Categories