I can't ge the autocomplete control work in the mvc grid. I created a new Display and Editor template to bind my person object (login and name property). The display template contains a simple Html.DisplayFor control to output the name of the person. Works perfect.
The Editor template contains an autocomplete bound to a server side data source, which populates the autocomplete controls with persons from a data store. So far so good.
Now the problem: When I leave the cell edit mode (with the autocomplete editor shown), a javascript error is thrown in "kendo.web.js". The error pops up in the following line:
that._unbindDataSource();
The error Message:
"Microsoft JScript runtime error: Object doesn't support property or method '_unbindDataSource'".
Any ideas how to get the autocomplete control work together with the grid?
16 Answers, 1 is accepted
Please check this out. I hope this will be fixed soon.
I added a little sample MVC3-solution which should make you easier to reproduce the problem. Just run the application, look for something in the autocomplete column and then leave the edit mode of the cell. The error occurs in the kendo.web.min.js
Hope this makes it easier to understand our problem :)
This is a known issue, which is fixed in the latest internal build (2012.2.924). I will suggest you download it and give it a try.
Georgi Krustev
the Telerik team
However, when I click away from the cell the grid is not updated with the value I selected from the autocomplete. Would you be able to send a working example of the project Mathias posted?
Thanks!!!
Ryan
Like Ryan said there seems to be a bug using the binding of the autocomplete. We had similar issues after leaving the edit mode of a cell. Right now we are not using the standard binding. We updating the dataItem of the Row manually to prevent this issue.
function updateGridAfterLookup(id, userInputValue)
{
var grid = $('#Lookup').closest(".k-grid").data("kendoGrid");
var tr = $('#Lookup').closest("tr");
var dataItem = grid.dataItem(tr);
grid = $('#Lookup').closest(".k-grid").data("kendoGrid");
if (dataItem)
{
dataItem['@ViewData.TemplateInfo.GetFullHtmlFieldName("")'].ID = id;
dataItem['@ViewData.TemplateInfo.GetFullHtmlFieldName("")'].Name = userInputValue;
}
grid.refresh();
}
We are using this method for example in the Select-Event of our Lookup. He should always find the right dataItem based on the fact that only one lookup can exist in batch edit grids.
Hope this can be a workaround for you as long as the binding doesn't work correctly.
I can't get my javascript to refresh my grid. I have something like below on any event and my grid doesn't refresh.
var grid $('#CashMatches').data("kendoGrid");grid.refresh();Does this have something to do with how my grid is defined:
@(Html.Kendo().Grid(Model.cashMatches).Name("CashMatches") .Columns(c => { c.Bound(ct => ct.cashTransactionID).Title("ID").ClientTemplate("<a id=\"tranID-#=cashTransactionID#\">#=cashTransactionID#</a>").Width(210); c.Bound(ct => ct.companyName).Title("Company"); c.Bound(ct => ct.tranReceivedDate).Title("Cash Date"); c.Bound(ct => ct.cashAmount).Title("Cash Amount").Format("{0:N2}");//.Format("#= kendo.format('{0:c}', Price) #"); c.Bound(ct => ct.cashTransactionID).Title("").ClientTemplate("<a id=\"searchID-#=cashTransactionID#\" onclick=\"premiumSearch('#=cashTransactionID#')\" class=\"k-icon k-i-search\"></a>").Filterable(false); c.Bound(ct => ct.policySearch).ClientTemplate("#=policySearch.policyDesc#").Title("Policy").Width(260); c.Bound(ct => ct.premShceduledDate).Title("Scheduled Date"); c.Bound(ct => ct.premDue).Title("Scheduled Amount").Format("{0:N2}"); c.Bound(ct => ct.offset).Title("Offset").ClientTemplate("<span style=\"color:#=offsetColor#\">#=offset#</span>").Format("{0:N2}"); c.Template(@<text></text>).ClientTemplate("<input type='checkbox' #= IsInBatch ? checked='checked':'' # class='chkbx' />") .HeaderTemplate("<input type='checkbox' id='masterCheckBox' onclick='checkAll(this)'/>"); }) .ToolBar(toolbar => { //toolbar.Save().SaveText("Update Batch"); //toolbar.Template(@<text>@{ Html.RenderPartial("CashBatches");}</text>); toolbar.Template(@<text>@{ Html.RenderPartial("CashToolbar");}</text>); }) .Pageable() .Editable(editable => editable.Mode(GridEditMode.InCell)) .Editable(editing => editing.Mode(GridEditMode.InCell).CreateAt(GridInsertRowPosition.Bottom)) .Sortable() .Filterable() .Selectable() .DataSource(d => d.Ajax().PageSize(100).ServerOperation(false) .Batch(true) .Read (r => r.Action("getCashMatches", "Cash")) .Update(r => r.Action("UpdateBatch", "Cash")) .Model(model => { model.Id(p => p.cashTransactionID); model.Field(p => p.cashTransactionID).Editable(false); model.Field(p => p.companyName).Editable(false); model.Field(p => p.tranReceivedDate).Editable(false); model.Field(p => p.cashAmount).Editable(false); model.Field(p => p.premShceduledDate).Editable(false); //model.Field(p => p.policyDesc).Editable(false); model.Field(p => p.premDue).Editable(false); }) ) .Resizable(resize => resize.Columns(true)) )
Mathias, the name of the AutoComplete is not correct. You are setting it to "Person", which actually is the object and not the shown property. Here is how you need to define the AutoComplete.
@model SampleApplication.ViewModels.ResultEntryViewModel
@(Html.Kendo().AutoComplete()
.Name(ViewData.TemplateInfo.GetFullHtmlFieldName(
"Name"
))
.DataTextField(
"Name"
)
.DataSource(dataSource => dataSource.Read(read => read.Action(
"GetAutocomplete"
,
"Home"
)).ServerFiltering(
true
))
.HtmlAttributes(
new
{ @
class
=
"k-widget k-autocomplete k-input"
, style =
string
.Format(
"width:200px"
) })
.Delay(500)
.HighlightFirst(
true
)
)
Ryan, refresh method will just redraw the grid and will not re-fetch the data. If you need to reload the grid use the read method. If the problem still persist I will ask you open another thread as the problem is not related to this one.
Regards,
Georgi Krustev
the Telerik team
I give you a little example:
My object is called Person. Every Person has an ID and a Name. We need the ID based on the fact that there are people with the same name. The grid should only show the name of the person. And also the AutoComplete looks only for the name of a person. But it isn't enough that only the name gets rebound to the grid. We also need the ID to safe it into the DataBase.
I think in your solution we bind only the name and just the name will be rebound to the grid. We need something like a key-value-pair in this (I think the dropdown provides the key-value-stuff (.DataValueField("ID")) and it would be nice if the AutoComplete would do the same)
As you can see in my current solution (3 posts above) we rewrite the ID and Name property of our object manually to the dataItem of the grid, because of the fact that the AutoComplete doesn't support binding the whole object.
This is the reason why I set Person as the Name of the AutoComplete. I wanted to try to bind the whole object against it. The ClientTemplate of the grid should do the rest by showing only the name of the object.
Yes, if you change the name of the AutoComplete to "Person.Name", then only this property will be updated. If you need to bind the AutoComplete to model, then you will need to set the name to "Person", as you did in the test application. The AutoComplete widget supports binding to object, but you need to select item from the suggestions. If you enter custom value, then the MVVM will not be able to find such item in the DataSource of the AutoComplete and will set the Person property to the custom string. That is why you see undefined after this. This is expected behavior. I believe that in this case, you will need to DropDownList widget as it does not allow custom values:
@model SampleApplication.ViewModels.ResultEntryViewModel
@(Html.Kendo().DropDownList()
.Name(ViewData.TemplateInfo.GetFullHtmlFieldName(
""
))
.DataTextField(
"Name"
)
.DataValueField(
"Name"
)
.DataSource(dataSource => dataSource.Read(read => read.Action(
"GetAutocomplete"
,
"Home"
)))
.HtmlAttributes(
new
{ style =
string
.Format(
"width:200px"
) })
)
Check this screencast, which shows what I mean.
Regards,
Georgi Krustev
the Telerik team
thanks for your answer. We still have a few DropDownLists in use but for this special case we need an AutoComplete. The fact is, that the amount of data is way too big for a DropDownList. Our case is very complicated. We made a Lookup-Control for some Grid-columns. This control consists of an AutoComplete, a few Buttons, a Window, 1-2 Grids in the Window,... and so on.
Right now everything still works fine. The only thing is, that we change the DataItems of the Grid manually based on the fact that the AutoComplete doesn't support the binding we need. Probably this will be supported in the future...
As I pointed, currently the AutoComplete supports binding to an object, but the end-user should select some of the available suggestions. There is no way, how to support object binding to a value which does not exist in the DataSource.
Georgi Krustev
the Telerik team
A few more questions then:
1. I have a MVC view which gets a Model. The autocomplete is in a form - so is it possible to bind the AutoComplete (however) against the model to provide on a postback getting the changed item back? Doesn't seems to work as I expect it to.
2. Is there a dataitem of the AutoComplete? I don't mean the dataItems of the dropDown-items... i mean a dataItem of the current "value". The current object which is chosen. I only get access to the value - but I need the whole json-object which has been selected earlier.
This is the current version of the AutoComplete:
@(Html.Kendo().AutoComplete()
.Name(ViewData.TemplateInfo.GetFullHtmlFieldName(""))
.DataTextField("Name")
.DataSource(dataSource => dataSource.Read(read => read.Action("GetLookupPersonAutocomplete", "Shared").Data("onLookupData")).ServerFiltering(true))
.Events(events => events.Open("onLookupOpen").Select("onLookupSelect"))
.HtmlAttributes(new { @class = "k-widget k-autocomplete k-input", style = string.Format("width:200px") })
.MinLength(Model.MinimumChars)
.Delay(200)
)
ad1: So... in a Grid it is bound to the grids-property. If I change the item of the AutoComplete everything seems to perfectly get bound to the grid (yeah the whole object seems to be in the grids dataitem!!! --> which is the goal). That actually doesn't work if a call the View by the EditorFor-call.... @Html.EditorFor(m => m.Person) --> the value doesn't get bound back... the Person property on my model is null on a postback.
ad2: I manually want to change the selected Item of the AutoComplete --> which should also get bound back to the grid/model.. Any possibility? There should be a way... it still works when selecting an item of the suggestions... so how does it work manually?
Straight up to your questions:
#1:
The AutoComplete is a simple input element and the form will post its value. If the widget is used as an editor template (like in your case), the MVVM will get the whole object depending on the selected item in the AutoComplete. Then it will post the model corresponding to the row (depending on the edit mode). If you need to post whole object (outside of the grid), you need to do it manually.
#2:
It has a dataItem(index) method which will return value at dataSource.at(index). The AutoComplete does not persist the selected indexes and that is why you can get the index in the select event. Check this online demo for more information.
RE: ad1:
I believe that the @Html.EditorFor(m => m.Person) will render the autocomplete (input element) with incorrect name and the MVVM will not be able to bind the input value to the row model.
RE: ad2:
Use the select method. Please note that the MVVM depends on the change event, which will be raised when the API is used. Trigger change event manually:
$(
"#id"
).data(
"kendoAutoComplete"
).trigger(
"change"
);
Georgi Krustev
the Telerik team
I will need more information about your current implementation. A runnable test project will be of great help.
Georgi Krustev
Telerik