This post is for search as you type functionality (on demand
loading) for ASP.NET site using JQuery and ASMX web services.
Approach:
- Step 1: Handle textbox keydown event to get user input(‘keyup’ could have been easier choice but it has a problem, will tell u that later in this post)
- Step 2: Send an AJAX hit to server to get search results corresponding to user input.
- Step 3: Catch and display result on client side
- Step 4: Separate handling for down/up key for traversing between search results, enter and tab keys for selecting specific search result and escape key to remove search result.
Cool things to look for:
- CSS stuff (z-index, etc.) that give search results google search type floating feel (exaggerating a bit to keep your interest here ;)
- AJAX calls to ASMX web service.
Code blocks: (Download Code)
ASPX (Just
a textbox to type and a div to hold results)
< span
style="color:White;">Search As You Type:
< input id="txtTest" type="text"
style="width: 400px;" />
< div id="divPredictedResultsContainer"
class="divPredictedResultsContainer" >
Jquery (Code to handle keydown event and make Ajax hits with entered
text)
<script type="text/javascript">
$(document).ready(function() {
var
selectedResultCounter = 1;
$("#txtTest").keydown(function(event) {
//check
if key pressed is alphabet, a number or backspace
if
((event.keyCode > 64 && event.keyCode < 91) || (event.keyCode
> 47 && event.keyCode < 58) || (event.keyCode == 8)) { //handle alphabets, numbers and backspace
var
currentValue = ''
if
(event.keyCode == 8 && $('#txtTest').val().length
> 0) {
currentValue = $('#txtTest').val().substring(0, $('#txtTest').val().length - 1);
} else {
currentValue = $('#txtTest').val()
+ String.fromCharCode(event.keyCode);
}
selectedResultCounter = 1;
$.ajax({
type: "POST",
url: "GetData.asmx/GetData",
data: "{'startsWith':'" + currentValue + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
$("#divPredictedResultsContainer").html(msg.d);
if (msg.d.indexOf("divPredictedResultStyle")
> -1) {
$("#divPredictedResultsContainer").addClass("roundedCorners");
}
},
error: function(xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
} else
if (event.keyCode == 40) { //handle down
key
var
resultCount = $(".divPredictedResultStyle").size();
if
(selectedResultCounter == resultCount + 1) {
selectedResultCounter =
1;
$("#divPredictedResult" +
resultCount).removeClass("divPredictedResultSelected");
}
$("#divPredictedResult"
+ selectedResultCounter).addClass("divPredictedResultSelected");
$("#divPredictedResult"
+ (selectedResultCounter - 1)).removeClass("divPredictedResultSelected");
selectedResultCounter =
selectedResultCounter + 1;
} else
if (event.keyCode == 38) { //handle up
key
selectedResultCounter =
selectedResultCounter - 1;
var
resultCount = $(".divPredictedResultStyle").size();
if
(selectedResultCounter == 1) {
selectedResultCounter = resultCount + 1;
$("#divPredictedResult1").removeClass("divPredictedResultSelected");
}
$("#divPredictedResult"
+ (selectedResultCounter - 1)).addClass("divPredictedResultSelected");
$("#divPredictedResult"
+ selectedResultCounter).removeClass("divPredictedResultSelected");
} else
if (event.keyCode == 9 || event.keyCode == 13)
{ //handle
tab key and enter key
if
(event.preventDefault) { //this is to select one of the records
event.preventDefault(); //from search results
event.stopPropagation();
}
$('#txtTest').val($(".divPredictedResultSelected").html());
return
false;
} else
if (event.keyCode == 27) { //handle escape key
$(".divPredictedResults").hide(); //hide
results div, if escape key is pressed
$("#divPredictedResultsContainer").removeClass("roundedCorners");
}
});
});
script>
Points to ponder
(read these points only if u r not in hurry, else move to ASMX code block :)
- · Here if I would have used keyup event in place of keydown, It wouldn’t have been possible to select result by pressing tab or enter key as in that case, event has already been occurred thus prevent default can’t work.
- · Code in red (see above) is a known bug :( u can c it as coding exercise): This code block handles backspace key but assumes that user will press it end of text only and not from between. I have this problem because on keydown I don’t have final value of textbox, I just have the keycode of key pressed, so I am forced to assume that key pressed is at end only(I’ll update this post once I find the proper solution).
- · Code in green is heart of this all, it sends request to an ASMX service and captures response coming from there.
- · In code blocks that handle up/down key there is logic to keep selecting search result records in loop, means if down key is pressed and last result found was currently selected then automatically selection will get changed to first search result.
ASMX Service code (To serve results from server)
< WebMethod()
> _
Public Function GetData(ByVal startsWith As
String) As String
Dim strResults As New StringBuilder(String.Empty)
Dim dtResults As DataTable =
GetDataForIntellisense(startsWith)
Dim counter As Integer = 1
strResults.Append("< div
class='divPredictedResults'>")
If dtResults.Rows.Count > 0 Then
For Each dr As DataRow In
dtResults.Rows
strResults.Append("< div
class='divPredictedResultStyle' id='divPredictedResult" + counter.ToString()
+ "'>" + dr("code").ToString() + "")
counter += 1
Next
Else
strResults.Append("No results
found.")
End If
strResults.Append("")
Return strResults.ToString()
End Function
There is
nothing typical in above ASMX code, its just about fetching records from database
and then generating html corresponding to records retreived. One thing worth
noticing is that one div is created
corresponding to each search result and they have been given ids in
incremental order. Other thing is method ‘GetDataForIntellisense’, implementation of this is upon you. Current code expects this method
to return a datable with a column named “code”.
CSS (last but not least)
In above css, class ‘divPredictedResultsContainer’
has two lesser known attributes, namely z-index and border-radius.
Z-index is to specify stack order of an element. It
lets results to float above other contents and thus you don’t need to reserve
space for search results and can show search results without disturbing other
contents of site.
Border-radius property is for giving rounded
corners effect to div. This might not work in older browsers.
Download sample code from here.
Download sample code from here.