Tuesday, February 10, 2009

Validation with hidden TabPanels in the ASP.NET Ajax Control Toolkit TabContainer

This one is a bit of a never ending story, unfortunately. After having found out how to hide tabs, I added validation logic to my TabContainer, only to find another bug:

When hiding a TabPanel by setting the Enabled property to false, any validation controls on that panel are still enabled. This is not what I expected, as with other types of panels, the Enabled property usually cascades down. Of course this results in validation errors displayed for hidden tabs.

I am now using the following (clumsy) work around to disable tabs:

 

    public static void DisableTab(TabPanel panel)

    {

        panel.Enabled = false;

 

        //work around TabPanel bug and disable the validation controls

        DisableValidationControls(panel);

    }

 

    private static void DisableValidationControls(Control c)

    {

        foreach (Control child in c.Controls)

        {

            if (child is BaseValidator)

                ((BaseValidator)child).Enabled = false;

            else

                DisableValidationControls(child);

        }

    }

Lets hope that the quality of the control toolkit gets improved soon.

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.