Showing posts with label TabContainer. Show all posts
Showing posts with label TabContainer. Show all posts

Tuesday, May 26, 2009

How to cancel Tab active changing with Validation

Sometimes, when you change the active Tab Panel, you want to do validation and check if it should go to next tabpanel. It will go to the new Tab Panel only if it is meets the validation.
For example, there is a TextBox in TabPanel. If TextBox is empty, I don't want to let it go to another TabPanel.
For this scenario, the validation is based on the client side. The first confirm is we have to use JavaScript to do validation or catch the validation result if you used Validation control. There is a client event "ActiveTabChanged"(add_activeTabChanged method in behavior) of TabContainer you can make use of to do validation in this event. If it is valid, you can let it free to go. Overwise, you need use javascript to let it back to the previous tab. In this way, you need use a client validation to restore the history of the active tab index so that it can remeber which tab panel it can go back to in JavaScript .
But in this approach, it is go through the ActiveChanged client event. It means the active tab has been changed before we call this event. We would see the active tab goes to another one and go back again if it is invalid with validation. It looks too stupid and ugly.

So, I got two approaches to achieve this.

1. We can modify the source code of Tab Panel behavior as below. In _header_onclick method, it calls raiseClick and set the activeTab directly. We can insert an additional code line before setting active tab so that we can do something on validation.

AjaxControlToolkit.TabPanel.prototype._header_onclick = function(e) {
this.raiseClick();
if (isValidated()) // add this validation method
this.get_owner().set_activeTab(this);
};

It won't go to another tab unless it meets the validation. See the entire code below:



<body>
<form id="form1" runat="server">
<ajaxToolkit:ToolkitScriptManager runat="Server" EnablePartialRendering="true" ID="ScriptManager1" />
<ajaxToolkit:TabContainer runat="server" ID="TabContainer1">
<ajaxToolkit:TabPanel runat="server" ID="TabPanel1" HeaderText="TabPanel1">
<ContentTemplate>
TabPanel1
<input type="text" id="text1" />
</ContentTemplate>
</ajaxToolkit:TabPanel>
<ajaxToolkit:TabPanel runat="server" ID="TabPanel2" HeaderText="TabPanel2">
<ContentTemplate>
TabPanel2
</ContentTemplate>
</ajaxToolkit:TabPanel>
</ajaxToolkit:TabContainer>
</form>
</body>

<script type="text/javascript">

AjaxControlToolkit.TabPanel.prototype._header_onclick = function(e) {
this.raiseClick();
if (isValidated()) // add this additional code line to do validation
this.get_owner().set_activeTab(this);

};

function isValidated() {
if ($get("text1").value == "")
return false;
return true;
}

</script>


2. The above code looks like a workround purely. The directly approach is using ActiveTabChanging client event. In general ASP.Net Ajax behavior model, we can call e.set_cancel(true) to cancel the changing behavior after validation, so we can prevent the active tab changing before ActiveTabChanged called.
Unfortunately, it doesn't contain this event in tab.js. The only public client event is add_activeTabChanged. So what I wanna saying is Let's make an add_activeTabChanging client event in tab.js behavior.

1) Please open tab.js in VS.
2) Please append the following code in AjaxControlToolkit.TabContainer.prototype = {


///<extended for activeTabChanging>
add_activeTabChanging: function(handler) {
this.get_events().addHandler("activeTabChanging", handler);
},
remove_activeTabChanging: function(handler) {
this.get_events().removeHandler("activeTabChanging", handler);
},
raiseActiveTabChanging: function(eventArgs) {
var eh = this.get_events().getHandler("activeTabChanging");
if (eh) {
eh(this, eventArgs);
}

},


///</extended for activeTabChanging>

3) Please modify set_activeTabIndex method block (The blod font is new code we need to append):



