Click here to Skip to main content
13,248,039 members (39,578 online)
Click here to Skip to main content
Add your own
alternative version


22 bookmarked
Posted 31 Jan 2011

Beautiful Prototype autocomplete Easy to Use

, 31 Jan 2011
Rate this:
Please Sign up or sign in to vote.
A beautiful ASP.NET Ajax Webcontrol which is easy to use


I love web creation, and I love beautiful Web graphic interfaces. Last time, I searched a beautiful ASP.NET autosuggest webcontrol with the possibility to write in 2 lines per item.

I did a research, and found this elegant control:

The editor of the control provides the library JavaScript file and a CSS file with a PHP example to do it.

I decided to do it an ASP.NET webcontrol, and I tried to design it for a very simple utilization like Microsoft Widgets.

This control is compatible with all navigators.


This control needs 3 basics things to run:

  1. You must provide the ServiceMethod property, it might be an .asmx file or .svc file
  2. You must provide the ServicePath property, it's the name of the method of your webservice or wcfservice to call to get formatted data to bind to the control.
  3. On this service method implementation, you must respect the json format result. The string must be formatted like that:
    { results: [" 
    "{ id: '1', value: 'TOTO,TETE', info: 'FireFox' }," 
    "{ id: '2', value: 'TATA,TYTY', info: 'Chrome' }," 
    "{ id: '3', value: 'TITI,TNTN', info: 'Safari' } ] }" 

The autosuggest functionality works with 'value' property.

Using the Code

This control is a very simple CompositeControl. It's a Textbox for the suggestion with an associated HTML hidden input to store the current selected id.

OnPreRender method does several things:

It adds the references of the JavaScript and CSS file on the document.

Sometimes, the CSS file did a reference to embedded pictures. I extracted this code of the CSS file to put it the server side.

I already explained this manipulation to get the picture address in assembly in my other article ASP.NET Combobox dropdownlist with Images.

And finally, it loads a JavaScript function which binds the textbox to the service to invoke when a key is pressed and the focus is in the textbox.

protected override void OnPreRender(EventArgs e)

	if (!this.DesignMode)
	// Test for ScriptManager and register if it exists
	// we need it for PageRequestManager manipulation in prerender
	ScriptManager sm = ScriptManager.GetCurrent(Page);

	if (sm == null)
		throw new HttpException
		("A ScriptManager control must exist on the current page.");

	//Add js and css files resource
	string cssdd = Page.ClientScript.GetWebResourceUrl
		(GetType(), "");
	string scriptJQuery = Page.ClientScript.GetWebResourceUrl(this.GetType(), 

	HtmlLink lnk = new HtmlLink();
	lnk.Href = cssdd;
	lnk.Attributes["rel"] = "stylesheet";
	lnk.Attributes["type"] = "text/css";

	HtmlGenericControl jq = new HtmlGenericControl("script");
	jq.Attributes.Add("language", "JavaScript");
	jq.Attributes.Add("type", "text/javascript");
	jq.Attributes.Add("src", scriptJQuery);
	jq.Attributes.Add("alt", "bsn.AutoSuggest_2.1.3.js");

	//Put one time the style whose gives reference to arrow of the combo
	if (!Page.Items.Contains("styleAlreadyPut"))
	//get URL of embedded pictures
	string urlImage_as_pointer_gif = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.as_pointer.gif");
	string urlImage_as_pointer_png = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.as_pointer.png");
	string urlImage_hl_corner_bl_gif = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.hl_corner_bl.gif");
	string urlImage_hl_corner_br_gif = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.hl_corner_br.gif");
	string urlImage_hl_corner_tl_gif = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.hl_corner_tl.gif");
	string urlImage_hl_corner_tr_gif = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.hl_corner_tr.gif");
	string urlImage_li_corner_png = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.li_corner.png");
	string urlImage_ul_corner_png = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.ul_corner.png");
	string urlImage_ul_corner_bl_gif = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.ul_corner_bl.gif");
	string urlImage_ul_corner_br_gif = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.ul_corner_br.gif");
	string urlImage_ul_corner_tl_gif = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.ul_corner_tl.gif");
	string urlImage_ul_corner_tr_gif = Page.ClientScript.GetWebResourceUrl
			(this.GetType(), "ClassLibrary1.img.ul_corner_tr.gif");
	StringBuilder strStyleas_pointer_gif = new StringBuilder();
	strStyleas_pointer_gif.Append(" div.autosuggest { ")
	   .Append(" position: absolute; ")
	   .Append(" background-position: top; ")
	   .Append(" background-repeat: no-repeat; ")
	   .Append(" padding: 10px 0 0 0; ")
	   .Append(" background-image:url('" + urlImage_as_pointer_gif + "');")
   .Append(" } ");
	HtmlGenericControl styleas_pointer_gif = new HtmlGenericControl("style");
	styleas_pointer_gif.Attributes.Add("type", "text/css");
	styleas_pointer_gif.Controls.Add(new LiteralControl
			( strStyleas_pointer_gif.ToString()));
	StringBuilder autoSuggestParam = new StringBuilder();
	string ServiceUrl = ServicePath + "/" + ServiceMethod + "?";

	autoSuggestParam.Append(" var options = { ")
		 .Append("script:\"" + ServiceUrl + "\", ")
		 .Append("callback: function (obj) 
			{ document.getElementById('" + 
			hiddenValue.ClientID + "').value =; }};");
	autoSuggestParam.Append(" var as_json = new bsn.AutoSuggest
			('" + txtAutoSuggest.ClientID + "', options); ");

	//add the control
	LiteralControl lc = new LiteralControl
		("<script language="javascript">" + autoSuggestParam + "</script>");

Now it's interesting to see inside bsn.AutoSuggest_2.1.3.js JavaScript file in detail.

When I downloaded bsn.AutoSuggest files, the 'script' property of the var option (just above) was script:"test.php?id=..".

The script value (test.php?id=..) allow finally to invoke an XMLHttpRequest and call asynchronously the page test.php with some GET parameters to bind data:

_b.Ajax.prototype.makeRequest = function(url, meth, onComp, onErr) {

    if (meth != "POST")
        meth = "GET";

    this.onComplete = onComp;
    this.onError = onErr;

    var pointer = this;

    // branch for native XMLHttpRequest object
    if (window.XMLHttpRequest) {

        this.req = new XMLHttpRequest();
        this.req.onreadystatechange = function() { pointer.processReqChange() };"GET", url, true); //
        // branch for IE/Windows ActiveX version
    else if (window.ActiveXObject) {

        this.req = new ActiveXObject("Microsoft.XMLHTTP");
        if (this.req) {
            this.req.onreadystatechange = function() { pointer.processReqChange() };
  , url, true);

So I said to myself, I must try to keep the same mechanic to call web service and WCF service.

I learnt that it's possible to invoke a webservice with GET parameters through XMLHttpRequest.

The script value must be formatted like this: ServicePath + "/" + ServiceMethod + "?param=p" here very simply: Webservice.asmx/getResults?input=...

To authorize this call, you must add a section in Web.config:

        <add name="HttpGet">
        <add name="HttpPost">

To call a WCF service, it's exactly the same mechanism: Service.svc/getResults?input=...

It's interesting to note that to invoke a WCF Contract Method from Ajax request, the method must have the attribute [WebGet()] and the WCF service class must have the attribute [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)].

And similarly, to invoke a webservice from Ajax request, the method must have the attribute [ScriptMethod] and the webservice class must have the attribute [ScriptService].

A last point, when we receive the response of the webservice, it's a wrapped response with XML, so we must strip XML.

WCF is better because it sends a clean response... :)

_b.AutoSuggest.prototype.setSuggestions = function(req, input) {

    // if field input no longer matches what was passed to the request
    // don't show the suggestions
    if (input != this.fld.value)
        return false;

    this.aSug = [];

    if (this.oP.json) {

        var txtResponse = req.responseText;
        var jsondata = '';

        // web service case
        if (txtResponse.charAt(0) == '<') {
            <string xmlns="">
                { results: [{ id: '1', value: 'Foobar', info: 'Cheshire' },
                            { id: '2', value: 'Foobarfly', info: 'Shropshire' },
                            { id: '3', value: 'Foobarnacle', info: 'Essex' } ] }
            //STRIP XML and HTML tags ( tratment)    
            var matchTag = /<(?:.|\s)*?>/g;
            txtResponse = txtResponse.replace(matchTag, "");
            jsondata = eval('(' + txtResponse + ')');
        //WCF service case
            /*{"d":"   { results: 
            [{ id: \"1\", value: \"Foobar\", info: \"Cheshire\" },
            { id: \"2\", value: \"Foobarfly\", info: \"Shropshire\" },
            { id: \"3\", value: \"Foobarnacle\", info: \"Essex\" } ] }    "}*/

            var alphaChars = /^([a-zA-Z])$/;

            if (alphaChars.test(txtResponse.charAt(2))) 
                txtResponse = txtResponse.replace("{\"d\":\"", "");
                txtResponse = txtResponse.substring(0, txtResponse.length - 2);
                jsondata = eval('(' + txtResponse + ')');

        for (var i = 0; i < jsondata.results.length; i++) {
            this.aSug.push({ 'id': jsondata.results[i].id, 
	   'value': jsondata.results[i].value, 'info': jsondata.results[i].info });
    else {
        var xml = req.responseXML;

        // traverse xml
        var results = xml.getElementsByTagName('results')[0].childNodes;

        for (var i = 0; i < results.length; i++) {
            if (results[i].hasChildNodes())
                this.aSug.push({ 'id': results[i].getAttribute('id'), 
		'value': results[i].childNodes[0].nodeValue, 
		'info': results[i].getAttribute('info') });
        }    }

    this.idAs = "as_" +;


Points of Interest

It was interesting to learn how to invoke .NET services with the basic JavaScript object XMLHttpRequest.

Once you see that, you can have a little idea about how ajaxtoolkit works with its ScriptManager.


  • 1st February, 2011: Initial post


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

David Zenou
Software Developer Several
France France
Fan of .NET Technologies
Go to see my blog :

You may also be interested in...


Comments and Discussions

GeneralNice example Pin
PunkIsNotDead1-Feb-11 4:15
memberPunkIsNotDead1-Feb-11 4:15 
GeneralRe: Nice example Pin
David Zenou1-Feb-11 5:47
memberDavid Zenou1-Feb-11 5:47 
GeneralRe: Nice example Pin
PunkIsNotDead1-Feb-11 9:37
memberPunkIsNotDead1-Feb-11 9:37 
GeneralGood!!! Pin
shakil030400331-Jan-11 22:51
membershakil030400331-Jan-11 22:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.171114.1 | Last Updated 1 Feb 2011
Article Copyright 2011 by David Zenou
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid