Click here to Skip to main content
6,594,932 members and growing! (14,828 online)
Email Password   helpLost your password?
Web Development » Ajax and Atlas » Controls     Intermediate

Implementing an Ajax.NET-based Lookup Server Control

By firefalcon

The article describes how to build a Lookup server control based on the Ajax.NET framework.
C#, Javascript, XML, HTML, Windows, .NET, ASP.NET, Visual Studio, Ajax, Dev
Posted:31 Aug 2005
Views:85,608
Bookmarked:94 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
25 votes for this article.
Popularity: 5.37 Rating: 3.84 out of 5
2 votes, 8.0%
1

2
5 votes, 20.0%
3
3 votes, 12.0%
4
15 votes, 60.0%
5

Introduction

AJAX is one of the most popular buzz words today. The idea is not new, but for some reasons it became popular during the last half year. With web-applications' popularity growth, users demand richer and faster interfaces. And AJAX could very much improve the user experience in web applications.

Let me show you an example of real user requirements. One of our customers needed a way to quickly select user stories and bugs. For example, bugs could be linked to user stories and there was a drop down for that purpose. But when you have about 100 items in the drop down, it is just unusable and a lookup control would make the selection simpler (like Google Suggests). So we decided to use AJAX in our product to implement these features, improve the user interface and to make it more responsive.

AJAX is completely new for me. I had read some general articles to get some idea sometime ago, but didn't try anything due to the lack of tools and ready to use libraries. However, recently I found Ajax.NET � a quite powerful framework that supports asynchronous callbacks. The examples were simple and so I decided to use it to achieve my goal.

In this article, I'll describe my experience of creating a lookup control based on Ajax.NET. To build a lookup control, you need a few things:

  1. A server method that will return a list of matched records.
  2. JavaScript that will handle post-backs and show a list of matched records.
  3. An input field on an ASPX/ASCX page.

I will not describe the Ajax.NET installation here, since it is very simple and there are some great sources that you can check.

Server side part

This part was really simple. All I had to implement was one simple method that returns an ArrayList of matched records and register a class where this method is located:

public class Main : Page
{

    private void Page_Load(object sender, EventArgs e)
    {
        Utility.RegisterTypeForAjax(typeof (Main));
    }

    [AjaxMethod()]
    public ArrayList GetSearchItems(string query)
    {
        // use real method ti query data from database instead

        ArrayList items = GetRecords();

        ArrayList matchItems = new ArrayList();

        foreach (string item in items)
        {
            if (item.ToLower().StartsWith(query.ToLower()))
                matchItems.Add(item);
        }
        return matchItems;
    }