set_activeTabIndex : function(value) {
if (!this.get_isInitialized()) {
this._cachedActiveTabIndex = value;
} else {
///<extended for activeTabChanging>
var eventArgs = new Sys.CancelEventArgs();
this.raiseActiveTabChanging(eventArgs);
if (eventArgs.get_cancel()) {
return false;
}
///</extended for activeTabChanging>
if (value < -1 value >= this.get_tabs().length) {
throw Error.argumentOutOfRange("value");
}
if (this._activeTabIndex != -1) {
this.get_tabs()[this._activeTabIndex]._set_active(false);
}
this._activeTabIndex = value;
if (this._activeTabIndex != -1) {
this.get_tabs()[this._activeTabIndex]._set_active(true);
}
if (this._loaded) {

this.raiseActiveTabChanged();
}
this.raisePropertyChanged("activeTabIndex");

}
return true;
},


4) Then we can use add_activeTabChanging client event now. As the same HTML sample, you can just call this event on client to cancel the process if it doesn't meet the validation.


<body>
<form id="form1" runat="server">
<ajaxToolkit:ToolkitScriptManager runat="Server" EnablePartialRendering="true" ID="ScriptManager1" />
<ajaxToolkit:TabContainer runat="server" ID="TabContainer1">
<ajaxToolkit:TabPanel runat="server" ID="TabPanel1" HeaderText="TabPanel1">
<ContentTemplate>
TabPanel1
<input type="text" id="text1" />
</ContentTemplate>
</ajaxToolkit:TabPanel>
<ajaxToolkit:TabPanel runat="server" ID="TabPanel2" HeaderText="TabPanel2">
<ContentTemplate>
TabPanel2
</ContentTemplate>
</ajaxToolkit:TabPanel>
</ajaxToolkit:TabContainer>
</form>
</body>

<script type="text/javascript">

function pageLoad() {

$find('TabContainer1').add_activeTabChanging(aa);

}
function aa(se, e) {

if ($get('text1').value == "")
e.set_cancel(true);
}


</script>

Tuesday, February 3, 2009

Dynamically create and remove TabPanel on client

TabContainer provides some method to create/remove TabPanel on server-side. However, we want to achieve this on client and needn't to do postback to server.
For example, we can build a button on the page so that it can create a tabpanel on client-side when you click it. The data in this dynamic tabpanel can be static existing in the page, or can be recieved from web service by Ajax. Then we can create a closed-button in each tabpanel header.

The following code can help you to achieve creating TabPanel on client on the fly.

<script type="text/javascript">
    var i = 3;
    function createnew() {

        CreateNewTabPanel('TabContainer1', 'TabPanel' + i, 'TabPanel' + i, 'TabPanel' + i);
        i++;

    
    }

    function CreateNewTabPanel(tabContainerID, tabPanelID, headerText, bodyText) {
        //create header
        var header = document.createElement('span');
        header.id = "__tab_" + tabContainerID + tabPanelID;
        header.innerHTML = headerText;
        $get(tabContainerID + "_header").appendChild(header);

        //create content
        var body = document.createElement('div');
        body.id = tabContainerID + "_" + tabPanelID;
        body.style.display = "none";
        body.style.visibility = "hidden";
        body.innerHTML = bodyText;
        body.cssClass = "ajax__tab_panel";
        $get(tabContainerID + "_body").appendChild(body);


        $create(AjaxControlToolkit.TabPanel, { "headerTab": $get(header.id) }, null, { "owner": tabContainerID }, $get(body.id));


    }


</script>
<body>
    <form id="form1" runat="server">
    <ajaxToolkit:ToolkitScriptManager runat="Server" EnablePartialRendering="true" ID="ScriptManager1" />
