Search code examples
c#razormany-to-manyrazor-pageskendo-multiselect

Can't bind Kendo Multi Select correctly to read and write to a many to many razor model


I have a many to many relationship in a razor page project that joins Roles (UserRoles) to Apps for permissions reasons in a larger project. I'm trying to get a kendo multi select control to read and write to the database via the model. I can do it with checkboxes, but there are too many entries and I need to use a multiselect drop down instead. I cannot get any help from Telerik other than hard coded array data displaying and not saving, which is of no use. I need to read and write assigned values from and to the database.

The code below basically shows what I am trying to do: selectedRoles needs to be an array or list of integers that are selected RoleID's from the database. In PopulateAssignedAppRoleData below they are reading correctly into the AssignedAppRoleDataList where it calls Assigned = appRoles.Contains(role.ID). However selectedRoles needs to resize to accept new RoleID's as I loop through the join table.

I'm not sure where or how to declare public int[] selectedRoles after I know how many integers it needs to hold, or whether I need to use a List<> or enumerable that I can resize dynamically, or whether I need a counter and then another void to populate in a repeat of the loop or.... :(

selectedRoles.Append (role.ID); does not work

public void UpdateAppRoles(FliveRetryContext context, string[] selectedRoles, App appToUpdate) is working correctly to save to database, I just need to fill the array or list to populate the selected values in drop down list.

Thank you for your help, my C# is fairly basic.

I haven't include all of the models, they aren't relevant but they all work

This is the call in the View:

@(Html.Kendo().MultiSelectFor(m=>m.selectedRoles)
                        .Placeholder("Select ...")
                        .DataTextField("Role")
                        .DataValueField("RoleID")
                        .BindTo(Model.AssignedAppRoleDataList)

and these are the calls in the page model: UpdateAppRoles works fine

public int[] selectedRoles = new int[] {};      

public void PopulateAssignedAppRoleData(FliveRetryContext context, App app)
        {
            var allRoles = context.Role;
            var appRoles = new HashSet<int>(
                app.RoleAppJoins.Select(c => c.RoleID));
            AssignedAppRoleDataList = new List<AssignedAppRoleData>();
            foreach (var role in allRoles)
            {
                AssignedAppRoleDataList.Add(new AssignedAppRoleData
                {
                    RoleID = role.ID,
                    Role = role.RoleName,
                    Assigned = appRoles.Contains(role.ID)

            });
                //This is where I need to append or count, but I don't know the syntax
        if (appRoles.Contains(role.ID))
            {
             selectedRoles.Append (role.ID);
        }
        }


        }

public void UpdateAppRoles(FliveRetryContext context,
            string[] selectedRoles, App appToUpdate)
        {
            if (selectedRoles == null)
            {
                appToUpdate.RoleAppJoins = new List<RoleAppJoin>();
                return;
            }

            var selectedRolesHS = new HashSet<string>(selectedRoles);
            var appRoles = new HashSet<int>
                (appToUpdate.RoleAppJoins.Select(c => c.Role.ID));
            foreach (var role in context.Role)
            {
                if (selectedRolesHS.Contains(role.ID.ToString()))
                {
                    if (!appRoles.Contains(role.ID))
                    {
                        appToUpdate.RoleAppJoins.Add(
                            new RoleAppJoin
                            {
                                AppID = appToUpdate.ID,
                                RoleID = role.ID
                            });
                    }
                }
                else
                {
                    if (appRoles.Contains(role.ID))
                    {
                        RoleAppJoin roleToRemove
                            = appToUpdate
                                .RoleAppJoins
                                .SingleOrDefault(i => i.RoleID == role.ID);
                        context.Remove(roleToRemove);
                    }
                }
            }
        }


Solution

  • Thanks to anyone that considered this, but I got it working

    added a new class:

        public class SelectedAppRoles
        {
            public int RoleID { get; set; }
        }
    

    Then a new list

            public List<SelectedAppRoles> selectedRoles;
    

    Then used the list instead of an array

    foreach (var role in allRoles)
                {
                    AssignedAppRoleDataList.Add(new AssignedAppRoleData
                    {
                        RoleID = role.ID,
                        Role = role.RoleName,
                        Assigned = appRoles.Contains(role.ID)
    
                    });
    
                    if (appRoles.Contains(role.ID))
                    {
                        selectedRoles.Add(new SelectedAppRoles
                        {
                            RoleID = role.ID,
                        });                 
                    }
                }