Thursday, February 05, 2009

How to hide TabPanels of the ASP.NET Ajax control toolkit’s TabContainer

When developing a user interface with tabs, sometimes you want to hide individual tabs from the user. For example a tab may be shown only to some users, or for some objects with extra properties. When I was implementing this recently with the ASP.NET Ajax control toolkit implementation of tabs, I ran into several issues. Here is how I got it to work:

When hiding a TabPanel from the server side code, I considered two options: Remove the TabPanel from the TabContainers collection of TabPanels, or set the Visible property of the TabPanel to false. Both these options follow common conventions of the .NET framework, but it turns out that both are wrong here.

First I removed the TabPanel from the TabContainer. However after a postback the server always complained about the view state (I am not sure about the cause of this – if you have any idea, please let me know).

Next I tried to set the Visible property of the TabPanel to false. This worked fine with a postback at first. However, the tabs implementation has another issue with postbacks: after each postback it forgets the currently active panel, and sets this back to the first panel. There are two ways to solve this issue: Use an UpdatePanel inside each TabPanel that does postbacks, or in the event handler of the postback (or auto postback), reset the currently active tab panel.

In my case, I had some controls on the TabPanels that would not work inside an UpdatePanel, so I had to use the work around of resetting the currently active tab panel. However, it turns out that setting the active tab panel does not work if you have set some tab panel’s visible property to false. As ASP.NET is not rendering invisible controls to the client, the tab’s Javascript implementation is not aware of them. This Javascript however seems to be implemented in a naive way, and just counts through the panels. For example if panel 2 is hidden, and you set the active panel to 3, the Javascript is actually going to show panel 4, as it is not aware of the 2nd hidden panel.

I inspected the Javascript code a little bit and found that the code is actually aware of the Enabled property of the panels. I would have expected setting the Enabled property to false would result in a grayed out panel, as is the convention. However, the panels are really not shown at all. In my case the following work around was possible:

  1. Set the Enabled property of a TabPanel to false to hide it.
  2. Wrap every TabPanel with postback or auto postbacks into an UpdatePanel.
  3. Where UpdatePanel is not possible, in the event handler of the (auto) postback, reset the TabContainer’s active tab panel.

WARNING: This work around comes at a price. Because you are setting the Enabled property to false, and not the Visible property, the “hidden” tabs are actually send to the client. While they are not rendered, the user can still access the contents with a simple “view source” in his browser. Therefore this work around should not be used, if the content of the hidden tabs is secret or contains other sensitive information. END OF WARNING

I hope that the quality of the tabs implementation is increased in the next version, specifically:

  • Fix the issue of the TabContainer forgetting the active tab on postbacks (issue 8255 and 12838).
  • Handle the Visible property of the TabPanel correctly, avoiding the security issue with the Enabled property.
  • Handle the Enabled property of the TabPanel as by convention, i.e. show the panels grayed out (issue 9171).

I have added links to the control toolkit issue tracker at Codeplex, please consider voting for the issues.

Update: There is also an issue with validation, see my separate post.

8 comments:

Anonymous said...

Martin--
Thanks for the post, this helped me fix similar issues I was having.

I was able to fix your security and validation issues by wrapping everything inside the [ContentTemplate] of the hidden [TabPanel] in an [asp:panel]. Whenever I set the TabPanel.Enabled = False, I also set asp:Panel.Visible = False.

This causes the validation to work properly (since the controls are no longer rendered, their validation doesn't fire) and there is no longer a security issue since the content isn't rendered.

I imagine that some ambitious programmer could inherit the ajax:TabPanel control and add this functionality at the base level so that all of the Tabs in the system operate properly.

Let's hope these issues are fixed in an update, but until then...

--Rich (Albany, NY)

JK said...

Just to share with everyone that has been bugged by this issue. I have got an workaround. Please visit my blog at:

http://jkallaboutdotnet.blogspot.com/2009/07/how-to-hide-tabpanel-ajax-30305120.html

Thanks!

me said...

Thank you Martin - I did as you suggested..

Set the Enabled property of a TabPanel to false to hide it.
Wrap every TabPanel with postback or auto postbacks into an UpdatePanel.

and it works! I've been fighting with this bug for hours!

FWIW I tried JK's tabcontainer subclass but his code was not complete - it references dt.rows which is not defined..

Anonymous said...

Hi I am having a strange problem with the tab panel. I have two tab panel in my tab container and i need o load only one tab panel and on click of a hyperlink in first tab panel the seconf panel should be shown. The problem which i am facing is the seconf tab panel code also is shown in the same tab panel.

krankenversicherungsvergleich-2 said...

thanks alot. it is very helpful info. regards

Brandon said...

Thanks for the post! I originally was having problems with the content of 1 tab bleeding to the next on a postback. That seemed be the result of setting the Visible property on a previous tab to false. Hence, Javascript was trying to hide the wrong tab. Using the Enabled property worked great!

-- Brandon

Anonymous said...

In newer verson of Ajax Toolkit v(4.1.50508.0), this fix is not working. It is disabling tab instead of hiding it.

I added css style to hide the tab.

.ajax__tab_disabled
{
display:none;
}

in code behind:

tab1.Enabled=False

Srinivasa Rao Ranga said...

thanks boss

working fine