I'm sending a list of objects (as Json) to the AutoComplete. There are two properties, Name and ID. Name is binding correctly to the AutoComplete and is being sent back on Post. I think I need to use the Select event to get the ID value and populate that field but I can't find the object when I look at the debugging info in the browser when the page is running. The event variable 'e' doesn't seem to have it.
How can i do this? Code is appended.
View Code:
<!-- AutoComplete text box for Issue To Employee -->
<
div
class
=
"row"
>
<!-- IssuedToEmployeeName NOTE: Autocomplete control MUST be the same name
as the field that's being bound or it won't
be sent back in the post operation!!!
-->
<
span
class
=
"col-sm-2"
>
<
label
>Issued To:</
label
>
</
span
>
<
span
class
=
"col-sm-2"
>
@(Html.Kendo().AutoComplete()
.Name("IssuedToEmployeeName")
.Delay(100)
.MinLength(2)
.DataTextField("IssuedToEmployeeName")
.Filter("contains")
.Events(e =>
{
e.Change("onChange")
.Select("onSelect")
.DataBound("onDataBound");
})
.DataSource(source =>
{
source.Read(read =>
{
read.Action("LookUpEmpName", "Home")
.Data("onAdditionalData");
})
.ServerFiltering(true);
})
)
</
span
>
<
span
class
=
"col-sm-1"
>
@Html.TextBoxFor(model => model.IssuedToEmployeeID, new { @class="form-control" })
</
span
>
<!-- IssuedOnDateTime -->
<
span
class
=
"col-sm-2"
>
<
label
>Issue Date/Time:</
label
>
</
span
>
<
span
class
=
"col-sm-3"
>
@Html.TextBoxFor(model => model.IssuedOnDateTime, new { @readonly = "true" })
</
span
>
<
span
class
=
"col-sm-2"
></
span
>
</
div
>
<script>
function onAdditionalData() {
return { text: $("#IssuedToEmployeeName").val() };
}
function onChange(e) {
//alert('onChange() event fired');
}
function onSelect(e) {
alert('onSelect() event fired; event arg = ' + e.arguments);
}
function onDataBound(e) {
//alert('onDataBound() fired. event arguement = ' + e);
}
</script>
Controller Code:
//
// LookUpEmpName()
public JsonResult LookupEmpName(string text)
{
string[] empNames = DataAccess.LookupEmpName(text);
List<
NameSearchResult
> result = new List<
NameSearchResult
>();
if (empNames!=null)
{
foreach (string name in empNames) {
NameSearchResult searchResult = new NameSearchResult();
string empName = null;
string empID = null;
CommonMethods.ParseNameSearchResult(name, ref empName, ref empID);
if((empName!=null) && (empID!=null)) {
searchResult.IssuedToEmployeeName = empName;
searchResult.EmployeeID = empID;
}
result.Add(searchResult);
}
}
return Json(result, JsonRequestBehavior.AllowGet);
}
11 Answers, 1 is accepted
I am afraid it is not possible. The AutoComplete value is always equal to the text, there is no underlying value. If you need to send the ID of an item not the text, then you should consider using a DropDownList or a ComboBox widget.
Regarding the ComboBox - if the text that the user entered does not match any item from the underlying collection then the value becomes the text that the user typed. You can, however fix this behavior with a small work-around discussed on the forums.
Kind Regards,
Petur Subev
Telerik

I think that's a bug in the AutoComplete widget that should be fixed. When first configuring the AutoComplete I sent it a list of strings from the Controller. What rendered in the View was a selection list of 'undefined'. The example I was working from t http://telerikhelper.net/2012/11/16/kendo-autocomplete-wrapper-for-asp-net-mvc/ shows sending a list of objects to the widget. That object has multiple properties. What's the point if you can't use them?
In my case, the user is editing in the view and is changing the employee for the transaction. It's more natural to look up the name via the AutoComplete widget than to have them enter the employee id which they would have to look up anyhow. Since I can get the id into the list along with the name I want to populate the employee id field based on the selection. Since the AutoComplete widget has that object at that moment it makes no sense that I can't make use of it at the point of selection. Now you're forcing me to do another workaround and another trip to the server. I don't think a combobox is an appropriate choice. I would have to download all employees in the company, hence my use of the AutoComplete widget.
Is there another way to accomplish this? I thought of looking up the empID based on the name but that will fail in cases of common names as the query won't produce a unique result.
No matter that you can use "list of objects with multiple properties" only the text property that you specified is used by the AutoComplete and only its value is send to the server. Here is an example:
http://jsbin.com/voveyuzi/2/edit
A work around would be to use a hidden field on your page and update its value based on the text when the AutoComplete changes its value.
Kind Regards,
Petur Subev
Telerik

