Friday, December 26, 2008

Conditionally display ConfirmButtonExtender

ConfirmButtonExtender is a nice way to build a kindly ModalPopup ConfirmPanel. Sometimes, we hope to show ConfirmButtonExtender only if it satisfies certain conditions, rather than it's popped out once we click the button.
For example, I have a RequiredFieldValidator Validation control on the page. ConfirmButtonExtender should not display even though I click the submit button untill I input something in the TextBox.

See the code:

<body>
    <form id="form1" runat="server">
        <ajaxToolkit:toolkitscriptmanager runat="Server" EnablePartialRendering="true"
            ID="ScriptManager1" />
   
        <asp:TextBox ID="TextBox1" runat="server" ></asp:TextBox>  
        <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ErrorMessage="RequiredFieldValidator" ControlToValidate="TextBox1"></asp:RequiredFieldValidator>

        <asp:Button ID="Button" runat="server" Text="Click Me" OnClientClick="disableSubmit();return false;" OnClick="Button_Click" /><br />
        <br />
        Server Time Refresh: <asp:Label ID="Label1" runat="server" Text=""></asp:Label>
        <asp:Button ID="HiddenButton" runat="server" Text="Hiddenbutton" style="display:none;" /><br />    
        <ajaxToolkit:ConfirmButtonExtender ID="ConfirmButtonExtender2" runat="server"
            TargetControlID="HiddenButton"
            OnClientCancel="cancelClick" BehaviorID="ConfirmButtonBehavior"
            DisplayModalPopupID="ModalPopupExtender1"  />
        <br />
        <ajaxToolkit:ModalPopupExtender ID="ModalPopupExtender1" runat="server"
        TargetControlID="HiddenButton"
        PopupControlID="PNL"
        OkControlID="ButtonOk"
        CancelControlID="ButtonCancel" BackgroundCssClass="modalBackground"
        />
        <asp:Panel ID="PNL"  runat="server" style="display:none; width:200px; background-color:White; border-width:2px; border-color:Black; border-style:solid; padding:20px;">
            Are you sure you want to click the Button1?
            <br /><br />
            <div style="text-align:right;">
                <asp:Button ID="ButtonOk" runat="server" Text="OK" OnClientClick="onOkScript()" />
                <asp:Button ID="ButtonCancel" runat="server" Text="Cancel" />
            </div>
        </asp:Panel>
    </form>
</body>
<script type="text/javascript">

function disableSubmit()
{
    if (typeof(Page_ClientValidate)=='function')
    {
        if (Page_ClientValidate() == true)
        {
            return checkSubmit();
        }
        else
        {
            return true;
        }
    }
    else
    {
        return checkSubmit();
    }
}

function checkSubmit() {

    var confirmButton = $find('ConfirmButtonBehavior');
   
    confirmButton._displayConfirmDialog();

}
function onOkScript() {
    var confirmButton = $find('ConfirmButtonBehavior');
    confirmButton._postBackScript = "__doPostBack(\u0027Button\u0027,\u0027\u0027)"; //reset bind onto Button

}
</script>



protected void Button_Click(object sender, EventArgs e)
{
    Label1.Text = "You clicked the " + ((Control)sender).ID + " at " + DateTime.Now.ToLongTimeString() + ".";
}

Thursday, December 25, 2008

Custom AutoComplete 4: Build an UpdateProgress for AutoComplete

I have introduced some kinds of Custom AutoComplete. Again, there is an another one -- Build an UpdateProgress for AutoComplete.

Check the code directly:

<head runat="server">
    <title>Untitled Page</title>
    <style>
        .autocomplete_completionListElement
        {
            visibility: hidden;
            margin: 0px !important;
            background-color: inherit;
            color: windowtext;
            border: buttonshadow;
            border-width: 1px;
            border-style: solid;
            cursor: 'default';
            overflow: auto;
            height: 200px;
            text-align: left;
            list-style-type: none;
            font-family: courier new;
            font-size: 8pt;
        }
        /* AutoComplete highlighted item */.autocomplete_highlightedListItem
        {
            background-color: #e3ec6e;
            color: black;
            padding: 1px;
        }
        /* AutoComplete item */.autocomplete_listItem
        {
            background-color: window;
            color: windowtext;
            padding: 1px;
        }
        body, div, p, h1, h2, h3, h4, ul, li, table
        {
            margin: 0;
            padding: 0;
            border: none;
        }
    </style>
</head>

