For example, if I have a 'Person' class, with a property of type 'Address'. The 'Address' class has a property 'Street'.
I'd like a grid that shows me a list of people, and one of the columns will be their street:-
columns.Bound(o => o.Address.Street);
This works fine as along as the person has an address assigned to them... however sometimes they might not, and Person.Address might be null... when this is the case, I get the following area originating from the jquery.js file (somewhere in the vicinity of resolveWith):-
Microsoft JScript runtime error: 'Address.Street' is null or not an object
I'm used to deep binding grids in ASP.NET AJAX where it will fail gracefully when it encounters a null in a grid cell.
On a more general note, what is the best practice for the object model here? I have a fairly complex entity model (using OpenAccess) which I found I could successfully map views and controllers to without the use of models; however I hit a limitation when using my objects with AJAX (converting the objects to JSON fails due to the recursive nature of the entity model), so I'm having to create a new MVC model for every class in my entity model which seems like a lot of redundant work.
That aside, it's not clear if the best practice is to recreate the model hierarchy with MVC models, or to flatten it out. To use my problem above as an example, I have a 'PersonModel' which maps to the 'Person' class... it has an 'Address' property which is an 'AddressModel' (which maps to the 'Address' class)...
public
class
PersonModel
{
public
string
Name {
get
;
set
; }
public
AddressModel Address {
get
;
set
; }
//...
public
class
AddressModel
{
public
string
Street {
get
;
set
; }
public
string
State {
get
;
set
; }
//...
Should I be flattening things out, like this:
public
class
PersonModel
{
public
string
Name {
get
;
set
; }
public
string
AddressStreet {
get
;
set
; }
public
string
AddressSuburb {
get
;
set
; }
//...
The latter seems very wrong, but in some circumstances feels like it is expected...
6 Answers, 1 is accepted
Indeed the grid does not make any checks for null when binding to nested objects. This is done mainly for performance reasons.
You can deal with this problem by either setting a ClientTemplate for that column:
columns.Bound(o => o.Address.Street).ClientTemplate("<#= Address? Address.Street : 'empty' #>");
or by flattening your model.
We believe that flattening of models (also referred to ViewModels) is a good practice to follow. It would avoid such null reference problems and only the required properties will be serialized to JSON thus improving performance.
Atanas Korchev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

I haven't tried it yet, but I can see how a ClientTemplate would work around this issue. I still think that it would be better if the grid handled this the same way the ASP.NET AJAX grid does. If there is potential for performance issues, then make the behaviour optional/configurable.
Re the flattening of the model, I've been trying different methods of structuring domain model -> view model relationships... none of them seem ideal... particularly when you are using OpenAccess. I've gotten as far as using AutoMapper, but I still have to manually map child objects based on id's set in my view model.
I did have automatic mapping of the object graph using AutoMapper and model binders working, however child objects were being duplicated when persisted using OpenAccess... for example if I want to create a new "User", and have a DropDownList for "Groups", the group I select is recreated in the database, instead of just being used as a value for the Group property of the user.
Anyway... that is another issue. More specifically to do with the grid...
The way I have settled on is to create a flat view model... to use my earlier example:-
public
class
Person
{
public
int
Id {
get
;
set
; }
public
string
Name {
get
;
set
; }
}
public
class
Address
{
public
int
Id {
get
;
set
; }
public
string
Street {
get
;
set
; }
public
string
Suburb {
get
;
set
; }
}
public
class
PersonModel
{
public
int
Id {
get
;
set
; }
public
string
Name {
get
;
set
; }
public
int
AddressId {
get
;
set
; }
public
string
AddressStreet {
get
;
set
; }
public
string
AddressSuburb {
get
;
set
; }
}
I can map this both ways successfully using AutoMapper.
When creating a person where the address already exists (assuming I selected the address from a DropDownList in my view), I have to:-
Person person =
new
Person();
Mapper.Map(personModel, person);
// messy, but apparently necessary...
person.Address = GetAddress(personalModel.AddressId);
context.Add(person);
context.SaveChanges();
Which is not great, but works.
Now if I want to do this in a grid I hit a problem... let's say I want a grid for all my people, and I have a property of my view model that gave me the full address:-
public
string
AddressString {
get
{
string
.Format(
"{0} {1}"
,
this
.AddressStreet,
this
.AddressSuburb); } }
I want display this as a column in my grid...
//...
columns.Bound(o => o.AddressString);
//...
Which works OK, but if I want to use InCell editing I can't now use my EditorTemplate based on AddressId...
//...
columns.Bound(o => o.AddressId).EditorTemplateName(
"AddressDropDownList"
);
//...
If I was using my domain "Address" class instead, then this would work, because the whole object could be passed to a DisplayTemplate that gives me the string I want (I can't do this now, because even if I had a DisplayTemplate for AddressId, and used a UIHint, I still have to get the string value somehow in the DisplayTemplate, as only the int is passed in... meaning an additional hit to the database and messy code)... but I can't use my domain "Address" object, because aside from not being best practice, breaks AJAX as I mentioned before.
The only two options I can see from where I am at the moment, are:-
1) I bind to o.AddressId... this means I can leverage an EditorTemplate to have a DropDownList when I want to edit InCell, however when not editing, I'm going to see an Id in the column, which means nothing to the end user; or
2) I bind to o.AddressString, which gives the end user something meaningful, but means I can't use an editor... even if I specify an editor template, it's going to bind the result to AddressString, which is useless in the controller
Is there a resolution for this that doesn't involve using a template? and if not, does anyone have a good example of a clean and reasonably generic method for implementing this sort of DropDownList editor in a grid when using an entity model?
Given I need to use AddressId in the controller, I'm guessing I have to stick to binding to AddressId in the grid... which means I'm OK for an editor, I just need an efficient way of converting that AddressId to my AddressString in a display template.
This seems like it should be a fairly common scenario... User/Group, Store/Region, Thread/Forum... anywhere you have a one to many mapping in an entity model and want to use a DropDownList... but there seems to be very little in the way of support for it
Thanks again for your help, and thanks to anyone else who can suggest a solution...
You can check the following examples which show how we have implemented this common scenario:
http://demos.telerik.com/aspnet-mvc/grid/serveredittemplates
http://demos.telerik.com/aspnet-mvc/grid/clientedittemplates
You can also check this code library project for implementing the same in batch editing (InCell mode)
http://www.telerik.com/community/code-library/aspnet-mvc/grid/batch-editing-with-combobox-editor-template.aspx
Atanas Korchev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Many thanks for your reply.
I tried the suggested project at http://www.telerik.com/community/code-library/aspnet-mvc/grid/batch-editing-with-combobox-editor-template.aspx and managed to get it working in my project.
I do have a few follow up questions/comments:-
The example project uses a projected model, not a flattened one as you recommended in your earlier post... does this mean there is no support for this type of editing using your best practice patterns?
As I've had to project the model to use this method, and move away from a flat model, I've had to abandon AutoMapper until I can work out how to project into the auto mapping...
var result = from o
in
GetAll<Person>()
select Mapper.Map<Person, PersonModel>(o);
// is now...
var result = from o
in
GetAll<Person>()
select
new
PersonModel
{
Id = o.Id,
Name = o.Name,
Address =
new
AddressModel
{
Id = o.Address.Id,
Street = o.Address.Street,
Suburb = o.Address.Suburb
}
};
Which means I also now have to handle the create/update differently... I can't just map Model to Entity any more.
With the OnEdit and OnSave handlers, the move from flat model (and mapping) to projection, and the resulting code for create/update, it's added around 70 extra lines of code for this one combo box... none of which can be re-used.
Is this the only solution? if so it makes InCell editing infeasible for almost all but the most basic applications.
In an attempt to make this slightly less painful, I tried to move some code to the editor to promote re-use...
@model PersonModel
<
script
type
=
"text/javascript"
>
function ComboOnLoad(e) {
var combo = $(this).data("tComboBox");
combo.reload();
}
function ComboOnDataBound(e) {
var combo = $(this).data("tComboBox");
combo.value(@(ViewData.Model != null ? ViewData.Model.Id : 0));
}
</
script
>
@(Html.Telerik().ComboBoxFor(m => m)
.DataBinding(d => d
.Ajax()
.Select("AjaxSelectList", "Address")
)
.ClientEvents(e => e
.OnDataBound("ComboOnDataBound")
.OnLoad("ComboOnLoad")
)
)
However it appears that the grid does not pass the model in when editing from the grid. The above code will work when used via "EditorFor" from a plain view (ViewData.Model is not null, and can be used to get the id and set the selected item)... however when this editor is used from the grid, ViewData.Model is always null...
columns.Bound(o => o.Address).ClientTemplate(
"<#= Address.Street #>"
).EditorTemplateName(
"Address"
);

It would appear there is no way of doing this in the editor template, as the Model being null is a known issue:- http://www.telerik.com/community/forums/aspnet-mvc/grid/a-data-is-always-null-in-the-editor-template.aspx
After reviewing the proposed solution I didn't want to move away from a flat model, so I've flattened the Address model into my Person model and I'm declaring the column in the grid like this:-
columns.Bound(o => o.AddressId).ClientTemplate(
"<#= AddressSuburb #>"
).EditorTemplateName(
"Address"
);
My editor looks like this:-
@model System.Int32?
@(Html.Telerik().ComboBoxFor(m => m)
.BindTo(ViewBag.AllAddresses)
)
I'm avoiding ajax binding in the combo for the moment... with ajax binding, the int value from the grid above is displayed briefly before the combo is bound and the actual name is loaded. This doesn't happen when a child model is used in the grid, I suspect because there is no explicit binding between the value in the grid and the combo at this stage.
I've created functions for the javascript required for the OnEdit/OnSave functions:-
function
ComboUpdateEdit(e, editProperty) {
var
$comboBox = $(e.cell).find(
"#"
+ editProperty);
if
($comboBox.length > 0) {
var
comboBoxData = $comboBox.data(
"tComboBox"
);
comboBoxData.fill(
function
() {
comboBoxData.value(e.dataItem[editProperty]);
});
}
}
function
ComboUpdateDisplay(e, editProperty, displayProperty) {
var
$comboBox = $(e.cell).find(
"#"
+ editProperty);
if
($comboBox.length > 0) {
var
comboBoxData = $comboBox.data(
"tComboBox"
);
var
selectedItem = comboBoxData.selectedIndex > -1 ? comboBoxData.data[comboBoxData.selectedIndex] :
null
;
if
(selectedItem) {
e.values[displayProperty] = selectedItem.Text;
}
else
{
var
value = comboBoxData.value();
e.values[displayProperty] = value;
}
}
}
// these can be reused for each combo in the grid...
function
GridOnEdit(e) {
if
(e.dataItem !=
null
) {
ComboUpdateEdit(e,
"AddressId"
);
}
}
function
GridOnSave(e) {
ComboUpdateDisplay(e,
"AddressId"
,
"AddressStreet"
);
}
It's not ideal, but works for basic combos.... hope this is all of some help to someone.
Are there an plans to come up with a more robust way to use combos in a client side grid edit?
We plan to introduce a foreign key column feature for our next release. Hopefully it would improve the integration of the combobox in the grid a lot.
By the way you can send us a stripped down project so we can check it out. I have a feeling that things can be simplified.
Atanas Korchev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items