1

I have the following Entity Framework class with a column which is a Foreign Key to the Primary Key in the same table:

[Table("Items")]
public class Item
{
    [Key]
    public long ItemID { get; set; }

    public string ItemName { get; set; }

    public long? ItemParentID { get; set; }

    [ForeignKey("ItemParentID")]
    public virtual Item Parent { get; set; }

    public virtual ICollection<Item> Children { get; set; }

}

The mapping above works great and I am able to get all the children items in the Children property to the nth level simply by passing the ItemParentID and selecting the Items.

Now I have to bind this data along with all the children items and their children items etc. in my razor view. I have started with the following code:

@if (Model.ChildItems.Count > 0)
    {
        foreach (Item parentItem in Model.ChildItems)
        {
            <div class="list-title">
                <span>@parentItem.ItemName</span>
                <ul>
                    @if (parentItem.Children.Count > 0)
                    {
                        foreach (Item childItem in parentItem.Children)
                        {
                            <li>
                                <a href="@FrontEndDomain.GetWebsiteURL()/@childItem.ItemID/details/@FrontEndDomain.GetURLString(Model.ParentItemName)/@FrontEndDomain.GetURLString(childItem.ItemName)" title="@childItem.ItemName">
                                    @childItem.ItemName
                                </a>
                            </li>
                        }
                    }
                    else
                    {
                        <li>
                            No items available for @parentItem.ItemName.
                        </li>
                    }
                </ul>
            </div>
        }
    }
    else
    {
        <h4>No items available.</h4>
    }

The above code works well with 2 levels of children items but I want to bind data of all the child items and their child items to nth level. I have checked other questions on SO but they are complex and most of them doesn't deal with lists like Children property mentioned above. Any simple way to get this done?

seadrag0n
  • 848
  • 1
  • 16
  • 40
  • What you need is a recursive function. One option would be to create a HtmlHelper extension method as shown in [this answer](http://stackoverflow.com/questions/27146524/how-to-render-singly-linked-list-in-mvc-view-page/27147744#27147744) –  Mar 21 '16 at 05:10
  • Hmmm... You could try using an `@helper` method to render this recursively. Pass in the current node as parameter, then iterate and render children. Example of `@helper` syntax here... http://stackoverflow.com/a/6532107/4322803 – Quantumplate Mar 21 '16 at 05:13
  • I find it hard to believe that the other answers on SO don't deal with lists containing lists - there's not that many other options. Can you post the links to the ones you looked at? – Enigmativity Mar 21 '16 at 07:08

2 Answers2

1

You can recursive use Html.RenderPartial helper like this(it is just example, without your specific markup):

View:

@model Item

<p>@Model.ItemName</p>
<ul>
    @if (Model.Children != null && Model.Children.Count > 0)
    {
        foreach (var child in Model.Children)
        {
            <li>
                @{Html.RenderPartial("Index", child);}
            </li>
        }
    }
    else
    {
        <li>
            No items available for @Model.ItemName.
        </li>
    }
</ul>
Slava Utesinov
  • 13,410
  • 2
  • 19
  • 26
0

You can solve this quite nicely with a recursive partialview.

RecursivePartial.cshtml:

@model Item

<span>@Model.ItemName</span>
<ul>
    @if (Model.Children?.Any() ?? false)
    {
        foreach (var child in Model.Children)
        {
            <li>
                @Html.Partial("RecursivePartial", child)
            </li>
        }
    }
    else
    {
        <li>
            No items available for @Model.ItemName.
        </li>
    }
</ul>

You could then call this partialview from wherever you need

Index.cshtml:

@model IEnumerable<Item>

@if (Model?.Any() ?? false)
{
    foreach (var item in Model)
    {
        @Html.Partial("RecursivePartial", item)
    }
}
else
{
    <h4>No items available.</h4>
}
Shazi
  • 1,490
  • 1
  • 10
  • 22