I still feel this is a bug and would like to see it fixed. If I can send the object to the widget, it seems only logical that I should be able to get access to the selected object and its properties in an event of the widget. This is a very common scenario.
I'm marking this as answered.

Please try my code. I hope it will matched with your requirement.
This an example of employee page in which you need a Autocomplete for manager.
User will type manager name and the corresponding EmployeeId of manager will be populated in "ManagerId"
CSHTML
---------
@model TelerikMvc5App.ViewModel.EmployeeViewModel
@Html.TextBoxFor(m => m.ManagerName)
@Html.TextBoxFor(m => m.ManagerId)
JavaScript
---------------
$(function () {
var GetManagerURL = '@Url.Action("GetManager", "Employee", new { Area = "Employee" })'; // if you have cretaed are as "Employee"
var GetManagerURL = '@Url.Action("GetManager", "Employee")'; // if you have not created any Area
$("#ManagerName").kendoAutoComplete({
placeholder: "Enter your manager name",
minLength: 3, // you need to type atleast 3 charactes
dataTextField: "EmployeeName",
select: onManager_select,
dataSource: {
transport: {
read: GetManagerURL,
parameterMap: function (data) {
return {
input: $("#ManagerId").val(),
take: data.take,
skip: data.skip
};
}
},
serverFiltering: true,
serverPaging: true,
pageSize: 10 // maximum list size in autocomplete
}
});
});
// do something when user will select an item from autocomplete
function onManager_select(e) {
var selectedOne = this.dataItem(e.item.index());
$("#ManagerId").val(selectedOne.EmployeeId);
}
"Employee" Controller
-------------
public JsonResult GetManager(string input, int take, int skip)
{
List<EmployeeViewModel> mgrList = new List<EmployeeViewModel>();
mgrList.Add(new EmployeeViewModel() { EmployeeId = 1, EmployeeName = "Prashad" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 2, EmployeeName = "Ashreewad" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 3, EmployeeName = "Sathish" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 11, EmployeeName = "Prashad1" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 21, EmployeeName = "Ashreewad1" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 31, EmployeeName = "Sathish1" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 12, EmployeeName = "Prashad2" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 22, EmployeeName = "Ashreewad2" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 32, EmployeeName = "Sathish2" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 13, EmployeeName = "Prashad3" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 23, EmployeeName = "Ashreewad3" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 33, EmployeeName = "Sathish3" });
try
{
if (!string.IsNullOrWhiteSpace(input))
{
if (mgrList != null)
{
mgrList = mgrList.Where(e => e.EmployeeName.ToLower().StartsWith(input.ToLower())).Take(take).ToList();
}
}
}
catch (Exception ex)
{
//
return null;
}
return Json(mgrList, JsonRequestBehavior.AllowGet);
}
EmployeeViewModel
--------------------------
public class EmployeeViewModel
{
[Display(Name = "Employee Name")]
public string EmployeeName { get; set; }
public int EmployeeId { get; set; }
[Display(Name = "Manager")]
[Required(ErrorMessage = "Manager is Required.")]
public int ManagerId { get; set; }
[Display(Name = "Manager")]
public string ManagerName { get; set; }
}
Thanks

In reviewing your code, I don't see where the manager name is posted to the input control, or is that handled by the AutoComplete control itself, and your anonymous function takes care of the Id? If that's the case, that would resolve my issue. Currently I've worked around it with a hack. I've concatenated the name and id with a delimiter and parse them out when the select action takes place. Not what I wanted to do, but it does work.

