My objective - and I want to do this without jQuery:
Having rewritten this code to employ a callback, I'm getting the JSON data and creating links. However, I'm confused about two things regarding how the addEventListener
works: first, why is the showProj
function invoked as the event listeners are added in the for loop (so far, only alerting each link's id)? And second, why do the links not respond to clicks afterwards? I thought adding event listeners merely enables the generated links to be clickable?
function ajaxReq() {
var request = new XMLHttpRequest();
return request;
}
function getJsonData(makeLinks) { // makeLinks = the callback
var request = ajaxReq();
request.open("GET", "/json/projects.json", true);
request.setRequestHeader("content-type", "application/json");
request.send(null);
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200) {
makeLinks(request.responseText);
}
}
} // onreadystatechange
} // getJsonData
getJsonData(makeLinks);
function makeLinks(result) { // result = request.responseText
var projects = JSON.parse(result);
var projects = projects["Projects"];
var projectList = document.getElementById("project-list"); // ul#project-list
for (var project in projects) {
var projectId = projects[project].id;
var listItem = "<li><a class=\"project-link\" id=\""+projects[project].project+"\" href=\"#\">" + projects[project].project + "</a></li>";
projectList.innerHTML += listItem;
}
var projLink = document.getElementsByClassName("project-link");
for (var i = 0; i < projLink.length; i++) {
var projId = projLink[i].id;
projLink[i].addEventListener("click", showProject(projId), false); // ** ?? **
}
} // makeLinks
function showProject(projId) {
/*
function showProject will load data corresponding to the link's id (or another attribute);
presently there are only alerts until the links are working
*/
alert("projId is: " + projId);
} // showProject
Again, what I'm ultimately after is simply to click on a .project-link
class link, get its id (or some other attribute) and then load corresponding data, e.g. (pseudo-code):
projLink.onclick = function(){
var projId = this.id;
showProject(projId);
}
... and I realize I could do it with this:
$(document).ready(function() {
$("#project-list").on("click", 'li a', function() {
var projId = this.id;
showProject(projId);
})
})
... but I want to know why the event listeners aren't working in the first place (that is, without the jQuery bit).
And lastly: would it be considered evil bad practice in this scenario to preclude a scope issue by defining var projLink globally, so that I don't have to redefine it e.g., inside showProj?
Many thanks in advance for any corrections, suggestions, insights.
You're correct that var projLink
is scoped to the makeLinks()
function, but more importantly it's also inside the Ajax callback, which is a separate asynchronous scope.
While that Ajax code is running asynchronously, the rest of your JS continues to run as well.
So if you call another function to also getElementsByClassName("project-link")
, most likely there aren't any yet because the Ajax callback hasn't finished doing its thing.
Possible options include:
request.onreadystatechange()
within makeLinks()
(not ideal)Take a look at this previous question about Ajax response.