ASP.NET Ajax Toolkit - getting a key-value pair from the auto complete extender
Autocomplete Extender is a nice control, no doubt. And free. I didn't check earlier versions but current solution uses JSON web services and pretty fast.
Originally the Autocomplete Extender lacked very important functionality - ability to operate with key-value pairs. If you think about that, the Google search auto complete serves its purpose - the resulting string IS the value which is important for the postback, but it is scarcely the case for the 98% of non-search applications. We need control to mimic dropdown list - so gimme ya money let me keep the value for the entered text! Such a functionality was added some time ago but regretfully the feature was left undocumented.
You need to make few small changes to the original example: add JavaScript handling on the client and modify Web Service to return more sophisticated array. The Web Service method has to generate the list with the items in {"First":"<Name>,"Second":"<Value>"} format. E.g.
{"First":"Nissan Oakville","Second":"34AF44d2-1190-f489"}Method AutoCompleteExtender.CreateAutoCompleteItem(name,value) can help to create proper format.
Page looks like this:
And this is a full web service code:<script type="text/javascript" language="javascript">
function GetCode(source, eventArgs )
{
document.getElementById("hCode").value = eventArgs.get_value();
}
</script>
Enter Manufacturer: <asp:TextBox ID="txtManufacturer" runat="server"/><input name="hCode" type="hidden"/>
<ajaxToolkit:AutoCompleteExtender ID="AutoCompleteExtender1" runat="server"
TargetControlID="txtManufacturer"
ServicePath="~/WebServices/AutoCompleteService.asmx"
ServiceMethod="GetCompletionList"
CompletionInterval="100"
CompletionSetCount="20"
MinimumPrefixLength="2"
OnClientItemSelected="GetCode"/>
[WebService(Namespace = "http://tempuri.org/")]As a result if postback is required, the hCode element will hold the value, matching the text from txtManufacturers box and can be extracted from Request.Form collection.
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class AutoCompleteService : System.Web.Services.WebService
{
[WebMethod]
[System.Web.Script.Services.ScriptMethod]
public string[] GetCompletionList(string prefixText, int count)
{
List<string> names = new List<string>();
using (SqlConnection conn = DbGateway.GetConnection())
{
SqlCommand cmd = new SqlCommand("GetManufacturersByPrefix", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@prefix", prefixText));
cmd.Parameters.Add(new SqlParameter("@count", count));
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
string item = AjaxControlToolkit.AutoCompleteExtender.CreateAutoCompleteItem
(reader["ManufacturerName"].ToString(),
reader["ManufacturerId"].ToString());
names.Add(item);
}
reader.Close();
}
conn.Close();
}
return names.ToArray();
}
}
P.S. Microsoft has to apply some serious ass-kicking to their Documentation Generation (or whatever) Department. Poor MSDN documentation and samples are unbearable and this tradition seems to infect the Microsoft-flavored open source community.
37 comments:
This is great posting saved me some hours of searching.
excellent !!!
Appreciate your comment. It is good to know that my post helps.
Excellent work.. Thanks a lot...
nice example man, i really helped me.
that really helped
my problem is that , i have a web service which returns a company name and town. every company is associated with some id and i want that id to go into hcode rather than whole companyname,town,id. any help
Sorry, I didn't really understand the problem. Do you want to show company and town and capture the company id?
The simplest way is to use this kind of pair:
{"First":"CompanyName (Town),"Second":"CompanyId"}
Next choice is investigate how JSON array is getting mapped to the Extender.
The ultimate solution is create your own Extender version, which can be flexed to show multiple columns - that's what Microsoft should do from the beginning.
Excellent post - thanks mate!
great posting! But what if the user tries to press enter on the textbox without selecting any item from the autocomplete extender panel. I tried this and it throws be a javscript error at run time "value is null or not an object". Cant we avoid this error?
-acvincent
Great observation! My example is more a walkthrough than a real production code. I didn't look carefully but my guess is the JSON pair is null so reading element of that pair should produce this kind of exception.
Of course some kind of plumbing must be put around.
This confirms that developers should not trusted in testing their own code - they tend to follow happy paths :)
FYI, the sample code uses "GetCompletionList" as the webmethod in the webservice, but "GetCompletionLists" as the webmethod for the extender declaration. Hung me up for a bit, so it might be good to change that to save others the time.
Josh
Thanks for this helpful example. Can you please show an example for the javascript code for OnClientItemSelected. your example has really showed me some path to do it right way.
Sorry. My mistake. I missed the javascript code that you have given. Thanks a ton. Its really great piece of code tat you have provided. It has really saved me some time. I will try improving it further and put it for someone like me needing such code.
This is a great post.
The logic is working fine in IE, but I could not make it work in Firefox or Chrome.
While debugging, I have figured out that I can see a auto-populate list without setting up a value for OnClientItemSelected property of AutoCompleteExtender. As soon as I set value to OnClientItemSelected (which is required to retrieve the selected item value), the auto-populate does not appear in non-IE browser.
Would you please post your comments? I will check your blog periodically.
Thank you for you help.
Excellent post..but I do have a problem.. I am selecting an item from the list, it populates the ID in the hidden field, then I go back and enter the item which is not is the list.. it still keeps the ID in the hidden field. Is there any way to clear the hidden field if Idont select the item from the list?
Hello I am having 1 issue From Your
OnClientItemSelected Actually The Problem When I Enter in the textbox from my keyboard its works but when i click from the Mouse Its Crashes [ Crashing Means Javascript Error UnSpecified Error ] Please Help Me With That :?
Thanks
How To Achive The Same Via UserControl Cause i am getting Error When i Try To Set The Target in Calling page Of UserControl
[ Calling Page Means in Which Page My usercontrol is called ]
sunil: that part may be just missing from the scenario, great catch
rahul: I didn't notice that behaviour before and was unable to reproduce it. What browser you're referring to?
Thank you so much for this info! Microsoft is really missing the point of open source. We cant use the tools without directions!
This article illustrates some very help techniques. I've been looking for a reference just like this. Thanks for submitting.
Grady Christie
Saved me a ton of time. Awesome stuff.
But what if the user types-in the whole text without selecting it from textbox.
How can we get the value in this case ?
Think about using auto complete extender as not just a "UI prettiness" but rather as a architectural decision. Allowing user to type a flexible text should be a well thought through. In my scenario user could type free text but some extra functionality was available for a "strongly-typed" entry, which iwas found by a paired ID. This combination is not suitable for a data entry, for example, when exact match is required. In this case you choice should be a more or less "ajaxi-smart" drop-down list, which does not allow free text.
Thank you so much for this info!
This is a great post.
nice example man, i really helped me.
Nice example.
In my webservice this kind of pair:
{"First":"ClientName ,
"Second":"ClientId"}
All is working , but i am not able to extract hCode values .
Can u please tell how to extract "ClientId" from textbox.
Thanks a ton.
Get stuff! I spent days trying to figure this out and come across this website and solved all my problems.
This was a great example for me. I used this method in reverse to display a name in another control when the lookup completed. Very nice. Thanks!
Well done, very useful !! :)
This post is fantastic.. I went through several other posts which mentioned updating the toolkit yada yada.. this post is extremely clear and conscise. Thanks!
Really Great Job Dear
jscript runtime error is occuring while selecting Object doesn'tsupport this property or method
Really Great Job Dear
jscript runtime error is occuring while selecting Object doesn'tsupport this property or method
Really Great Job Dear
jscript runtime error is occuring while selecting Object doesn'tsupport this property or method
Sir nice article.
Can u tell me how to make this same for multiple column,
ie(ManufacturerName,ManufacturerID),(LocationName,LocationID)
Maybe I didn't understand the question but it is the case I am talking bout - just substitute ID with Second column.
Thanks for the example. It saved me hours. I can't agree more about the poor documentation with the ajax toolkit.
awesome!!! thanks , appreciate your efforts.
Post a Comment