0

I am trying to post back the changes to the nested list of checkboxes for Groups and their Users but keep getting my list Count = 0 when it posts. Right now, there are no groups within groups, but I would still like to make this recursive if we move towards that in the future.

I have a hierarchical IList of GroupsUsers attached to my Activity Model as such:

Activity:

public class Activity
{
    public int ActivityId { get; set; }
    public string Name { get; set; }
    public string Path { get; set; }
    public string Description { get; set; }
    public Nullable<int> ParentId { get; set; }
    public IList<GroupsUsers> Hierarchy { get; set; }
}

GroupsUsers:

public class GroupsUsers
{
    public Guid? Guid { get; set; }
    public string Name { get; set; }
    public bool IsAllowed { get; set; } = false;
    public IList<GroupsUsers> Children { get; set; } = new List<GroupsUsers>();
}

I have tried EditorFor, Partial View, and Helper but am having no luck with any of them posting back the Hierarchy. My Model.Hierarchy is posting back with Count = 0.

Here's my current attempt:

Main View (watered down):

@model MyProject.Models.Activity

@using (Html.BeginForm())
{
    <!-- Activity stuff -->

    <ul style="list-style:none;">
        @for (var i = 0; i < Model.Hierarchy.Count(); i++)
        {
            @Html.EditorFor(model => model.Hierarchy[i])
        }
    </ul>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Save" class="btn btn-default" />
        </div>
    </div>
}

Current Attempt. GroupsUsers.cshtml:

@model MyProject.Models.GroupsUsers

<li>
    @Html.HiddenFor(model => model.Guid)
    @Html.HiddenFor(model => model.Name)
    @Html.CheckBoxFor(model => model.IsAllowed, new { @class = "groupsusers-checkbox", @style = "margin-right:5px; cursor:pointer;", @value = Model.Guid.ToString() }) @Html.LabelFor(model => model.IsAllowed, Model.Name, new { @class = "build-checkbox-label", @style = "font-weight:normal; margin-top:-2px;" })

    @if (Model.Children.Any())
    {
    <ul style="list-style:none;">
        @for (var i = 0; i < Model.Children.Count(); i++)
        {
            @Html.EditorFor(model => model.Children[i])
        }
    </ul>
    }
</li>

I'm looking for my list of checkboxes to display as a list hierarchy recursively and post Model.Hierarchy back properly.

Any help would be appreciated... I only included Attempt #2 and #3 in case I was close to having it correct.

justiceorjustus
  • 2,017
  • 1
  • 19
  • 42
  • I feel like the `foreach` loop is what's tripping things up - the model binder isn't able to determine that there is a relationship between `Hierarchy` and `Children` objects, and so you end up with no `Children`. In fact, I suspect they're being posted as additional `Hierarchy` entries. That said, try switching to a `for` loop - this will make it so that the naming convention of the checkboxes indicates to the model binder that they are nested lists. – sleeyuen Jun 08 '17 at 15:45
  • The first issue is the incorrect use of `@Html.Partial()` in the main view - you should be using an `EditorTemplate` for type of `GroupsUsers` so the `name` attributes are correctly prefixed (but if you do want to use `@Html.Partial()` then refer [this answer](https://stackoverflow.com/questions/29808573/getting-the-values-from-a-nested-complex-object-that-is-passed-to-a-partial-view/29809907#29809907) –  Jun 09 '17 at 05:21
  • Your current attempt using a `foreach` loop will not work. For an explanation, refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943). Your `EditorTempate` needs to be named `/Views/Shared/EditorTemplates/GroupsUsers.cshtml` and the model in that template needs to be `@model GroupUsers` (not `IEnumerable`) –  Jun 09 '17 at 05:22
  • @StephenMuecke I have updated my post to follow what you instructed and show what I have at the moment. I had to work around not passing the IEnumerable itself in a bit of an ugly way, but I'm still receiving Count = 0 on the post. It seems to find the EditorFor template correctly, however. – justiceorjustus Jun 09 '17 at 13:13
  • Its just `@Html.EditorFor(model => model.Hierarchy)` and `@Html.EditorFor(model => model.Children)` - you do not need a loop, or a check for `null`. And remove `@value = Model.Guid.ToString()` NEVER attempt to set the `value` attribute (or the `name` attribute) when using a `HtmlHelper` method. Your property is a `bool` - it cannot possibly bind to a `Guid` –  Jun 09 '17 at 20:39

0 Answers0