February 6th, 2010
I was reading a blog post about jQuery event delegation by Karl Swedberg yesterday. One corner case I found in his examples is dealing with nested DOM elements of the same type (e.g. divs within divs, or in the following example tables within tables).
Here’s a solution (albeit possibly not the best) that makes use of jQuery’s parentsUntil() method, added in version 1.4:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN”
”http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” xml:lang=”en-us” lang=”en-us”
xmlns:v=”urn:schemas-microsoft-com:vml”>
<head profile=”http://www.w3.org/2005/10/profile”>
<script type=”text/javascript”>
$(function() {
$(“#outer”).click(function(event) {
var parentCells = $(event.target).parentsUntil(this).filter(“td”);
var outermostCell = $.merge($(event.target), parentCells).last();
$(“#output”).text(outermostCell.text());
});
});
</script>
</head>
<body>
<div id=”output”>[Nothing clicked]</div>
<br />
<table id=”outer” border=”1″ cellpadding=”15″>
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
</tr>
<tr>
<td>d</td>
<td>
<table id=”inner” border=”1″ cellpadding=”15″>
<tr>
<td>i</td>
<td>ii</td>
<td>iii</td>
</tr>
<tr>
<td>iv</td>
<td>v</td>
<td>vi</td>
</tr>
<tr>
<td>vii</td>
<td>viii</td>
<td>ix</td>
</tr>
</table>
</td>
<td>e</td>
</tr>
<tr>
<td>f</td>
<td>g</td>
<td>h</td>
</tr>
</table>
</body>
</html>
November 18th, 2009
Here’s a handy way to delete multiple items (that may not be contiguous) from a JavaScript array.
This hinges around using splice() in a for() loop. The trouble is that every time you slice, the index of each of the following items in the array gets decremented but you’re still increasing your index variable with each iteration.
For example:
var arr = [
{ name: 'a', active: true },
{ name: 'b', active: false },
{ name: 'c', active: true },
{ name: 'd', active: false },
{ name: 'e', active: true }
];
// let's kill the inactive objects
var kill = [];
for (var i = 0; i < arr.length; i++) {
if (!arr[i].active)
kill.push(i);
}
// now 'kill' contains [1, 3]
We're fine so far: now we have the indexes that we want to remove. Here's where the trouble starts:
// remove inactive elements from array - BAD
for (var i = 0; i < kill.length; i++)
arr.splice(kill[i], 1);
As mentioned above, this is bad because each time you remove an element from the array, the following elements will all have their indexes decremented. That means that the next "kill" index you come across will reference the wrong element!
Here's a simple way to mitigate:
// remove inactive elements from array - GOOD
for (var i = 0; i < kill.length; i++)
arr.splice(kill[i] - i, 1);
Note the change in the splice index from "kill[i]" to "kill[i] - i", which accounts for the decremented array indexes.
By the way, you may be asking, "Why not use 'delete'?" Well, delete leaves holes in your array, which we don't want.
You may also be asking, "Why not use foreach() instead of for(), thereby, bypassing the need for an index variable?" Well, it's unsafe to use foreach() on an array. You should only ever use foreach() on an object, for reasons that I won't get into here.
Hope this helps someone.
