Kendo UI DropDownListFor html wrapper - How to set up the BindTo to a collection in model? Rather than ViewData or Viewbag

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: https://i.sstatic.net/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);

Upvotes: 3

Views: 2180

Answers (1)

Steve Greene
Steve Greene

Reputation: 12324

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>

Upvotes: 2

Related Questions