<script type="text/javascript">
    function pageLoad() {
        $find('autocomplteextender1').add_populated(shownev); //if no result, this event will not be triggered and "loading" can't be hidden. But if result is exist, hiding event will be triggered when the user selects value to hide popuplist.So we need populated event to hide "loading" when the result is not empty.

        $find('autocomplteextender1').add_populating(populatingev);
        $find('autocomplteextender1').add_hiding(onhiding); // no matter the result is empty or not, hiding event will be triggered. If the result is empty, it will trigger hiding event after response returned. If the result is exist, hiding event will be triggered after user selected value to hide popuplist.
    }
    function onhiding() {

        var updateProgress = $get('<%= UpdateProgress2.ClientID %>');
        var dynamicLayout = '<%= UpdateProgress2.DynamicLayout.ToString().ToLower() %>';

        if (dynamicLayout) {
            updateProgress.style.display = "none";
        }
        else {
            updateProgress.style.visibility = "hidden";
        }
    }
    function shownev() {
        var updateProgress = $get('<%= UpdateProgress2.ClientID %>');
        var dynamicLayout = '<%= UpdateProgress2.DynamicLayout.ToString().ToLower() %>';

        if (dynamicLayout) {
            updateProgress.style.display = "none";
        }
        else {
            updateProgress.style.visibility = "hidden";
        }

    }
    function populatingev() {
        var updateProgress = $get('<%= UpdateProgress2.ClientID %>');
        var dynamicLayout = '<%= UpdateProgress2.DynamicLayout.ToString().ToLower() %>';

        if (dynamicLayout) {
            updateProgress.style.display = "block";
        }
        else {
            updateProgress.style.visibility = "visible";
        }


    }

</script>

<body>
    <form id="form2" runat="server">
    <asp:ScriptManager ID="ScriptManager2" runat="server" />
    <asp:UpdateProgress ID="UpdateProgress2" runat="server">
        <ProgressTemplate>
            loading...
        </ProgressTemplate>
    </asp:UpdateProgress>   
    <asp:TextBox ID="TextBox1" runat="server" Width="437px"></asp:TextBox>
    <cc1:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server" BehaviorID="autocomplteextender1"
        MinimumPrefixLength="1" ServicePath="AutoComplete.asmx" ServiceMethod="GetCompletionList1"
        TargetControlID="TextBox1" CompletionListCssClass="autocomplete_completionListElement"
        CompletionListItemCssClass="autocomplete_listItem" CompletionListHighlightedItemCssClass="autocomplete_highlightedListItem"
        CompletionInterval="1000" DelimiterCharacters=";" CompletionSetCount="10" FirstRowSelected="true"
        EnableCaching="true" Enabled="true">
    </cc1:AutoCompleteExtender>

    </form>
</body>

Thursday, December 18, 2008

Custom AutoComplete 3: Check if AutoComplete List has result items

This kide of requirement I encountered many times.
When the prefixText the user inputed didn't cause any result items from AutoComplete, we need generate an alert for it. For example, the background of TextBox should become red if empty result occurs. See the below thumbnail.



When I'm during the process of typing "mary", the result of web method will be returned. After I type additional "x", the result is empty as "maryx" is not exist. Then the background becomes red.

We need rebuild the onMethodComplete function to attach a callback function after results are updated so that we can generate the alert meassage. Now we can see the code:

<head runat="server">
    <title></title>
    <style>
        .autocomplete_completionListElement
        {
            visibility: hidden;
            margin: 0px !important;
            background-color: inherit;
            color: windowtext;
            border: buttonshadow;
            border-width: 1px;
            border-style: solid;
            cursor: 'default';
            overflow: auto;
            height: 200px;
            text-align: left;
            list-style-type: none;
            font-family: courier new;
            font-size: 8pt;
        }
        /* AutoComplete highlighted item */.autocomplete_highlightedListItem
        {
            background-color: #e3ec6e;
            color: black;
            padding: 1px;
        }
        /* AutoComplete item */.autocomplete_listItem
        {
            background-color: window;
            color: windowtext;
            padding: 1px;
        }

    </style>
</head>

<script type="text/javascript">
    function pageLoad() {

        $find('autocomplteextender1')._onMethodComplete = function(result, context) {

            $find('autocomplteextender1')._update(context, result, /* cacheResults */false);
            webservice_callback(result, context);
        };

    }
    function webservice_callback(result, context) {

        if (result == "")
            $find("autocomplteextender1").get_element().style.backgroundColor = "red";
        else
            $find("autocomplteextender1").get_element().style.backgroundColor = "white";
    }

</script>

