
I have these model classes:
public
class
Part
{
public
Guid Id {
get
;
set
; }
string
Name {
get
;
set
; }
public
Part()
{
}
}
public
class
DetailItem
{
public
Guid Id {
get
;
set
; }
public
Part Part {
get
;
set
; }
public
DetailItem()
{
}
}
In my View, the model is the DetailItem. I am trying to use a ComboBox to select the Part for the DetailItem:
@(Html.Kendo().ComboBoxFor(model => model.Part)
.DataValueField("Id")
.DataTextField("Name")
.Filter(FilterType.Contains)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetParts", "RefData");
})
.ServerFiltering(true);
}
)
)
14 Answers, 1 is accepted
Is the combobox posted with a form? If yes, then you should bind the combobox to the Part.Id property:
Html.Kendo().ComboBoxFor(model => model.Part.Id)
Regards,
Daniel
Telerik

Thanks--I will try that.
How do I handle the case where the user enters a value that's not in the list in this case? How does the new value get passed back?
The custom value will be sent to the server but in most cases it will not be bound by the model binder. If custom values should be allowed then you could retrieve it from the ModelState or from the request data:
if
(ModelState[
"Part.Id"
].Errors.Any())
{
var customValue = ModelState[
"Part.Id"
].Value.AttemptedValue;
ModelState.Remove(
"Part.Id"
);
AddCustomValue(customValue);
}
Regards,
Daniel
Telerik

Binding to model.Part.Id worked for the ComboBox. Maybe this should be a new thread, but the next problem is that I have the ComboBox in a Grid.
To get the grid to show the part name instead of part ID when the cell isn't in edit mode, I have to have a ClientTemplate:
columns.Bound(p => p.Part.Id).EditorTemplateName("PartComboBox").ClientTemplate("#= Part.Name #");
That works until I enter a new custom value in the ComboBox. The ComboBox shows the value, but once I leave Edit mode for the cell, the grid shows "undefined" for the value. How do I get it showing the new value?
If the same editor is used for a grid then I can suggest either to use a ForeignKey column for the Part.Id field or bind the column to the object and explicitly specify the binding in the editor via the HtmlAttributes method:
columns.Bound(p => p.Part)
Html.Kendo().ComboBoxFor(model => model.Part.Id)
.HtmlAttributes(
new
{ data_bind =
"value:Part"
})
...
Regards,
Daniel
Telerik

I wasn't able to successfully apply either of those approaches in my scenario.
I have another class called "Assembly" that has a collection of Parts. On the edit page for an Assembly I have a grid bound to the Parts collection:
My grid definition is:
@(Html.Kendo().Grid(Model.Parts)
.Name("Parts")
.Columns(columns =>
{
columns.Bound(p => p.Quantity);
columns.Bound(p => p.Part.Id).EditorTemplateName("PartComboBox").ClientTemplate("#= Part ? Part.Name : '' #");
columns.Bound(p => p.Instructions);
columns.Command(command => command.Destroy()).Width(100);
}
)
.Navigatable()
.Editable(edit => edit
.Mode(GridEditMode.InCell)
.CreateAt(GridInsertRowPosition.Bottom)
)
.DataSource(datasource => datasource
.Ajax()
.Model(model =>
{
model.Id(p => p.Id);
model.Field(p => p.Part).DefaultValue(new Models.PartViewModel());
})
)
)
The PartComboBox editor template is this:
@(Html.Kendo().ComboBox()
.Name("Part")
.DataValueField("Id")
.DataTextField("Name")
.Filter(FilterType.Contains)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetParts", "RefData").Data(@<
text
>
function()
{
var val=$("#Part").data("kendoComboBox").input.val();
return {
Name: val}
}
</
text
>);
})
.ServerFiltering(true);
}
)
)
I am not sure if i understand correctly the issue but if you wish to submit the grid data with a form as part of the assembly then you can use the approach demonstrated in this code-library project.
Regards,
Daniel
Telerik

I'm not trying to submit the grid as part of the form.
My problem is that if I bind using the ComboBox like this:
columns.Bound(p => p.Part.Id).EditorTemplateName("PartComboBox");
The cell (when not in edit mode) shows the part ID rather than the part name. I can fix that by changing to:
columns.Bound(p => p.Part.Id).EditorTemplateName("PartComboBox").ClientTemplate("#= Part ? Part.Name : '' #");
That works until I enter a new custom value in the ComboBox. The ComboBox shows the value, but once I leave Edit mode for the cell, the grid shows "undefined" for the value.
I tried various approaches of binding to "p.Part" instead of "p.Part.Id" but that doesn't work either. I either end up with the cell showing nothing or showing "[object Object]".
It seems the approach with explicitly specifying the binding will not work for the combobox. Because of the name generated for the text input the correctly bound object will be overridden. In that case I can suggest to use a separate editor for the grid or to remove the text input name via code or to use a foreignkey column. I attached a sample project that demonstrates the suggested solutions.
Regards,
Daniel
Telerik

The demo solution you posted is showing problems similar to what I have been describing.
In the top grid ("Parts"), select a cell and enter a value that's not from the list, like "Part 109". When you leave the cell, it shows "undefined."
In the bottom grid ("PartsForeignKey"), if you enter a non-existent value the cell is empty when you leave it.
The foreignkey column cannot be used for custom values because it can only show values available in the data that is passed initially on the server. The problem with displaying the value when binding to object can be avoided by changing the logic in the template but the binding will not work correctly after setting a custom value because the field will no longed be an object. Custom binding might be the best option for this scenario. I attached the project modified to demonstrate one possible implementation.
Regards,
Daniel
Telerik

Thank you--that seems to be working.
The last piece is that I need to do server filtering for the combo box data source, based on the entered text. I previously had this working, but since I adapted to use your code it's not. What is the id of the combo box now?
I have this for the data source:
source.Read(read =>
{
read.Action("GetParts", "Home").Data(@<
text
>
function()
{
var val=$("#Part").data("kendoComboBox").input.val();
return {
userId: @ViewBag.UserId,
Name: val}
}
The id that will be generated by default would be "Part_Id". You can also use the HtmlAttributes method to set any ID to the input:
.HtmlAttributes(
new
{ data_bind =
"customValueObject:Part"
, data_skip=
"true"
, id =
"Part"
})
Regards,
Daniel
Telerik

I hadn't noticed that the sample you sent had the ID set to a Guid using the HtmlAttributes. Now I see.
Thanks for the help; I think I have this all working now.