<span id="mes"></span><br />
<span id="mes1"></span>
    <ajaxToolkit:TabContainer runat="server" ID="TabContainer1"   >
            <ajaxToolkit:TabPanel runat="server" ID="TabPanel1" HeaderText="TabPanel1">
                <HeaderTemplate>
                    TabPanel1
                </HeaderTemplate>
            <ContentTemplate>  
                TabPanel1     
            </ContentTemplate>
        </ajaxToolkit:TabPanel> 
                    <ajaxToolkit:TabPanel runat="server" ID="TabPanel2" HeaderText="TabPanel2">
            <ContentTemplate>  
                TabPanel2     
            </ContentTemplate>
        </ajaxToolkit:TabPanel>             
    </ajaxToolkit:TabContainer>

    <input type="button" onclick="createnew()" value="create a new pane" />

    </form>
</body>



To remove the related TabPanel on client dynamically, please check the code as below:


<script type="text/javascript">
    function removeAt(tabPanelClientID,index) {

        var activeTabPanel = $find('<%=TabContainer1.ClientID%>').get_tabs()[index];

        var tabContainerID = "<%=TabContainer1.ClientID %>";

        $get(tabContainerID + "_header").removeChild($get(tabPanelClientID+"_tab"));

        $get(tabContainerID + "_body").removeChild($get(tabPanelClientID));

        activeTabPanel.dispose();

        $find('<%=TabContainer1.ClientID%>').set_activeTabIndex(index+1);
    }


</script>

<body>
    <form id="form1" runat="server">
    <input type="image" style="height: 14px; width: 14px" onclick="removeAt(this.alt);return false;"
        alt="0" src="../../../effect/PopupDiv-roundCorner/images/close.gif" />
    <ajaxToolkit:ToolkitScriptManager runat="Server" EnablePartialRendering="true" ID="ScriptManager1" />
    <ajaxToolkit:TabContainer runat="server" ID="TabContainer1">
        <ajaxToolkit:TabPanel runat="server" ID="TabPanel1">
            <HeaderTemplate>
                headertext0
                <input type="image" style="height: 14px; width: 14px" onclick="removeAt('<%=TabPanel1.ClientID %>',0);return false;"
                    alt="0" src="../../../effect/PopupDiv-roundCorner/images/close.gif" />
            </HeaderTemplate>
            <ContentTemplate>
                TabPanel1
            </ContentTemplate>
        </ajaxToolkit:TabPanel>
        <ajaxToolkit:TabPanel runat="server" ID="TabPanel2">
            <HeaderTemplate>
                headertext1
                <input type="image" style="height: 14px; width: 14px" onclick="removeAt('<%=TabPanel2.ClientID %>',1);return false;"
                    alt="1" src="../../../effect/PopupDiv-roundCorner/images/close.gif" />
            </HeaderTemplate>
            <ContentTemplate>
                TabPanel2
            </ContentTemplate>
        </ajaxToolkit:TabPanel>
        <ajaxToolkit:TabPanel runat="server" ID="TabPanel3">
            <HeaderTemplate>
                headertext2
                <input type="image" style="height: 14px; width: 14px" onclick="removeAt('<%=TabPanel3.ClientID %>',2);return false;"
                    alt="2" src="../../../effect/PopupDiv-roundCorner/images/close.gif" />
            </HeaderTemplate>
            <ContentTemplate>
                TabPanel3
            </ContentTemplate>
        </ajaxToolkit:TabPanel>
    </ajaxToolkit:TabContainer>
    </form>
</body>

Wednesday, January 21, 2009

Create a Vertical Tab

In this post, if you are familiar with Css Style and JavaScript, it should not be a difficult thing for you.

This time let's hit to create a Vertical Tab like the tab control in http://www.microsoft.com/. Have you seen the bottom tab content navigation in Microsoft home page http://www.microsoft.com/?

If you used TabContainer before, you must have thought it is really a vertical TabContainer. Now, we get to start from Zero, to create one by css and JavaScript.



See the line in the left section of image, it seems to be faded out and it's like a tail to the end. To achieve this, we have to prepare several images for it. The rest things are simple. (Just create some div in related sections)

Check the below code:

HTML:

<head runat="server">
    <title></title>
    <link href="AutoReport.css" rel="stylesheet" type="text/css" />

    <script src="AutoReport.js" type="text/javascript"></script>