    private ArrayList GetRecords()
    {
        ArrayList items = new ArrayList();
        items.Add("Ted");
        items.Add("Teddy");
        items.Add("Mark");
        items.Add("Alfred");
        return items;
    }
. . .

The GetSearchItems method gets a list of all records from any source and filters those records that start with the query parameter. query is what the user types in the input field.

Client side part

First, I decided to write a very simple JavaScript that will show a DIV with the found records right under the query input field. I thought "One step closer". But it is required to select one of the items below. The simplest thing is to turn all items to hyperlinks and fill the query field with the correct value on click. Here is what I�ve got:

<INPUT id=search type=text name=search runat="server"
autocomplete ="off">
<div id="list"></div>

autocomplete="off" is required to tell the browser not to show the possible values for the input field. Otherwise our control will not work.

function GetSearchItems_CallBack(response) {
    var div = document.getElementById("list");
    div.innerHTML = "";
    if (response.value != null && response.value.length > 0) {
        for (var i = 0; i < response.value.length; ++i){
        div.innerHTML += 
          "<a href=\"javascript:Fill('" + response.value[i] + "');\">" + 
                                         response.value[i] + "</a><br />";
    } 
}

The JavaScript GetSearchItems_CallBack function should be bended to the onkeydown event. This could be done in the code-behind or right on the *.aspx page. Let�s use the code-behind.

private void Page_Load(object sender, EventArgs e)
{
    search.Attributes.Add("onkeydown", 
                  "javascript:Main.GetSearchItems(this.value,
                                       GetSearchItems_CallBack);");
    Utility.RegisterTypeForAjax(typeof ( Main ));
}

The result looks like this:

While it is the simplest, it is not very usable. You type something, and then click a link in the list that appears � too many actions. What is required is some cool keyboard support. People should be able to use the up/down keys for list navigation and the Enter key for completion.

Looking for JavaScript

I have never handled keys in JavaScript before and was too lazy to write a large and complex script by myself. I know JavaScript, but not as good as C#, so my first reaction was "Let's find something ready to use and adopt it for our needs". I should say that there are not so many free scripts available. I spent about an hour to find a good one. So can't miss a reference. Thanks to Julian Robichaux for the really fancy script with great comments (it is quite rare for free scripts, and for commercial ones as well :))

The script provides a function to query the server, but I needed a custom one. Luckily, the only change required was in the mainLoop function.

mainLoop = function() {

        val = escape(queryField.value);
                      
        if(lastVal != val && searching == false){
                        
            var response = Main.GetSearchItems(val);
            showQueryDiv('smi', response.value); lastVal = val;
        }
                      
        setTimeout('mainLoop()', 100);
        return true;
};

The script should be enabled via the onload handler:

<body onload="InitQueryCode('search')">

Finally, I've got what I wanted within a small amount of time. But the solution was not reusable, so I decided to create a simple server control.

Server control

The AJAX Lookup server control is a really simple thing. The following parts of the existing solution should be customizable:

  • Name of the callback function.
  • Path to the JavaScript file.
  • Colors like matching list background and highlight, div padding and so on.

It is possible to invent something else, but I didn't require more and, in general, I don't like to add complexity if it is not required in the near future.

The implementation is fairly simple. We may inherit our control from the TextBox. Then all we need to do is set some variables and register some JavaScript functions.

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace play
{
    /// <summary>

    /// AjaxLookup.cs

    /// </summary>

    public class AjaxLookup : TextBox
    {
        private string scriptFile = "";
        private string callBackFunction = "";
        private string backgroundColor = "#EEE";
        private string highlightColor = "#CCC";
        private string font = "Verdana";
        private string divPadding = "2px";
        private string divBorder = "1px solid #CCC";

        public string ScriptFile
        {
            get { return scriptFile; }
            set { scriptFile = value; }
        }

        public string CallBackFunction
        {
            get { return callBackFunction; }
            set { callBackFunction = value; }
        }

        public string BackgroundColor
        {
            get { return backgroundColor; }
            set { backgroundColor = value; }
        }

        public string HighlightColor
        {
            get { return highlightColor; }
            set { highlightColor = value; }
        }

        public string DivFont
        {
            get { return font; }
            set { font = value; }
        }

        public string DivPadding
        {
            get { return divPadding; }
            set { divPadding = value; }
        }

        public string DivBorder
        {
            get { return divBorder; }
            set { divBorder = value; }
        }

        public AjaxLookup()
        {
            this.Attributes.Add("autocomplete", "off");
        }

        protected override void Render(HtmlTextWriter writer)
        {
            base.Render(writer);

            // bind script that contains almost all logic

            Page.RegisterStartupScript("LoadScript", 
                 "<script language="'JavaScript'" src='" + ScriptFile + "'>" + 
                                                                 "</script>");

            // include UI settings

            string styles = String.Format(
                @"<script language="'JavaScript'">
                    var DIV_BG_COLOR = '{0}';
                    var DIV_HIGHLIGHT_COLOR = '{1}';
                    var DIV_FONT = '{2}';
                    var DIV_PADDING = '{3}';
                    var DIV_BORDER = '{4}';
                </script>",
                BackgroundColor, HighlightColor, DivFont, 
                                      DivPadding, DivBorder);

            Page.RegisterStartupScript("LookupStyles", styles);

            // initialize postback handling 

            Page.RegisterStartupScript(
                "RegisterScript",
                "<script language="'JavaScript'">" + 
                    "InitQueryCode('" + this.ClientID + "')</script>");

            // set correct calllback function

            Page.RegisterStartupScript("RegisterCallBack", 
                               @"<script language="'JavaScript'">
                
                mainLoop = function() {

                    val = escape(queryField.value);
                      
                    if(lastVal != val && searching == false){
                        
                        var response = " + CallBackFunction + @"(val);
                        showQueryDiv('smi', response.value); lastVal = val;
                    }
                      
                    setTimeout('mainLoop()', 100);
                    return true;};
                </script>");
        }
    }

The control can be used like this:

<Ajax:AjaxLookup 
        Runat="Server" 
        id="search" 
        BackgroundColor="#EEE" 
        DivBorder="1px solid #CCC" 
        DivPadding="2px"  
        DivFont="Arial" 
        HighlightColor="#C30" 
        CallBackFunction="Main.GetSearchItems" 
        ScriptFile="lookup.js" />

And here is how the Lookup control looks like in production:

This implementation is not ideal, but is quite good to start from. You may improve the flexibility, add some additional parameters and so on.

Conclusion

In general, Ajax.NET could be helpful for many useful things. It is reasonable to start from the simplest thing like a lookup control, but I hope that in future many parts of the UI in our project will be based on AJAX.

Contact

  • Contact email: michael [at] targetprocess.com.
  • Blog.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

firefalcon


Member
Lead of TargetProcess Project (www.targetprocess.com).
TargetProcess is an integrated Project Management and Bug Tracking software
Location: Belarus Belarus

Other popular Ajax and Atlas articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 17 of 17 (Total in Forum: 17) (Refresh)FirstPrevNext
GeneralI am unable to runthis PinmemberRehan Hussain22:17 4 Jun '08  
QuestionHow can we hide the drop down div on page load PinmemberPeupyG0:19 1 Mar '07  
GeneralThe current code is excellent - need help for modification Pinmember0:11 1 Mar '07  
QuestionThe Code is not supply Chinese,how to let it supply Chinese? [modified] Pinmemberfenzqu21:08 20 Oct '06  
GeneralMultiple control in the same page Pinmemberimmob12:37 6 Jul '06  
QuestionThe control does not work inside a gridview PinmemberSumit Banerjee10:38 10 Mar '06  
GeneralOne cotrol per page PinmemberWangckyo5:06 6 Jan '06  
GeneralAjax Projects PinmemberHazem Torab11:57 4 Jan '06  
GeneralOnly 1 control per page? PinmemberRieni Miclis5:52 14 Dec '05  
General"Enter key" triggers form to post Pinmembergabrielk12:14 18 Oct '05  
GeneralLegend Pinmemberramsaycolin3:29 12 Oct '05  
GeneralAJAX is great PinmemberCarl Mercier4:50 1 Sep '05  
Questionsounds good, but... PinsussSum Yung Gai22:59 31 Aug '05  
AnswerRe: sounds good, but... Pinmemberfirefalcon0:02 1 Sep '05  
GeneralRe: sounds good, but... PinsussSum Yung Gai0:19 1 Sep '05  
GeneralRe: sounds good, but... Pinmemberfirefalcon0:59 1 Sep '05  
GeneralRe: sounds good, but... Pinmembersimone_b9:02 1 Oct '05  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 31 Aug 2005
Editor: Smitha Vijayan
Copyright 2005 by firefalcon
Everything else Copyright © CodeProject, 1999-2009
Web12 | Advertise on the Code Project