SitePoint Sponsor

User Tag List

Results 1 to 9 of 9
  1. #1
    SitePoint Wizard
    Join Date
    Nov 2004
    Location
    Nelson BC
    Posts
    2,310
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Moving items around causes loss of event handlers?

    Hi guys,

    I have a table with some checkboxes in it, the order of the items in the table is supposed to represent the item's priority, with the checkbox used to turn the item on/off. Only items that are on have priority, the rest have priority of 0. Items with priority are listed in order starting from the top of the table, and those without priority are below them in any old order.

    What I'm trying to do is: when a checkbox is checked, move the item (tr) to the bottom of the "section" of the table that contains items with priorities, set the priority to 1, and increment everything above it. I have this working ok. What happens is, the checkbox does not ever check, and other oddities. Here is the code in its simplest form:

    Code:
    <html>
    <head>
    <style type="text/css">
    .highlight {
    	background-color: FFFFAA;
    }
    </style>
    <script type="text/javascript">
    function hl() {
    	this.className += " highlight";
    }
    
    function unhl() {
    	this.className = this.className.replace(" highlight","");
    }
    
    function prioritize() {
    	if (this.checked) {
    		this.value = 1; // the lowest priority
    		
    		// we need to move this into the priorities section
    		var tr = this.parentNode.parentNode; // the tr of this item
    		var tb = tr.parentNode; // the tbody object
    		var rows = tb.getElementsByTagName("tr"); // all the trs in the table
    		
    		for (var i=0; i < rows.length; i++) {
    			var chk = rows[i].getElementsByTagName("input")[0]; // ugh we assume a lot here, if there are more inputs in the row this needs to change
    			if (chk.value >= this.value) {
    				// add 1 to the value (we are shifting the priority values up 1 each)
    				chk.value += 1;
    			} else {
    				// we have entered the "non priority" ie unchecked boxes
    				tb.insertBefore(tr, rows[i]);
    				// we're done
    				break;
    			}
    		}
    	} else {
    		// we need to move this OUT of the priorities section
    		// not done yet =)
    	}
    	return true;
    
    
    }
    
    function assignEvts() {
    	var tbl = document.getElementsByTagName("table")[0];
    	
    	var trs = tbl.getElementsByTagName("tr");
    	var inps = tbl.getElementsByTagName("input");
    	
    	for (var i=0; i < trs.length; i++) {
    		trs[i].onmouseover = hl;
    		trs[i].onmouseout = unhl;
    	}
    
    	for (var i=0; i < inps.length; i++) {
    		inps[i].onclick = prioritize;
    	}
    }
    
    
    window.onload=assignEvts;
    </script>
    </head>
    <body>
    <table border="1">
    <tr><td>item 1</td><td><input type="checkbox" value="0"></td></tr>
    <tr><td>item 2</td><td><input type="checkbox" value="0"></td></tr>
    <tr><td>item 3</td><td><input type="checkbox" value="0"></td></tr>
    <tr><td>item 4</td><td><input type="checkbox" value="0"></td></tr>
    <tr><td>item 5</td><td><input type="checkbox" value="0"></td></tr>
    <tr><td>item 6</td><td><input type="checkbox" value="0"></td></tr>
    </table>
    </body>
    </html>
    What I think is happening: When I call insertBefore, the TR in question is losing all its event handlers, and the onclick event handler for the checkbox is being lost also.

    I have tried a few tricks...using the microsoft table.moveRow function instead of insertBefore (same result). I also tried storing the innerHTML for the two rows and switching it.

    Oh I forgot to mention, this is an IE only project for a client so FF/Opera etc do not matter (yet). It has to work in IE

    Cheers,

    Jim

  2. #2
    SitePoint Wizard
    Join Date
    Nov 2004
    Location
    Nelson BC
    Posts
    2,310
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    edit: I wonder if this is happening

    edit2: doh, I suck, nice edit

  3. #3
    SitePoint Wizard
    Join Date
    Nov 2004
    Location
    Nelson BC
    Posts
    2,310
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    *bump*

  4. #4
    SitePoint Wizard
    Join Date
    Mar 2001
    Posts
    3,537
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You need a <tbody> element in your html. See if this helps (untested in IE):
    Code:
    <html>
    <head><title>testss</title>
    
    <script type="text/javascript">
    
    window.onload = assignEvts;
    
    function assignEvts() 
    {
    	var tbl = document.getElementsByTagName("table")[0];
    	var inps = tbl.getElementsByTagName("input");
    	for (var i=0; i < inps.length; ++i) 
    	{
    		inps[i].onclick = prioritize;
    		inps[i].parentNode.parentNode.priority = "off";  //attach priority property to tr
    	}
    }
    
    function prioritize()
    {
    	var tr = this.parentNode.parentNode; // the tr of this item
    	var tb = tr.parentNode; // the tbody object
    	var temp = tb.removeChild(tr);  //remove tr whose input element was clicked
    		
    	if(this.checked)  //then insert in proper place
    	{
    		temp.priority = "on";
    		
    		var rows = tb.getElementsByTagName("tr");
    		for (var i=0; i < rows.length; ++i)
    		{
    			if(rows[i].priority == "off") 
    				break;
    		}
    		if(i==rows.length) //then all tr's have "on" for their priority
    		{
    			tb.appendChild(temp);
    		}
    		else
    		{
    			tb.insertBefore(temp, rows[i]);
    		}
    	}
    	else //then being unchecked, so toss the tr onto the end of <tbody>
    	{
    		temp.priority="off";
    		tb.appendChild(temp);
    	}
    }
    			
    			
    </script>
    </head>
    <body>
    
    <table border="1">
    <tbody>
    	<tr><td>item 1</td><td><input type="checkbox" value="0"></td></tr>
    	<tr><td>item 2</td><td><input type="checkbox" value="0"></td></tr>
    	<tr><td>item 3</td><td><input type="checkbox" value="0"></td></tr>
    	<tr><td>item 4</td><td><input type="checkbox" value="0"></td></tr>
    	<tr><td>item 5</td><td><input type="checkbox" value="0"></td></tr>
    	<tr><td>item 6</td><td><input type="checkbox" value="0"></td></tr>
    </tbody>
    </table>
    
    </body>
    </html>

  5. #5
    SitePoint Wizard
    Join Date
    Nov 2004
    Location
    Nelson BC
    Posts
    2,310
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    As usual I overcomplicated the problem. Here is some new code that shows it equally with no event handlers involved.
    Code:
    <html>
    <head>
    <script type="text/javascript">
    // cross-browser
    function moveRowUp() {
    	var tb = document.getElementsByTagName("tbody")[0];
    	var firstRow = tb.getElementsByTagName("tr")[0];
    	var lastRow = tb.getElementsByTagName("tr")[5];
    	tb.insertBefore(lastRow,firstRow);
    }
    
    // IE specific
    function moveRowUp2() {
    	var tbl = document.getElementsByTagName("table")[0];
    	tbl.moveRow(5,0);
    }
    </script>
    </head>
    <body>
    <table border="1">
    <tbody>
    <tr><td>item 1</td><td><input type="checkbox" value="0"></td></tr>
    <tr><td>item 2</td><td><input type="checkbox" value="0"></td></tr>
    <tr><td>item 3</td><td><input type="checkbox" value="0"></td></tr>
    <tr><td>item 4</td><td><input type="checkbox" value="0"></td></tr>
    <tr><td>item 5</td><td><input type="checkbox" value="0"></td></tr>
    <tr><td>item 6</td><td><input type="checkbox" value="0"></td></tr>
    </tbody>
    </table>
    <button onclick="moveRowUp();">move item 6 to top</button><br/>
    <button onclick="moveRowUp2();">move item 6 to top (IE ONLY)</button><br/>
    </body>
    </html>
    How to create problem: Check item 6, click either button to move it to the top, result: item 6 gets unchecked. If I could fix or even understand this, I'd be happy.

  6. #6
    SitePoint Zealot
    Join Date
    Jun 2005
    Posts
    117
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi,
    Attributes other than name and id(i think) don't get cloned unless they were declared inline, or, you use some really buggy attribute setting code. Here is one fix.
    Code:
    function moveRowUp() {
    	var tb = document.getElementsByTagName("tbody")[0];
    	var firstRow = tb.getElementsByTagName("tr")[0];
    	var lastRow = tb.getElementsByTagName("tr")[5];
            var checkBox = lastRow.getElementsByTagName("input")[0];
            var isChecked = checkBox.checked;
    	tb.insertBefore(lastRow,firstRow);
            checkBox.checked = isChecked;
    }
    Another fix sould be something like this
    Code:
           var attribute = document.createAttribute("checked");
                attribute.value = false;
                checkBox.setAttributeNode(attribute);
               checkBox.checked = false;
    although..I don't think the false would be recognized.


    AFrieze

  7. #7
    SitePoint Wizard
    Join Date
    Nov 2004
    Location
    Nelson BC
    Posts
    2,310
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yeah, thanks for the effort, it's not really what I need because my checkboxes have dynamically assigned event handlers, plus the checkboxes themselves are built via dom commands.

    I'll probably end up using some clumsy hack to get this working, like rebuild the table every time a checkbox is clicked (ugh).

  8. #8
    SitePoint Zealot
    Join Date
    Jun 2005
    Posts
    117
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi JimFraser
    Could you create a hidden element with all the event handlers you need already assigned and then just clone it

    Example
    Code:
    <input id = "cloneCheckBox1" type = "checkbox" style = "visibility: hidden;" onmouseover="doSomething()" onmouseout = "doSomething()"  onclick = "doSomething()">
    
    
    //instead of creating an element and assigning even handlers, clone an existing element
    var checkBox = document.getElementById('cloneCheckBox1').cloneNode(false);
    checkBox.style.visibility = "visible";
    I believe doing it this way will carry your event handlers over.
    AFrieze

  9. #9
    SitePoint Wizard
    Join Date
    Nov 2004
    Location
    Nelson BC
    Posts
    2,310
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    After much &&#37;!king around with this, I have determined that YOU CAN'T DO IT.

    Whenever you use appendChild in IE, 90% of the attributes disappear, no matter how they were initiated.

    What makes it worse is if there is no "html" to begin with (as was my case, it was all being created through javascript/ajax/json and then javascript again). For anyone who wants to say "oooo...but what about lynx users" I will promptly say "I dont care about them, this is a corporate intranet application where everyone uses internet explorer 6 with javascript turned on"

    I ended up changing the design radically and using textboxes that either have 0 for not selected/no priority and a number greater than 0 for a priority. It works fine, it's just not so nice to use.

    Cheers AFrieze for the help


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •