ASP.NET MVC List of Categorized Items to Display as Accordion

Viewed 208

I currently have a page showing a list of all items sorted by Category and SortOrder. The page must contain "all" items and users should be able to hide/unhide items by category using accordion / collapsible panels.

I have the following simplified models:

public class Basket
{
    public List<Item> Items { get; set; }
}

public class Item
{
    public string Category { get; set; }
    public string Name { get; set; }
    public int SortOrder { get; set; }
}

The object being passed from my controller to my view:

Basket model = new Basket()
{
    Items = new List<Item>()
    {
        new Item(){ Category = "CategoryA", SortOrder = 1, Name = "A001" },
        new Item(){ Category = "CategoryA", SortOrder = 2, Name = "A002" },
        new Item(){ Category = "CategoryA", SortOrder = 3, Name = "A003" },
        new Item(){ Category = "CategoryB", SortOrder = 1, Name = "B001" },
        new Item(){ Category = "CategoryB", SortOrder = 2, Name = "B002" }
    }
};

return View(model);

My Display Templates for the Basket model:

@model SampleApp.Models.Basket

<div>
    @Html.DisplayFor(model => model.Items)
</div>

My Display Templates for the Item model:

@model SampleApp.Models.Item

@{
    string cat = Model.Category;
}

<div>
    @if (Model.SortOrder == 1)
    {
        <button type="button" class="btn btn-info" data-toggle="collapse" data-target=".@cat">@cat</button>
    }

    <div class="collapse @cat">
        @Html.DisplayFor(model => model.Category) -
        @Html.DisplayFor(model => model.SortOrder) -
        @Html.DisplayFor(model => model.Name)
    </div>
</div>

The result I was aiming for:

<div>
    <div>
        <button type="button" class="btn btn-info" data-toggle="collapse" data-target=".CategoryA">CategoryA</button>

        <div class="CategoryA collapse in" aria-expanded="true" style="">
            <div>CategoryA - 1 - A001</div>
            <div>CategoryA - 2 - A002</div>
            <div>CategoryA - 3 - A003</div>
        </div>
    </div>

    <div>
        <button type="button" class="btn btn-info" data-toggle="collapse" data-target=".CategoryB">CategoryB</button>

        <div class="CategoryB collapse in" aria-expanded="true" style="">
            <div>CategoryB - 1 - B001</div>
            <div>CategoryB - 2 - B002</div>
        </div>
    </div>
</div>

The result I am getting:

<div>
    <div>
        <button type="button" class="btn btn-info" data-toggle="collapse" data-target=".CategoryA">CategoryA</button>

        <div class="CategoryA collapse in" aria-expanded="true" style="">CategoryA - 1 - A001</div>
    </div>
    <div>
        <div class="CategoryA collapse in" aria-expanded="true" style="">CategoryA - 2 - A002</div>
    </div>
    <div>
        <div class="CategoryA collapse in" aria-expanded="true" style="">CategoryA - 3 - A003</div>
    </div>

    <div>
        <button type="button" class="btn btn-info" data-toggle="collapse" data-target=".CategoryB">CategoryB</button>

        <div class="CategoryB collapse in" aria-expanded="true" style="">CategoryB - 1 - B001</div>
    </div>
    <div>
        <div class="CategoryB collapse in" aria-expanded="true" style="">CategoryB - 2 - B002</div>
    </div>
</div>
1 Answers

I did not work with asp.net mvc 4 but I know what is your problem. you need three view template not two.

One for Basket model, one for group of items with specific category and one for each item inside that category. You missing view for group of items.

@model List<SampleApp.Models.Item>

@{
    var groupItems = Model.GroupBy(item => item.Category).Select(item => item.Key);
}

<div>
    @if (Model.SortOrder == 1)
    {
        <button type="button" class="btn btn-info" data-toggle="collapse" data-target=".@cat">@cat</button>
    }

   @foreach(var groupItem in groupItems)
   {
      var itemsInsideAGroup = Model.Where(item => item.Category.Equals(groupItem));

      <div class="@groupItem collapse in" aria-expanded="true" style="">
          <!-- Here load item template with loop for itemsInsideAGroup -->
      </div>
   }
</div>

and item template is something like this

@model SampleApp.Models.Item

<div>
     @Html.DisplayFor(model => model.Category) -
     @Html.DisplayFor(model => model.SortOrder) -
     @Html.DisplayFor(model => model.Name)
</div>
Related