I did a mistake on input control, it should be input: $("#ManagerName").val(),
Please see updated code
CSHTML
---------
@model TelerikMvc5App.ViewModel.EmployeeViewModel
@Html.TextBoxFor(m => m.ManagerName) --- AutoComplete will bind here
@Html.TextBoxFor(m => m.ManagerId) --- OnSelect manager Id will be populated here
JavaScript
---------------
$(function () {
var GetManagerURL = '@Url.Action("GetManager", "Employee", new { Area = "Employee" })'; // if you have cretaed are as "Employee"
var GetManagerURL = '@Url.Action("GetManager", "Employee")'; // if you have not created any Area
$("#ManagerName").kendoAutoComplete({
placeholder: "Enter your manager name",
minLength: 3, // enter min 3 char
dataTextField: "EmployeeName",
template: '<span>#: EmployeeName # (Manager ID#: EmployeeId #)</span>', // if you need ant template
select: onManagerSelect,
dataSource: {
transport: {
read: GetManagerURL,
parameterMap: function (data) {
$("#ManagerId").val(''); // this will clear manager id in every request or keypress
return {
input: $("#ManagerName").val(), // here manager name is posted to the input control
take: data.take,
skip: data.skip
};
}
},
serverFiltering: true,
serverPaging: true,
pageSize: 10 // max list size
}
});
});
function onManagerSelect(e) {
var dataItem = this.dataItem(e.item.index());
if (dataItem == 'undefined' || dataItem == null )
{
$("#ManagerId").val('');
$("#ManagerName").val('');
}
else {
$("#ManagerId").val(dataItem.EmployeeId);
$("#ManagerName").val(dataItem.EmployeeName);
}
}
Controller
---------------------------------
public JsonResult GetManager(string input, int take, int skip)
{
List<EmployeeViewModel> mgrList = new List<EmployeeViewModel>();
mgrList.Add(new EmployeeViewModel() { EmployeeId = 1, EmployeeName = "Prashad" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 2, EmployeeName = "Ashreewad" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 3, EmployeeName = "Sathish" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 11, EmployeeName = "Prashad1" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 21, EmployeeName = "Ashreewad1" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 31, EmployeeName = "Sathish1" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 12, EmployeeName = "Prashad2" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 22, EmployeeName = "Ashreewad2" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 32, EmployeeName = "Sathish2" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 13, EmployeeName = "Prashad3" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 23, EmployeeName = "Ashreewad3" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 33, EmployeeName = "Sathish3" });
try
{
if (!string.IsNullOrWhiteSpace(input))
{
if (mgrList != null)
{
mgrList = mgrList.Where(e => e.EmployeeName.ToLower().StartsWith(input.ToLower())).Take(take).ToList();
}
}
}
catch (Exception ex)
{
//
return null;
}
return Json(mgrList, JsonRequestBehavior.AllowGet);
}
EmployeeViewModel
--------------------------
public class EmployeeViewModel
{
[Display(Name = "Employee Name")]
public string EmployeeName { get; set; }
public int EmployeeId { get; set; }
[Display(Name = "Manager")]
[Required(ErrorMessage = "Manager is Required.")]
public int ManagerId { get; set; }
[Display(Name = "Manager")]
public string ManagerName { get; set; }
}
CSHTML
---------
@model TelerikMvc5App.ViewModel.EmployeeViewModel
@Html.TextBoxFor(m => m.ManagerName) --- AutoComplete will bind here
@Html.TextBoxFor(m => m.ManagerId) --- OnSelect manager Id will be populated here ( you may use a hidden filed here)
JavaScript
---------------
$(function () {
var GetManagerURL = '@Url.Action("GetManager", "Employee", new { Area = "Employee" })'; // if you have cretaed are as "Employee"
var GetManagerURL = '@Url.Action("GetManager", "Employee")'; // if you have not created any Area
$("#ManagerName").kendoAutoComplete({
placeholder: "Enter your manager name",
minLength: 3, // enter min 3 char
dataTextField: "EmployeeName",
template: '<span>#: EmployeeName # (Manager ID#: EmployeeId #)</span>', // if you need ant template
select: onManagerSelect,
dataSource: {
transport: {
read: GetManagerURL,
parameterMap: function (data) {
$("#ManagerId").val(''); // this will clear manager id in every request or keypress
return {
input: $("#ManagerName").val(), // here manager name is posted to the input control
take: data.take,
skip: data.skip
};
}
},
serverFiltering: true,
serverPaging: true,
pageSize: 10 // max list size
}
});
});
function onManagerSelect(e) {
var dataItem = this.dataItem(e.item.index());
if (dataItem == 'undefined' || dataItem == null )
{
$("#ManagerId").val('');
$("#ManagerName").val('');
}
else {
$("#ManagerId").val(dataItem.EmployeeId);
$("#ManagerName").val(dataItem.EmployeeName);
}
}
Controller
---------------------------------
public JsonResult GetManager(string input, int take, int skip)
{
List<EmployeeViewModel> mgrList = new List<EmployeeViewModel>();
mgrList.Add(new EmployeeViewModel() { EmployeeId = 1, EmployeeName = "Prashad" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 2, EmployeeName = "Ashreewad" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 3, EmployeeName = "Sathish" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 11, EmployeeName = "Prashad1" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 21, EmployeeName = "Ashreewad1" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 31, EmployeeName = "Sathish1" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 12, EmployeeName = "Prashad2" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 22, EmployeeName = "Ashreewad2" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 32, EmployeeName = "Sathish2" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 13, EmployeeName = "Prashad3" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 23, EmployeeName = "Ashreewad3" });
mgrList.Add(new EmployeeViewModel() { EmployeeId = 33, EmployeeName = "Sathish3" });
try
{
if (!string.IsNullOrWhiteSpace(input))
{
if (mgrList != null)
{
mgrList = mgrList.Where(e => e.EmployeeName.ToLower().StartsWith(input.ToLower())).Take(take).ToList();
}
}
}
catch (Exception ex)
{
//
return null;
}
return Json(mgrList, JsonRequestBehavior.AllowGet);
}
EmployeeViewModel
--------------------------
public class EmployeeViewModel
{
[Display(Name = "Employee Name")]
public string EmployeeName { get; set; }
public int EmployeeId { get; set; }
[Display(Name = "Manager")]
[Required(ErrorMessage = "Manager is Required.")]
public int ManagerId { get; set; }
[Display(Name = "Manager")]
public string ManagerName { get; set; }
}
I hope it will work for you.
Thanks