<body>
    <form id="form2" runat="server">
    <asp:ScriptManager ID="ScriptManager2" runat="server" />
    <asp:UpdatePanel ID="uppanle1abcxyz" runat="server">
        <ContentTemplate>
            <asp:TextBox ID="TextBox1" runat="server" Width="150px"></asp:TextBox>
            <cc1:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server" BehaviorID="autocomplteextender1"
                MinimumPrefixLength="1" ServicePath="AutoComplete.asmx" ServiceMethod="GetCompletionList1"
                TargetControlID="TextBox1" CompletionListCssClass="autocomplete_completionListElement"
                CompletionListItemCssClass="autocomplete_listItem" CompletionListHighlightedItemCssClass="autocomplete_highlightedListItem"
                CompletionInterval="500" DelimiterCharacters=";" CompletionSetCount="10" Enabled="true">
            </cc1:AutoCompleteExtender>
        </ContentTemplate>
    </asp:UpdatePanel>
    </form>
</body>

Wednesday, December 3, 2008

How to do somthing(call JavaScript code) after AnimationExtender completed

Many engineers use AjaxControlToolkit AnimationExtender to achieve the animation process. It encapsulates JavaScript library to achieve.
Now there is a scenario: When the AnimationExtender is completed, how can we do some JavaScript? For example:

<asp:ImageButton ID="ib1" ImageUrl="~/images/AJAX.gif" OnClientClick="return false;"  Height="100px" Width="100px" runat="server" />
<ajaxToolkit:AnimationExtender id="OpenAnimation" runat="server" BehaviorID="AnimationBehavior"  TargetControlID="ib1" >
   <Animations>
        <OnClick>
           <Sequence>
           <EnableAction Enabled="false" />              
           <Pulse Duration=".1" />
           <Parallel AnimationTarget="ib1" Duration=".3" Fps="30">
             <FadeOut />
               <Scale ScaleFactor="5" Unit="px" Center="true"  ScaleFont="true" FontUnit="pt" />
           </Parallel>              
           <StyleAction Attribute="postbackurl" Value="~/Default.aspx"/>
         </Sequence>
        </OnClick>
     </Animations>
</ajaxToolkit:AnimationExtender>



With the above sample, it will do Animation after you click the imagebutton. But now, we want to make it redirect to a new page after clicking the imagebutton and completing the Animation. If you define imagebutton OnClick event, it will not be triggered because OnClientClick returns false. If you remove out OnClientClick="return false;", it will do postback directly when you click the button, rather than waiting the completion of animation. Maybe we can call some client event, which will be triggered after AnimationExtender is completed. But the problem is AnimationBehavior hasn't any client event about onCompleted.

Actually, I'd like to make a way to achieve it: we can build an Animation object to contact with the AnimationBehavior, receive the Animation instance from it and declare OnEnd client event of Animation object.


<script type="text/javascript">

     function pageLoad() {
         var animation =$find('AnimationBehavior')._onClick.get_animation();
         animation.add_ended(onend);
     }
     function onend() {
         window.location.href = "../../../Default.aspx";
    
     }

</script>


Now, after you click the imagebutton, it will do the Animation. After anything is completed, it will go to the new page.

Thursday, November 27, 2008

Build a Combobox in ASP.Net

As we all known, DropDownList in ASP.Net is totally different from Combobox in WinForm. However, sometimes, we hope we are able to input some words in DropDownList in ASP.Net, and the related item will be hightlighten so that we can get the functionality of Combobox in WinForm.


