This is a dynamic web page that is all Ajaxy. When you click on an Active checkbox, it sends the request immediately up to the server and it’s immediately activated/deactivated. When you edit a field (as you can see on line 4) new icons appear for save and revert. As you can also probably see here, you can add or delete as many items as you want pretty effortlessly.
Here’s what I do. When a user clicks on the “markers” radio button (center bottom) I display a div that is empty. I throw a request at my server for all the current markers. The PHP at the server creates ready-to-go HTML. Here is what a single row looks like:
<tr valign="middle" class="arial s11 normal bk" onMouseOver="this.style.cursor: pointer;">
<td align="center">
<span style="display: none" comment="id">1</span>
<span style="display: none" comment="dirty">0</span>
<span style="display: none" comment="caption">Status 5.0.0</span>
<span style="display: none" comment="marker">Status 5\.0\.0</span>
<span style="display: none" comment="action">2</span>
<input type="checkbox" CHECKED onClick="updateActive(this)">
</td>
<td><input type="text" style="width: 150px" value="Status 5.0.0" onKeypress="makeDirty(this)"></td>
<td><input type="text" style="width: 150px" value="Status 5\.0\.0" onKeypress="makeDirty(this)"></td>
<td>
<select size="1" onChange="makeDirty(this)">
<option value="1">Delete Contact Record</option>
<option value="2" SELECTED>Delete on empty else unsubscribe</option>
<option value="3">Change status to Needs Attention</option>
<option value="4">Remove message, do nothing</option>
<option value="5">Unsubscribe record</option>
</select>
</td>
<td align="center"><img src="/graphics/dot_clear.gif" height="16" width="16" onClick="doSave(this)"></td>
<td align="center"><img src="/graphics/dot_clear.gif" height="16" width="16" onClick="doRevert(this)"></td>
<td align="center"><img src="/graphics/icon_delete.gif" height="16" width="16" onClick="doDelete(this)"></td>
</tr>
As you can see, by sending back complete and ready-to-display HTML, the ajax call simply needs to do a document.getElementById(‘theDiv’).innerHTML = kind of thing… I only need to modify what the surfer is looking at, I don’t need to do any processing at all. This is about as fast as JS and a server call can get. But note the incredibly important event drivers, like onClick: updateActive(this) – that’s the key to pretty much the key to what comes next.
Responding to eventsOK, so the user clicks on the active checkbox of a row… what to do? Well, since the function call sent the
this reference in it, I have a handle to the node that sent me the event. My personal protocol is to call that parameter “sender” because it makes sense to me.
function onActive(sender)
{
}
Now I have an event handler that will respond to any “active” checkbox that the user clicks on. But the “id” field that I desperately need to make my call to the server is in a completely different place… how do I get it?
function onActive(sender)
{
node = sender;
while (node.nodeName != ‘TR’) { node = node.parentNode; }
}
This little snippet will now take the “sent” node, and walk up the DOM tree (or out of the tree, depending on how you look at it) towards the root until the name of the node is TR… or a Table Row! Look again at the demo HTML row: it is clear that the sender is in a cell, which is of course in a row of a table.
The next step is to grab all of the spans that live on the tree under the current row… again by my own personal design, I try to choose either inputs for display and spans for data, or spans for display and inputs for data – this just makes life a little easier. The magic function is getElementsByTagName (note, Element
s)
function onActive(sender)
{
node = sender;
while (node.nodeName != ‘TR’) { node = node.parentNode; }
var spans = node.getElementsByTagName(‘SPAN’);
var id = spans[0].innerHTML;
alert(id);
}
As you can see, by asking the ROW node for children under it of the SPAN persuasion, I get everything on the tree underneath it that I want… which is the data I’ve been looking for. I can then reference the ID of <this> row and send off an Ajax request to Activate/Deactivate the marker with an id of <that id>.
One more time, with feeling:* The Active checkbox is clicked for a row
* The checkbox sends an onClick event to the function onActive, with the parameter (this) (reference to the node).
* The onActive function hears the function call with the reference to the DOM node (sender)
* The "node" variable is set to the sender parameter
* Loop: while the "node" variable's name is not TR (table row) I ask for <it's> parent node.
* The first step is to the TD
* The second step puts me at the TR
* I ask the ROW node for all elements underneath it that are a SPAN
* Since know the order of the SPANS under this row, I know that span[0] will have the ID value I'm looking for
* In this example, I simply do an ALERT with the value, but in the real application, I shoot of an AJAX request to the database that updates the marker with ID (theID).
Note: Some would argue that I could have placed the ID right into the dynamically written javascript, rather than doing it this way and you’re right: I could have. But many other functions in this example require the methodology that I just described, so in the interest of future readability I’ve done all functions identically rather than using a different method for each feature of the application
Why is this so important?Well, in a clear cut example as you see here, it seems to be less important because there are other ways of doing it. But consider now: the user adds several and deletes several items from <somewhere> in that list… now the array management issues (and debugging) start to get really scary. Why do all that, since the DOM is keeping it “visually sorted” for my surfer, and I can “Ask The DOM” for the values?
And back to the original question, What is a variable?Thinking in this way, the DOM can become just another variable heap for you – and the method for “getting what you want to hang on to” is just a little different than if you use the more traditional variable name. Is this more processing intensive than just using a variable name? Of course! But it is trivially more intensive, and more importantly, it reduces an incredible amount of processing time that I’d need to go through if I was maintaining parallel arrays that managed the data.
Looking forward to your comments,
/p