SitePoint Sponsor

User Tag List

Results 1 to 7 of 7
  1. #1
    SitePoint Evangelist
    Join Date
    Aug 2005
    Posts
    574
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Problems with a show/hide toggle

    This is driving me nuts. I built an original table where you could show or hide various elements using this basic script:

    Code:
    function showHide(elementID, show)
    {
    	var el = document.getElementById(elementID);
    
    	if(show)
    	{
    		el.style.display = '';
    	}
    	else
    	{
    		el.style.display = 'none';
    	}
    
    	return false;
    }
    
    function showHideGroup(group, show)
    /*
    	Group should be an array with names of elements to hide.
    */
    {
    	for(i=0; i<group.length; i++)
    	{
    		showHide(group[i], show);
    	}
    }
    Rows of the table are easy to hide because you can use a single ID. For columns, we used the showHideGroup and then assigned the various IDs within the array variable. For example, we wanted to hide 3 columns titled Payments, Balances and Notes so the variables went like this:

    Code:
    var paymentsShowHide = ['showHidePayments', 'payments1', 'payments2', 'payments3' . . . 'paymentsn']
    
    var balancesShowHide = ['showHideBalances', 'balances1', 'balances2', 'balances3' . . . 'balancesn']
    
    var notesShowHide = ['showHideNotes', 'notes1', 'notes2', 'notes3' . . . 'notesn']
    And we accessed it using HTML like this:

    HTML Code:
    <li id="paymenthidelink"><a title="Hide Payments" href="#" onclick="javascript:showHide('paymentshowlink', 1);showHide('paymenthidelink', 0);showHideGroup(paymentsShowHide, 0);"><img src="_images/hidePayments.gif" align="middle" width="41" height="16" name="hidePayments" alt="Hide Payments" /></a></li>																
    <li id="paymentshowlink" style="display:none;"><a title="Show Payments" href="#" onclick="javascript:showHide('paymenthidelink', 1);showHide('paymentshowlink', 0);showHideGroup(paymentsShowHide, 1);"><img src="_images/showPayments.gif" align="middle" width="41" height="16" name="showPayments" alt="Show Payments" /></a></li>
    			
    <li id="balancehidelink"><a title="Hide Balances" href="#" onclick="javascript:showHide('balanceshowlink', 1);showHide('balancehidelink', 0);showHideGroup(balancesShowHide, 0);"><img src="_images/hideBalances.gif" align="middle" width="41" height="16" name="hideBalances" alt="Hide Balances" /></a></li>																
    <li id="balanceshowlink" style="display:none;"><a title="Show Balances" href="#" onclick="javascript:showHide('balancehidelink', 1);showHide('balanceshowlink', 0);showHideGroup(balancesShowHide, 1);"><img src="_images/showBalances.gif" align="middle" width="41" height="16" name="showBalances" alt="Show Balances" /></a></li>
    			
    
    <li id="noteshidelink"><a title="Hide Notes" href="#" onclick="javascript:showHide('notesshowlink', 1);showHide('noteshidelink', 0);showHideGroup(notesShowHide, 0);"><img src="_images/hideNotes.gif" align="middle" width="41" height="16" name="hideNotes" alt="Hide Notes" /></a></li>																
    <li  id="notesshowlink" style="display:none;"><a title="Show Notes" href="#" onclick="javascript:showHide('noteshidelink', 1);showHide('notesshowlink', 0);showHideGroup(notesShowHide, 1);"><img src="_images/showNotes.gif" align="middle" width="41" height="16" name="showNotes" alt="Show Notes" /></a></li>

    All of that worked perfectly. You can see a sample here. You can open any session by clicking on the little red plus beside a date. Then at the bottom where it says Customize Your View -- those are the 3 showHideGroups I'm talking about: Payments, Balances and Notes.

    The problem came when I wanted to insert new rows in the table. I would copy an existing row to use as a model, give all cells new IDs and add the new IDs to the appropriate variables above. Consistenly, the Balances and Notes columns in the new row would toggle just fine, but the Payments columns would break. I have spent hours and HOURS trying to figure this out and I'm still stumped. An obvious difference between the 3 columns is that Balances and Notes are both single cell columns, whereas Payments consists of lots of different cells, some with row or col spans. So I'm guessing the problem has something to do with that. However, the original table had the same number of cells and the same row and col spans and it worked just fine. Here's a sample where I just used a few rows and tried to duplicate one. You can see that you can still toggle Balances and Notes, and you can still open and close the session record, but if you try to toggle Payments, it breaks. Here's the URL . Can anyone tell me what's happening and how I can fix it?

  2. #2
    Programming Team silver trophybronze trophy
    Mittineague's Avatar
    Join Date
    Jul 2005
    Location
    West Springfield, Massachusetts
    Posts
    17,158
    Mentioned
    190 Post(s)
    Tagged
    2 Thread(s)

    error message

    Maybe this will help
    JavaScript - http://shrink-art.com/susan/school/seniorProject/beta10/showHideSample/singleClient.php
    Event thread: click
    Error:
    name: TypeError
    message: Statement on line 160: Could not convert undefined or null to object
    Backtrace:
    Line 160 of linked script http://shrink-art.com/susan/school/seniorProject/beta10/showHideSample/_scripts/myScripts.js
    el.style.display = "none";
    Line 173 of linked script http://shrink-art.com/susan/school/seniorProject/beta10/showHideSample/_scripts/myScripts.js
    showHide(group[i], show);
    Line 1 of script
    showHide("paymentshowlink", 1);
    showHide("paymenthidelink", 0);
    showHideGroup(paymentsShowHide, 0);
    At unknown location
    and
    JavaScript - http://shrink-art.com/susan/school/seniorProject/beta10/showHideSample/singleClient.php
    Event thread: click
    Error:
    name: TypeError
    message: Statement on line 156: Could not convert undefined or null to object
    Backtrace:
    Line 156 of linked script http://shrink-art.com/susan/school/seniorProject/beta10/showHideSample/_scripts/myScripts.js
    el.style.display = "";
    Line 173 of linked script http://shrink-art.com/susan/school/seniorProject/beta10/showHideSample/_scripts/myScripts.js
    showHide(group[i], show);
    Line 1 of script
    showHide("paymenthidelink", 1);
    showHide("paymentshowlink", 0);
    showHideGroup(paymentsShowHide, 1);
    At unknown location

  3. #3
    SitePoint Evangelist
    Join Date
    Aug 2005
    Posts
    574
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Oh my goodness. I had no idea. I have noticed an error that fairly consistently says, "el has no properties" and then refers to this part of the script:

    Code:
    function showHide(elementID, show)
    {
    	var el = document.getElementById(elementID);
    
    	if(show)
    	{
    		el.style.display = '';
    	}
    	else
    	{
    		el.style.display = 'none';
    	}
    
    	return false;
    }
    But I had no idea what that meant and it seemed to be working fine so I was just ignoring it. Guess that wasn't a good idea. I hadn't seen the error messages you generated.

    What DOES all that mean? Can anyone decipher or at least start me in the right direction? I understand bits and pieces of it but not enough to know how to fix it or even really what's wrong. Maybe . . . does it mean that I have to give each element I plan to showHide a display style, even if it's just display=' '?

  4. #4
    Programming Team silver trophybronze trophy
    Mittineague's Avatar
    Join Date
    Jul 2005
    Location
    West Springfield, Massachusetts
    Posts
    17,158
    Mentioned
    190 Post(s)
    Tagged
    2 Thread(s)

    null - undefined error

    Those are js error messages from the Opera error console.
    Firefox simply says
    el has no properties
    The problem is that this line
    Code:
    var el = document.getElementById(elementID);
    is not getting an element with the id "elementID" to create the el object. Thus, when either the el.style.display = "none"; or el.style.display = ""; lines try to assign a style.display value to the el object the object doesn't exist.
    You could try trouble-shooting by temporarily adding an alert to the script
    Code:
    function showHide(elementID, show)
    {
    /* ALERT ADDED FOR DEBUGGING */
    alert("elementID: " + elementID + " show: " + show);
    	var el = document.getElementById(elementID);
    
    	if(show)
    	{
    		el.style.display = '';
    	}
    	else
    	{
    		el.style.display = 'none';
    	}
    
    	return false;
    }

  5. #5
    SitePoint Evangelist
    Join Date
    Aug 2005
    Posts
    574
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That helped enormously. The solution I came up with mystifies me, though. What I ended up having to do is to go back and make sure all the payment IDs were in order like payments1, payments2, etc. Why was that causing it to break? All the correct names were in both the HTML and the script, but because they weren't appearing in the same order in the HTML that they were in in the script, it wasn't working.

    Also, is there a way around this? It's sort of a pain to have to completely rename all the IDs every time I make a change in the table. The example wasn't hard because there were only 30 or so of them. But the real thing has close to 300. And I tend to redo it every time I turn around. Yikes!

  6. #6
    Programming Team silver trophybronze trophy
    Mittineague's Avatar
    Join Date
    Jul 2005
    Location
    West Springfield, Massachusetts
    Posts
    17,158
    Mentioned
    190 Post(s)
    Tagged
    2 Thread(s)

    in order

    You certainly want to not have to do a major edit every time you make a slight modification. Seems that getElementId would work no matter where the element was. This sounds like an array is in play somewhere. Like a getElementsByTagName. Maybe the showHideGroup function?

  7. #7
    SitePoint Evangelist
    Join Date
    Aug 2005
    Posts
    574
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the response. I'm baffled by this. I thought the order of the ID names wouldn't matter, either. The showHideGroup function does call an array:

    Code:
    function showHideGroup(group, show)
    /*
    	Group should be an array with names of elements to hide.
    */
    {
    	for(i=0; i<group.length; i++)
    	{
    		showHide(group[i], show);
    	}
    }
    And I declared the array variable in the script here:

    Code:
    var paymentsShowHide = ['showHidePayments', 'payments1', 'payments2', 'payments3' . . . 'paymentsn']
    Then I call it (along with some of the single showHide functions) here:

    HTML Code:
    <li id="paymenthidelink"><a title="Hide Payments" href="#" onclick="javascript:showHide('paymentshowlink', 1);showHide('paymenthidelink', 0);showHideGroup(paymentsShowHide, 0);"><img src="_images/hidePayments.gif" align="middle" width="41" height="16" name="hidePayments" alt="Hide Payments" /></a></li>																
    <li id="paymentshowlink" style="display:none;"><a title="Show Payments" href="#" onclick="javascript:showHide('paymenthidelink', 1);showHide('paymentshowlink', 0);showHideGroup(paymentsShowHide, 1);"><img src="_images/showPayments.gif" align="middle" width="41" height="16" name="showPayments" alt="Show Payments" /></a></li>
    I wasn't sure what you meant by getElementsByTagName. Were you thinking that might be interfering? I didn't think I had used that anywhere, but I did a search and it turns out that the tabtastic scripts I'm using for my tabs do use that in several places:

    It's in addcss.js (to add the stylesheet) -- probably no issue here since it's only looking for the head tag:

    Code:
    function AddStyleSheet(url,idx){
    	var css,before=null,head=document.getElementsByTagName("head")[0];
    
    	if (document.createElement){
    		if (url){
    			css = document.createElement('link');
    			css.rel  = 'stylesheet';
    			css.href = url;
    		} else css = document.createElement('style');
    		css.media = 'all';
    		css.type  = 'text/css';
    
    		if (idx>=0){
    			for (var i=0,ct=0,len=head.childNodes.length;i<len;i++){
    				var el = head.childNodes[i];
    				if (!el.tagName) continue;
    				var tagName = el.tagName.toLowerCase();
    				if (ct==idx){
    					before = el;
    					break;
    				}
    				if (tagName=='style' || tagName=='link' && (el.rel && el.rel.toLowerCase()=='stylesheet' || el.type && el.type.toLowerCase()=='text/css') ) ct++;
    			}
    		}
    		head.insertBefore(css,before);
    
    		return document.styleSheets[before?idx:document.styleSheets.length-1];
    	} else return alert("I can't create a new stylesheet for you. Sorry.");
    }
    // e.g. var newBlankSheetAfterAllOthers = AddStyleSheet(); 
    // e.g. var newBlankSheetBeforeAllOthers = AddStyleSheet(null,0);
    // e.g. var externalSheetAfterOthers = AddStyleSheet('http://phrogz.net/JS/Classes/docs.css');
    // e.g. var externalSheetBeforeOthers = AddStyleSheet('http://phrogz.net/JS/Classes/docs.css',0);
    
    
    // Cross-browser method for inserting a new rule into an existing stylesheet.
    // ss       - The stylesheet to stick the new rule in
    // selector - The string value to use for the rule selector
    // styles   - The string styles to use with the rule
    function AddRule(ss,selector,styles){
    	if (!ss) return false;
    	if (ss.insertRule) return ss.insertRule(selector+' {'+styles+'}',ss.cssRules.length);
    	if (ss.addRule){
    		ss.addRule(selector,styles);
    		return true;
    	}
    	return false;
    }
    
    // e.g. AddRule( document.styleSheets[0] , 'a:link' , 'color:blue; text-decoration:underline' );
    // e.g. AddRule( AddStyleSheet() , 'hr' , 'display:none' );
    It's also in tabtastic.js, which is the main tabtastic file. This one does target the ul tag and my links to trigger my showHideGroup are in a ul tag. I don't know if that's messing things up or not but here's tabtastic.js:

    Code:
    //*** This library is copyright 2004 by Gavin Kistner, gavin@refinery.com
    //*** It is covered under the license viewable at http://phrogz.net/JS/_ReuseLicense.txt
    //*** Reuse or modification is free provided you abide by the terms of that license.
    //*** (Including the first two lines above in your source code mostly satisfies the conditions.)
    
    //*** Tabtastic -- see http://phrogz.net/JS/Tabstatic/index.html
    //*** Version 1.0    20040430   Initial release.
    //***         1.0.2  20040501   IE5Mac, IE6Win compat.
    //***         1.0.3  20040501   Removed IE5Mac/Opera7 compat. (see http://phrogz.net/JS/Tabstatic/index.html#notes)
    //***         1.0.4  20040521   Added scroll-back hack to prevent scrolling down to page anchor. Then commented out :)
    
    AttachEvent(window,'load',function(){
    	var tocTag='ul', tocClass='tabsetTabs', tocClass1='tabsetTabsMain', tabTag='a',contentClass='tabsetContent';
    
    
    	function FindEl(tagName,evt){
    		if (!evt && window.event) evt=event;
    		if (!evt) return DebugOut("Can't find an event to handle in DLTabSet::SetTab",0);
    		var el=evt.currentTarget || evt.srcElement;
    		while (el && (!el.tagName || el.tagName.toLowerCase()!=tagName)) el=el.parentNode;
    		return el;
    	}
    
    	function SetTabActive(tab){
    		if (tab.tabTOC.activeTab){
    			if (tab.tabTOC.activeTab==tab) return;
    			KillClass(tab.tabTOC.activeTab,'active');
    			if (tab.tabTOC.activeTab.tabContent) KillClass(tab.tabTOC.activeTab.tabContent,'tabsetContent_active');
    			//if (tab.tabTOC.activeTab.tabContent) tab.tabTOC.activeTab.tabContent.style.display='';
    			if (tab.tabTOC.activeTab.prevTab) KillClass(tab.tabTOC.activeTab.previousTab,'preActive');
    			if (tab.tabTOC.activeTab.nextTab) KillClass(tab.tabTOC.activeTab.nextTab,'postActive');
    		}
    		AddClass(tab.tabTOC.activeTab=tab,'active');
    		if (tab.tabContent) AddClass(tab.tabContent,'tabsetContent_active');				
    		//if (tab.tabContent) tab.tabContent.style.display='block';
    		if (tab.prevTab) AddClass(tab.prevTab,'preActive');
    		if (tab.nextTab) AddClass(tab.nextTab,'postActive');
    	}
    	function SetTabFromAnchor(evt){
    		//setTimeout('document.body.scrollTop='+document.body.scrollTop,1);
    		SetTabActive(FindEl('a',evt).semanticTab);
    	}
    
    	
    	function Init(){
    		window.everyTabThereIsById = {};
    		
    		var anchorMatch = /#([a-z][\w.:-]*)$/i,match;
    		var activeTabs = [];
    		
    		var tocs = document.getElementsByTagName(tocTag);
    		for (var i=0,len=tocs.length;i<len;i++){
    			var toc = tocs[i];
    			//if (!HasClass(toc,tocClass)) continue;
    if (!HasClass(toc,tocClass) && !HasClass(toc, tocClass1)) continue;
    			var lastTab;
    			var tabs = toc.getElementsByTagName(tabTag);
    			for (var j=0,len2=tabs.length;j<len2;j++){
    				var tab = tabs[j];
    				if (!tab.href || !(match=anchorMatch.exec(tab.href))) continue;
    				if (lastTab){
    					tab.prevTab=lastTab;
    					lastTab.nextTab=tab;
    				}
    				tab.tabTOC=toc;
    				everyTabThereIsById[tab.tabID=match[1]]=tab;
    				tab.tabContent = document.getElementById(tab.tabID);
    				
    				if (HasClass(tab,'active')) activeTabs[activeTabs.length]=tab;
    				
    				lastTab=tab;
    			}
    			AddClass(toc.getElementsByTagName('li')[0],'firstchild');
    		}
    
    		for (var i=0,len=activeTabs.length;i<len;i++){
    			SetTabActive(activeTabs[i]);
    		}
    
    		for (var i=0,len=document.links.length;i<len;i++){
    			var a = document.links[i];
    			if (!(match=anchorMatch.exec(a.href))) continue;
    			if (a.semanticTab = everyTabThereIsById[match[1]]) AttachEvent(a,'click',SetTabFromAnchor,false);
    		}
    		
    		if ((match=anchorMatch.exec(location.href)) && (a=everyTabThereIsById[match[1]])) SetTabActive(a);
    		
    		//Comment out the next line and include the file directly if you need IE5Mac or Opera7 support.
    		AddStyleSheet('tabtastic.css',0);
    	}
    	Init();
    },false);
    Is that causing a problem?


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
  •