Fortunately, AjaxControlToolkit provides ListSearch control for us to achieve this(http://www.asp.net/AJAX/AjaxControlToolkit/Samples/ListSearch/ListSearch.aspx). But we have to build two controls to populate the functionality and type the key words above the select control.


It's still different from Combobox in Winform. We hope we can type the words inside DropDownList and the related item will be returned in the list as the below pic.
How can we achieve that?
I rebuild the whole select control with HTML code and Css so that I can input text inside select control.


Default.aspx:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>combobox</title>
    <link href="ListSearch.css" rel="stylesheet" type="text/css" />
</head>

<script type="text/javascript">
    var dropShow = false
    var currentID
    function dropdown(el) {
        if (dropShow) {
            dropFadeOut()
        } else {
            currentID = el
            el.style.visibility = "visible"
            dropFadeIn()
        }
    }
    function dropFadeIn() {//select box fade in
        if (currentID.filters.alpha.opacity < 100) {
            currentID.filters.alpha.opacity += 20
            fadeTimer = setTimeout("dropFadeIn()", 50)
        } else {
            dropShow = true
            clearTimeout(fadeTimer)
        }
    }
    function dropFadeOut() {//select box fade out
        if (currentID.filters.alpha.opacity > 0) {
            clearTimeout(fadeTimer)
            currentID.filters.alpha.opacity -= 20
            fadeTimer = setTimeout("dropFadeOut()", 50)
        } else {
            dropShow = false
            currentID.style.visibility = "hidden"
        }
    }
    function dropdownHide() {
        if (dropShow) {
            dropFadeOut()
            dropShow = false
        }
    }
    function hiLight(el) {//highlight place
        if (dropShow) {
            for (i = 0; i < el.parentElement.childNodes.length; i++) {
                el.parentElement.childNodes(i).className = "link_record0"
            }
            el.className = "link_record1"
        }
    }
    function CheckMe(el) {//replace with the selected item
        document.all.text1.value = el.innerText

    }
    document.onclick = dropdownHide


    function listsearch() {
        if (dropShow) {

        } else {
            currentID = value1
            value1.style.visibility = "visible"
            dropFadeIn()
        }
        var word = document.all.text1.value;
        var l;
        var childsnum = value1.childNodes.length;
        for (l = 0; l < childsnum; l++) {
            var s = value1.childNodes[l].innerText;

            if (s.substring(0, word.length) == word)
                hiLight(value1.childNodes[l]);

        }

    }
</script>

<body text="#000000">
    <form id="form1" runat="server">
    <table>
        <tr>
            <td>
                <div class="link_box" onselectstart="return false" style="width: 98%;">
                    <div class="link_head" onclick="dropdown(value1)">
                        <table height="100%" cellspacing="0" cellpadding="0" width="100%" border="0">
                            <tr>
                                <td>
                                    <div class="link_text">
                                        <nobr><input id="text1" type="text" onkeyup="listsearch()"></input></nobr>
                                    </div>
                                </td>
                                <td align="right" width="22">
                                    <div onmouseup="this.className='link_arrow0'" class="link_arrow0" onmousedown="this.className='link_arrow1'"
                                        onkeypress="this.className='link_arrow0'">
                                        6</div>
                                </td>
                            </tr>
                        </table>
                    </div>
                    <div class="link_value" id="value1" style="width: 500px; height: 300px">
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                attach</label></div>
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                bea</label></div>
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                free</label></div>
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                jump</label></div>
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                lumb</label></div>
                        <div class="link_record0" onmouseover="hiLight(this)" onclick="CheckMe(this);document.all.form1.city.value=this.innerText">
                            <label>
                                luppy</label></div>
                    </div>
                </div>
            </td>
            <td>
                <input type="hidden" value="Please Select" name="city">
                <input type="submit" value="ok">
            </td>
        </tr>
    </table>
    </form>
</body>
</html>


ListSearch.css:

BODY {
FONT: 12px
}
TD {
FONT: 12px
}
DIV {
FONT: 12px
}
LABEL {
PADDING-RIGHT: 0px; PADDING-LEFT: 4px; PADDING-BOTTOM: 0px; PADDING-TOP: 3px; HEIGHT: 19px
}
.link_box {
CURSOR: default; TEXT-ALIGN: left;
}
.link_head {
BORDER-RIGHT: 2px inset; BORDER-TOP: 2px inset; BORDER-LEFT: 2px inset; WIDTH: 100%;
BORDER-BOTTOM: 2px inset; HEIGHT: 23px
}
.link_text {
PADDING-LEFT: 2px; BACKGROUND: #fff
}
.link_arrow0 {
BORDER-RIGHT: 2px outset; BORDER-TOP: 2px outset; BACKGROUND: buttonface;
FONT: 14px marlett; BORDER-LEFT: 2px outset; WIDTH: 22px;
BORDER-BOTTOM: 2px outset; HEIGHT: 19px; TEXT-ALIGN: center
}
.link_arrow1 {
BORDER-RIGHT: buttonshadow 1px solid; PADDING-RIGHT: 0px;
BORDER-TOP: buttonshadow 1px solid; PADDING-LEFT: 2px;
BACKGROUND: buttonface; PADDING-BOTTOM: 0px; FONT: 14px marlett;
BORDER-LEFT: buttonshadow 1px solid; WIDTH: 22px; PADDING-TOP: 2px;
BORDER-BOTTOM: buttonshadow 1px solid; HEIGHT: 19px; TEXT-ALIGN: center
}
.link_value {
BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; FILTER: alpha(opacity:0);
VISIBILITY: hidden; OVERFLOW-X: hidden; OVERFLOW: auto; BORDER-LEFT: 1px solid;
BORDER-BOTTOM: 1px solid; POSITION: absolute
}
.link_record0 {
BORDER-TOP: #eee 1px solid; PADDING-LEFT: 2px; BACKGROUND: #fff;
WIDTH: 100%; COLOR: #000; HEIGHT: 20px
}
.link_record1 {
BORDER-TOP: #047 1px solid; PADDING-LEFT: 2px; BACKGROUND: #058;
WIDTH: 100%; COLOR: #fe0; HEIGHT: 20px
}


The sample is based on native code. I plan to build it by ASP.Net Ajax ScriptControl model in the future.