</head>
<body>
    <form id="form1" runat="server">
    <div id="divAdmin">
        <div id="divAdmin_Content">
            <div id="divAdmin_LeftMenu">
                <div id="li-toptail">
                </div>
                <div id="liManager_User" onmouseover="HighLight_Li('liManager_User','liAdd_User','divManager_User','divAdd_User');">
                    Member</div>
                <div id="liAdd_User" onmouseover="HighLight_Li('liAdd_User','liManager_User','divAdd_User','divManager_User');">
                    Add User</div>
                <div class="li">
                </div>
                <div class="li">
                </div>
                <div class="li">
                </div>
                <div class="li">
                </div>
                <div class="li">
                </div>
                <div id="li-bottomtail">
                </div>
            </div>
            <div id="divAdmin_RightView">
                <div id="divManager_User">this is panel1
                </div>
                <div id="divAdd_User">this is panel2
                </div>
            </div>
        </div>
    </div>
    </form>
</body>


AutoReport.css

body
{
    /*font-family: "Trebuchet MS", Verdana, Tahoma, sans-serif;*/
    font-family:Tahoma,Verdana,Segoe,sans-serif;
    font-size: 12px;
    text-align: center;

    color: #666;

}
/*Admin*/
#divAdmin
{
    width: 550px;
}

#divAdmin_Header
{
    padding: 5px;
    background: url(Images/sprite.png) repeat-x 0px 0px;
    height: 22px;
    border: thin solid #D6D6C0;
    text-align: right;
    color: #666666;
}

#divAdmin_Content
{

}

#divAdmin_LeftMenu
{
    float:left;
    height: 350px;
    width: 86px;
    background-image: url('Images/leftmenu.png');
   
    border-left-width: thin;
    border-left-style: solid;
    border-left-color: #CFCFCF;
    border-bottom-style: solid;
    border-bottom-width: thin;
    border-bottom-color: #CFCFCF;
}

#divAdmin_RightView
{
    float: left;
    background-color: #EEEEEE;
    width: 460px;
    height: 350px;
    border-right-width: thin;
    border-right-style: solid;
    border-right-color: #CFCFCF;
    border-bottom-style: solid;
    border-bottom-width: thin;
    border-bottom-color: #CFCFCF;
}
.li
{
    height: 30px;
    width: 86px;
    background-image: url('Images/leftmenu-line.png') ;
}
#li-toptail
{
    background-image: url('Images/leftmenu-toptail.png') ;
    height: 30px;
    list-style-type:none;
    width: 86px;
   
}
#li-bottomtail
{
    background-image: url('Images/leftmenu-bottomtail.png') ;
    height: 30px;
    list-style-type:none;
    width: 86px;
   
}
#divManager_User
{
    padding-left:80px;
    display:block;
    text-align:left;
    padding-top: 5px;
}
#divAdd_User
{
    padding-left:80px;
    display:none;
    text-align:left;
    padding-top: 5px;
           
}
#liManager_User
{
    background-image: url('Images/leftmenu-litail.png') ;
    height: 30px;
    list-style-type:none;
    width: 86px;
}
#liAdd_User
{
    background-image: url(Images/leftmenu-line.png) ;
    height: 30px;
    list-style-type:none;
    width: 86px;
}


AutoReport.js

/*leftmenu onmouseover*/
function HighLight_Li(HighLight_Li,LowLight_Li,Display_div,Hidden_div)
{
    document.getElementById(HighLight_Li).style.backgroundImage='url(Images/leftmenu-litail.png)';
    document.getElementById(LowLight_Li).style.backgroundImage='url(Images/leftmenu-line.png)';
    document.getElementById(Display_div).style.display='block';
    document.getElementById(Hidden_div).style.display='none';
}




Several images need to download, and please put them in Image folder:
leftmenu-toptail.png


leftmenu-litail.png



leftmenu-line.png


leftmenu-bottomtail.png




leftmenu.png



sprite.png