I’ve got a matrix of drop down lists, and I’d like to be able to show the user when they have edited a setting visually (for example by setting the background of the table cell to red). If they switch it back to the original value, it will go back to the default background color. This way it will be unambiguously clear what the state of the system is.
To do this I have come up with setting an onchange handler on the <select> element like this: select.setAttribute('onchange','chSel(this,'+select.selectedIndex+');'); where select is a <select> element.
It will call the function chSel with a reference to itself and the current setting, so it will be able to set classes which will determine display properties via CSS:
function chSel(node, origSelIndex) {
if (node.selectedIndex == origSelIndex) // switching back to the set state
node.parentNode.removeAttribute('class');
else node.parentNode.setAttribute('class','cell_changed');
}
That doesn’t require the retrieval of dynamic data, though the saved selectedIndex value in the onchange handler serves as element-specific static data.
I wanted to extend this functionality I have described by making a border around my table, which I intend to color red when ANY of its contents are modified, so that if a table is huge it is still possible to tell at a glance if any of its entries are modified.
There is a bad way and a better way to implement this. The bad way, which I do know how to implement in compliant HTML/XHTML, is to have chSel (which is executed any time the user interacts with a drop down menu) run a full search through the entire table to count edits, and mark the table border accordingly. This may not actually be a performance problem but I anticipate that it will be. I don’t think it would scale that well.
The better way is to keep a count of the number of edited elements. When that number drops back to zero (user changes all his edits back to original values) I can re-mark the table as unedited.
However this requires that I have some method of determining if a select menu has been changed from a new value to a different new value, as opposed to changing from the original value to a new value, i.e. it is now relevant what the value being changed from is. There does not appear to be a way to do this. This discussion seems to indicate that I cannot create and retrieve custom attributes while keeping my document valid. When I have tried to assign arbitrary attributes I’ve had difficulty retrieving their values.
What’s left? Can I build an object which I will use as a hash from elements to integers? Will javascript even let me do that?
I’m not sure I totally follow what you’re trying to do, but you can keep track of state either in javascript variables or in custom DOM attributes. Javascript variables are slightly easier, but you have to give them an appropriate scope so they survive the duration of your operation. Custom DOM attributes are sometimes easier to make object oriented and to avoid any global javascript variables. jQuery’s
.data()capability is actually in between the two. It uses one custom data attribute to tag the DOM object with a unique tag and then stores all the actual data in a javascript map.Once you store the state appropriately, anytime you get a change event, you can compare to the previous value and see what actually changed from the previous state, update your new state and save the new value as the previous value or do whatever else you need to do.
For example, in this way, you could keep a count of how many edited items there were and anytime that value goes from 0 to non-zero or non-zero to 0, you would change the overall table look as desired. Likewise, anytime an individual cell changes, you could update it’s look.
If your DOM elements are your only data structure, then it’s probably easiest to just create a custom attribute and keep additional data there. The HTML5 way of doing this is to preprend “data-” to your attribute names as in
obj.setAttribute("data-origSelectIndex", x)orobj["data-origSelectIndex"] = xto keep them clear of any name conflicts with standard attributes.If there’s any reason you don’t want to use custom attributes, then you would need to make a parallel javascript data structure (probably an array where each item in the array corresponds to one DOM element in some way that you can map between the two) that held the data.