Looking through the various blog posts and Google Suggest still seems to be a topic everyone is interested in. With a further bit of investigation I discovered what Google is doing is nothing new, all they are doing is using a Javascript method that has been around for a while now, but of course in a rather clever way. Most developers seem to think of web browsers as old style posting back to the server type of client with very little else you can do to talk to the server from the client unless you have a Java or ActiveX app installed (urrrghh security problems!).
So introduce the very humble JavaScript code that is available on so many browsers today and a with a bit of help from some samples on Jim Ley's site (This site is well worth a look and rich in information on JavaScript RPC) , I managed to put together a quick example of a "Google Suggest" type interface using APS.NET.
I call it Cartoon Character Search (Okay it was late at night and there was still a bit of Xmas spirit in the air!)
The interface works on basically the same principle as Google Suggest (however not at all as advanced). The user starts to type in the names of a cartoon character and as they do a request is made back to the server using the JavaScript XML HTTPRequest object to look up the names in an underlying database. In this case I made do with a .NET DataTable object instead. Now don't let the fact that it says XML HTTPRequest put you off, this is only a method and I have not used any XML in this example.
Below is the code I used for the page shown above. The page is created completely in HTML so you should be able to just cut and paste it in.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Cartoon Character Search - Example created By Rory Street</title>
<script language=javascript>
var xmlhttp=false;
var _ai = 0;
// -----> This method was provided from Jim Ley's website
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
// JScript gives us Conditional compilation, we can cope with old IE versions.
// and security blocked creation of the objects.
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
xmlhttp = false;
}
}
/*@end @*/
if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
xmlhttp = new XMLHttpRequest();
}
// -->>>>>> End method
// Over here we make a call back to our server side page and return the results from our query
// to a DIV tag sitting under the text box
function methDataGet(strMethod,strValue,returnDiv)
{
xmlhttp.open("GET", "WebForm1.aspx?str=" + strValue,true);
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
document.getElementById(returnDiv).innerHTML = xmlhttp.responseText
document.getElementById(returnDiv).style.visibility = 'visible'
}
}
xmlhttp.send(null) }
function selectName(oName)
{
if(oName)
{
document.frmTest.txtInput.value = oName.innerHTML;
}
//lostfocus('theDiv');
}
function lookmeup(oElement,oDiv,evt)
{
//Detect if the user is using the down button
if(detectKeyPress(evt)==38)
{
keyUpList()
}
else if(detectKeyPress(evt)==40)
{
keyDownList()
}
else if(detectKeyPress(evt)==13)
{
selectName(document.getElementById('ai'+_ai));
}
else
{
lostfocus(oDiv);
methDataGet("methGetAddressName",oElement.value,oDiv)
}
}
function keyDownList()
{
if(_ai!=0)
{
uhAddress(document.getElementById('ai'+_ai))
}
_ai = _ai +1;
if(document.getElementById('ai'+_ai))
{
hAddress(document.getElementById('ai'+_ai))
selectName(document.getElementById('ai'+_ai))
}
else
{
_ai = _ai -1;
hAddress(document.getElementById('ai'+_ai))
selectName(document.getElementById('ai'+_ai))
}
}
function keyUpList()
{
if(_ai!=0)
{
uhAddress(document.getElementById('ai'+_ai))
}
_ai = _ai -1;
if(document.getElementById('ai'+_ai))
{
hAddress(document.getElementById('ai'+_ai))
selectName(document.getElementById('ai'+_ai))
}
else
{
_ai = _ai +1;
hAddress(document.getElementById('ai'+_ai))
selectName(document.getElementById('ai'+_ai))
}
}
//Highlights a div
function hAddress(tobject)
{
if(tobject)
{
tobject.style.background = 'blue'
tobject.style.color= "white"
}
}
//unhighlights a div
function uhAddress(tobject)
{
if(tobject)
{
tobject.style.color= "black"
tobject.style.background = '#ffffff'
}
}
//Detects what key was pressed
function detectKeyPress(evt)
{
evt = (evt) ? evt : (window.event) ? event : null;
if (evt)
{
var charCode = (evt.charCode) ? evt.charCode :
((evt.keyCode) ? evt.keyCode :
((evt.which) ? evt.which : 0));
return charCode;
}
}
function lostfocus(oDiv)
{
if(document.getElementById(oDiv).style.visibility = 'visible')
{
document.getElementById(oDiv).style.visibility = 'hidden';
_ai=0;
}
}</script>
</head>
<body onclick="javascript:lostfocus('theDiv')">
<h1>Cartoon Character Search</h1>
<form name="frmTest" method=post action="">
<input type=text size=40 name="txtInput" id="txtInput" onkeyup="javascript:lookmeup(this,'theDiv',event)"/><br>
<div name="theDiv" id="theDiv" style="position: relative; width: 200px; height: 70px; z-index: 1;border: 1px solid #00FFFF; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px;background-color: #FFFFFF;visibility:hidden;overflow: auto"></div>
</form>
</body>
</html>
I then created a C# ASP.NET project called TestRemoteAPI and created a page called WebForm1.ASPX. On this page I went into the HTML and removed all of it and then inserted a Literal control onto the page. I then added the following code to the code behind on the page.
Place the following just inside the page class: You will also need System.Data()
private DataRow[] drarray;
In the Page_Load event put the following code. This picks up a request from our client side HTML as a simple request object.
private void Page_Load(object sender, System.EventArgs e)
{
// Put user code to initialize the page here
DataTable dTable = GetCharacters();
drarray = dTable.Select("Name like '" + Request.QueryString["str"] + "*'");
int i=0;
for(int r=0 ; r < drarray.Length; r++)
{
i=i+1;
Literal1.Text=Literal1.Text + "<div id=\"ai" + i.ToString() + "\" name=\"ai" + i.ToString() + "\">" +drarray[r]["Name"] + "</div>";
}
}
The following code can go beneath the Page_Load event method, all this does is emulates a database for us.
private DataTable GetCharacters()
{
DataTable dtTempTable = new DataTable("MyCharacters");
dtTempTable.Columns.Add("Name");
DataRow dr;
dr = dtTempTable.NewRow();
dr["Name"]="Daffy";
dtTempTable.Rows.Add(dr);
dr = dtTempTable.NewRow();
dr["Name"]="Donald";
dtTempTable.Rows.Add(dr);
dr = dtTempTable.NewRow();
dr["Name"]="Goofy";
dtTempTable.Rows.Add(dr);
dr = dtTempTable.NewRow();
dr["Name"]="Porky";
dtTempTable.Rows.Add(dr);
dr = dtTempTable.NewRow();
dr["Name"]="Road Runner";
dtTempTable.Rows.Add(dr);
dr = dtTempTable.NewRow();
dr["Name"]="Tweety";
dtTempTable.Rows.Add(dr);
dr = dtTempTable.NewRow();
dr["Name"]="Taz";
dtTempTable.Rows.Add(dr);
dr = dtTempTable.NewRow();
dr["Name"]="Micky";
dtTempTable.Rows.Add(dr);
dr = dtTempTable.NewRow();
dr["Name"]="Bat Fink";
dtTempTable.Rows.Add(dr);
dr = dtTempTable.NewRow();
dr["Name"]="Bat Man";
dtTempTable.Rows.Add(dr);
dr = dtTempTable.NewRow();
dr["Name"]="Marvin the Martian";
dtTempTable.Rows.Add(dr);
dr = dtTempTable.NewRow();
dr["Name"]="Bux Bunny";
dtTempTable.Rows.Add(dr);
return dtTempTable;
}
So how does it all work?
Well the HTML page we are using is making an XML HTTPRequest back to our server side page WebForm1.aspx (note the HTML page can be called anything but must sit in the same directory as WebForm1.aspx unless you want to change the path names in the JavaScript). When the server side page gets the request it draws the results into an ASP.NET Literal control on the page, each result contained within a DIV. The JavaScript client side takes the HTML of the page sent to it and places this inside a DIV client side (this is the drop down box you see appear below the text box). When the user presses the down and up arrow keys on their keyboard it selects the various options, I didn't put a mouse selection method in but this should be very easy to do with an onlick event. At the moment the page only shows you different selections based on what you are typing in but can quite easily be made to do all sorts of things. The nice thing about this method is it works on most browsers and I have tested it on Mozilla and IE without any problems. Playing around with it you will probably realise there are hundred of applications this type of method can be used on and it is so very simple to use.
If you have any suggestions or comments or have found a way to improve on the code please let me know I would love to hear from you. It is by no means perfect and was just a little something I put together from various examples around the net.