3
votes

I'm learning about Kendo UI. We're moving towards using Kendo UI for everything in the views of our MVC apps.

I am attempting to bind to a collection that's within the model object that is in each row for the Kendo Grid. We are using an EditorTemplate to achieve the dropdown, which has worked for several more simple examples.

In this case however, we are attempting to make the source of this dropdown menu filtered by the value of property in that object.

Model object:

public class AppRolesForUserVM
{
    public int AppId { get; set; }
    public string appName { get; set; }
    public AppRole appRole { get; set; }
    public AppUser appUser { get; set; }
    public List<AppRole> appRolesList { get; set; }

}

Snippet from the grid:

 @(Html.Kendo().Grid<AppRolesForUserVM>()
              .Name("ApplicationGrid")
              .Columns(columns =>
              {
                  columns.Bound(p => p.AppId).Title("Application Id").Width(50);
                  columns.Bound(p => p.appName).Title("Application Name").Width(100);                    
                  columns.Bound(p => p.appRole.Id).ClientTemplate("#=appRole.Name#").EditorTemplateName("AppRolesForUser").Title("AppRole").Width(100);  // ***** 

The last column in the above code is where we've been attempting to implement this drop down menu. It refers to editorTemplateName AppRolesForUser which is below:

AppRolesForUser EditorTemplate:

@model AdminAuthorization.Models.ViewModels.AppRolesForUserVM

@(Html.Kendo().DropDownListFor(p => p.appRole.Id)
    .Name("appRole.Id")
    .DataTextField("Name")
    .DataValueField("Id")
    .BindTo((IEnumerable)ViewData["ListOfRoles"]) // ***** 
)

Where I've marked **** is where I'm hoping to figure out how to make this actually pull data based on an input parameter from the model object AppRolesForUserVM... Passing the appId property to get a list of roles for that application... Simple enough right?

With the way I have it set up now, the dropdown list shows after you select the Edit button, but the dropdown list is empty! Link to image of dropdown with nothing in it: http://i.stack.imgur.com/bEcMw.png

I've been attempting to change the BindTo within the editortemplate to refer to Model.appRolesList, but every time I get null pointer exceptions because I guess the model isn't being passed to this dropdownlistFor helper? Not sure...

My team has been a little stumped on how to implement this functionality. We're all fairly new to using Kendo, and thus there are no experts in the group when it comes to the ins and outs of these types of circumstances.

Thank you in advance for taking the time to read this! :)

EDIT: it seems like the foreign key method will be the best way to implement this functionality, but I'm running into issues trying to reference the collection from the foreign key html wrapper. I'll post another code snippet when I'm back at my desk

EDIT 2 with code snippet:

This is the updated grid to use just a .ForeignKey reference instead of the .Bound. In this example I'm still struggling to reference the list of objects within the AppRolesForUserVM object... Might anybody have the syntax to do so? Most of the examples I've seen in the Kendo Demos are fairly simple where they refer to a collection stored in ViewData or ViewBag.

 @(Html.Kendo().Grid<AppRolesForUserVM>()
                  .Name("ApplicationGrid")
                  .Columns(columns =>
                  {
                      columns.Bound(p => p.AppId).Title("Application Id").Width(50);
                      columns.Bound(p => p.appName).Title("Application Name").Width(100);
                      columns.ForeignKey(p => p.appRole.Id, q.appRolesList).ClientTemplate("#=appRole.Name#").Title("App Role").Width(100);
1
Do you have a ViewData item named "ListOfRoles"? Your model shows you have a property List<AppRole> appRolesList which I assume is what you want to display for the options? - user3559349
doesn't the ForeignKey column type allow you to specify the dataSource.. why not use it? demos.telerik.com/aspnet-mvc/grid/foreignkeycolumn - JamieD77
Jamied77, I was not aware of that feature, thank you! :) ... Stephen, yes using the appRolesList is the plan. My view model already has the filtered list contained within appRolesList, so hopefully pointing to that within the model object of the editor template could be feasible? When attempting to plug in that value is where I ran into null pointer exceptions. 8^/ - Dinglemeyer NeverGonnaGiveUUp
Then would it not be .BindTo(p => p.appRolesList)? - user3559349
I'll be trying that syntax when I get back to the office. Thank you Stephen! - Dinglemeyer NeverGonnaGiveUUp

1 Answers

2
votes

I haven't done this with an EditorTemplate, but another option is to make a controller action that returns roles and use it:

public JsonResult ReadRoles(int id)
{
    var roleList = context.Roles.Where(r => r.AppId == id).OrderBy(r => r.Name).ToSelectList(r => r.Id.ToString(), r => r.Name);
    var result = Json(roleList, JsonRequestBehavior.AllowGet);
    return result;
}

Then your drop down becomes something like:

@(Html.Kendo().DropDownListFor(p => p.appRole.Id)
    .Name("appRole.Id")
    .DataSource(source => source.Read(read => read.Action("ReadRoles", "App", new { id = @Model.AppId })
    .DataTextField("Name")
    .DataValueField("Id")
    .HtmlAttributes(new {data_value_primitive = "true"})
)

where App is the controller you put the read action into and ToSelectList is an extension method we wrote to create an IEnumerable.

EDIT with the final approach I was able to use to get this working: I have gotten this working and it is using a similar approach to what was in this answer, just slightly tweaked.

The dropdown editortemplate code I'm using now is:

@model Project.Models.ViewModels.AppRolesForUserVM

@(Html.Kendo().DropDownListFor(p => p.appRole.Id)
    .Name("appRole.Id")
    .DataSource(source => source.Read(read => read.Action("ReadRoles", "App").Data("onRead")))
    .DataTextField("Name")
    .DataValueField("Id")
    .HtmlAttributes(new { data_value_primitive = "true" })
)

The .Data("onRead") in the data source declaration calls the following function, which gets the data row being edited and then gets the value from the first column in that row; which contains the ID I want to pass to my controller's read action:

    <script type="text/javascript">
        function onRead(e) {
            var row = $(event.currentTarget).find(".k-grid-edit-row");
            var id = row.find("td:first").html();
            return { id: id };
        }
    </script>