Hi Richard, FYI, I came cross the same issue and it seems now we can get all fields from the autocomplete, through the select event
function onSelect(e) {
var item = this.dataItem(e.item.index());
$('#customer-name').val(item.Name);
}

I am having the same exact issue, but am seeing another issue. On the Autocomplete, I'm returning a list of objects through my controller using JSON. My autocomplete is bound to a text field of my model. I have the select event which is being fired. I get the selected dataitem and can get any of the fields returned by the controller. I set the corresponding Id of the model into my hidden field, but that Id field doesn't come back into my controller method in the model. Here's the code I'm talking about:
LocationAdd.vbhtml (custom popup editor template)
@ModelType LocationVM
<
script
>
function onSelect_Loc(e) {
var item = this.dataItem(e.item.index());
alert(item.Id);
$('#EsaId').val(item.Id);
$('#CanvasPriority').val("PriTest");
}
</
script
>
@Html.HiddenFor(Function(model) model.Id)
@Html.LabelFor(Function(model) model.LocationName)
@(Html.Kendo().AutoComplete() _
.Name("LocationName") _
.DataTextField("LocationName") _
.Events(Sub(e) e.Select("onSelect_Loc")) _
.DataSource(Sub(source)
source.Read(Sub(read)
read.Action("GetAutoCompLocation", "Management").Data("onData_Loc")
End Sub) _
.ServerFiltering(True)
End Sub)
)
@Html.LabelFor(Function(model) model.CanvasPriority)
@Html.TextBoxFor(Function(model) model.CanvasPriority)
@Html.LabelFor(Function(model) model.AsssignedTo)
@Html.TextBoxFor(Function(model) model.AsssignedTo)
And in the onSelect event, I can write to other non-hidden input fields (like CanvasPriority above). I see those values on the popup form, but when the model posts back to my controller, non of those fields (except the LocationName field) comes back in the model. If I manually type into those fields and hit Update, I do see those fields in my model in the controller.
So it seems any field written to within the Select event doesn't "stick" when sending model back to my controller. Is there some other selector other than the simple $("#Id") that needs to be used? I have been working on this for a week and am very frustrated at this point.
It is not very clear how the model is updated and send to the server.
If you are using regular Html FORM element to post the values, then you will need to ensure that the every single input name attribute matches the corresponding Model fields. In this case, the process of matching the posted values to the Server Model is not related to Kendo UI by any means.
If the inputs are bound to a ObservableObject model (for instance in grid editing) using MVVM value binding, then you will need to trigger the change event of the modified inputs in order to notify the related bindings.
Regards,
Georgi Krustev
Telerik