views:

1336

answers:

3

I've created two functions to load expanded views of a month in the archive section of my blog when it's link is clicked:

// Load open view of a month in the Archive section
function loadMonth(date) {
  // Remove other open month
     removeMonth();

  // Hide opening month's link
  // Define variable to hold month anchor tag
     var monthLink = document.getElementById(date); 
     monthLink.style.display = "none"; // Hide month anchor

  // Define new open month node and its attributes
     var openMonth = document.createElement("div");
     openMonth.setAttribute("id", "openMonth");
     openMonth.innerHTML = "Testing one, two, three.";

  // Insert open month
  // Define a variable to hold the archive Div node
     var archive = document.getElementById("archive");
  // Insert the open month in the archive node before it's link
     archive.insertBefore(openMonth,monthLink);

     return;
  }


// Close full view of a month and replace with respective link
function removeMonth() {

  // Define global function vars
     var archive = document.getElementById("archive"); // Define a var to hold the archive Div node
     var openMonth = document.getElementById("openMonth"); // Define var to hold the open month Div node

  // Get date of full view month for replacement anchor tag where ID = date
     var month = openMonth.getElementsByTagName("span")[0].innerHTML; // Define var to hold the name of the open month
     var date = (new Date(month + " 15, 2008").getMonth() + 1); // Define var to hold the numerical equivalent of the month
     var year = archive.getElementsByTagName("h3")[0].innerHTML.split(" "); // Define var to hold the year being displayed in the archive
     date = year[1] + "" + date; // Change date var to string and insert year

  // Remove the open month
     archive.removeChild(openMonth);

  // Show Link for that month
     document.getElementById(date).className = "big"; // Fixes display error when anchor has class firstLink
     document.getElementById(date).style.display = "inline"; // Returns link from display "none" state
     return;
}

The functions work when run on the original static content, but when a second link is clicked in the archive, they do nothing. I am wondering if maybe because the elements that were created by my functions cannot be called by document.getElementById. Perhaps a different method of accessing those nodes should be used, or maybe replacing "document" with something that works on javascript created elements too?

Any advice would be greatly appreciated. Thanks.

+5  A: 

You should be fine with:

openMonth.id = "openMonth";

getElementById() can only work if the element is part of the DOM, but since you already use insertBefore() this is merely a side note.

There is a common source of confusion involved here: An attribute named "id" is not necessarily the one that is defined as the element ID in the underlying DTD. In declarative HTML, they are linked automatically. When you use setAttribute(), you are not more than creating an attribute named "id". The element ID itself is accessible via the .id property.

Edit

The following works for me:

function test()
{
  // create element, set ID
  var p = document.createElement("P");
  p.innerHTML = "Look ma, this is a new paragraph!";
  p.id = "newParagraph";

  // make element part of the DOM
  document.getElementsByTagName("BODY")[0].appendChild(p);

  // get element by ID
  var test = document.getElementById("newParagraph");
  alert(test.innerHTML);
}
Tomalak
Unfortunately, changing that line did not fix the problem. Not sure what you meant by "getElementById() can only work if the element is part of the DOM..." Isn't the object I am inserting part of the DOM? Or Is that why you said it is only a side note...
Bloudermilk
Right after you created an element, it is just *there*, not connected to anything, and invisible to getElementById(). You must add it to the DOM to make it visible. I'll add a test case.
Tomalak
Since you add the "openMonth" element to "archive" element using insertBefore(), there must be an additional error somewhere. Maybe the archive element itself is not part of the document?
Tomalak
+2  A: 

To answer your main question: document.getElementById does work with dynamically added elements.

In your sample code you are creating the openMonth div and setting its innerHTML. Then in the remove tag you are doing this:

var month = openMonth.getElementsByTagName("span")[0].innerHTML;

openMonth.getElementsByTagName("span") will not exist and will get an error because there are no span elements. I don't know if this is a mistake in the code or if it is just a incomplete sample in the post.

Ryan Cook
You're absolutely right! To be honest, I hadn't gotten that far in my code. I am new to Javascript and did not realize that would throw off the whole function. Thank you so much!
Bloudermilk
A: 

Another idea - you're reusing the 'openMonth' id for different elements, maybe that's a problem even if you remove the previous element first.

You could try to use a class instead of id, or you could holding a global variable with the 'current month element'.

orip