EF Core ASP.NET MVC include details and index in one view one-to-many
I have a todo table with a one-to-many relationship to a steps table. There are many steps for each todo. The Index view lists all the todos, and the Details view shows one todo with its many steps in a table below it. What I would like is to have a view that shows all the todos listed with all of its steps under each. I plan to have an accordion to expand/collapse the steps for each todo in the list. Any help on how to do this would be greatly appreciated.
controller
public IActionResult Index()
{
List<TodoList> todolists;
todolists = _context.TodoLists.ToList();
return View(todolists);
}
public IActionResult Details(int id)
{
TodoList todolist = _context.TodoLists
.Include(e => e.Steps)
.Where(a => a.Id == id).FirstOrDefault();
return View(todolist);
}
Details view
<form asp-action="Details" id="TodoForm">
<div asp-validation-summary="ModelOnly" ></div>
<div >
<label asp-for="Name" ></label>
<input asp-for="Name" disabled />
</div>
<div >
<label asp-for="Description" ></label>
<input asp-for="Description" disabled />
</div>
<div >
</div>
<div >
<table id="StepTable">
<thead>
<tr>
<th>Priority</th>
<th>Name</th>
<th style="width:75px;">
</th>
</tr>
</thead>
<tbody>
@for (int i = 0; i < Model.Steps.Count; i )
{
<tr>
<td>
<input asp-for="@Model.Steps[i].Priority" disabled />
</td>
<td>
<input asp-for="@Model.Steps[i].Name" disabled />
</td>
<td style="width:60px;">
</td>
</tr>
}
</tbody>
</table>
</div>
<input type="hidden" id="hdnLastIndex" value="0" />
</form>
Index view
<table >
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Description)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id" ><i ></i> Edit</a>
<a asp-action="Details" asp-route-id="@item.Id" ><i ></i> Details </a>
<a asp-action="Delete" asp-route-id="@item.Id" ><i ></i> Delete</a>
</td>
</tr>
}
</tbody>
</table>
CodePudding user response:
I suggest you can use Bootstrap Collapse.
Firstly be sure your project contains bootstrap.css
and bootstrap.js
.
Then,check the Bootstrap version. Bootstrap uses data-target
/data-toggle
before v5.0 and uses data-bs-target
/data-bs-toggle
for v5.0.
Here is a whole working demo:
Model
public class TodoList
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public List<Step> Steps { get; set; }
}
public class Step
{
public int Id { get; set; }
public string Priority { get; set; }
public string Name { get; set; }
}
View
@model IEnumerable<TodoList>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table >
<thead>
<tr>
<th></th>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Description)
</th>
<th></th>
</tr>
</thead>
<tbody>
@{
int i = 0;
}
@foreach (var item in Model) {
<tr>
<td>
<button type="button"
data-bs-toggle="collapse" data-bs-target="#step_@i"
aria-expanded="false" aria-controls="step_@i"> </button>
</td>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
<tr id="step_@i" >
@for (int j = 0; j < item.Steps.Count; j )
{
<td>
Priority:<input asp-for="@item.Steps[j].Priority" disabled />
<br/>
Name:<input asp-for="@item.Steps[j].Name" disabled />
</td>
}
</tr>
i ;
}
</tbody>
</table>
Add Bootstrap.css
and Bootstrap.js
in _Layout.cshtml
<head>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
</head>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
Controller
public class TodoListsController : Controller
{
private readonly MvcProjContext _context;
public TodoListsController(MvcProjContext context)
{
_context = context;
}
// GET: TodoLists
public async Task<IActionResult> Index()
{
return View(await _context.TodoLists.Include(a=>a.Steps).ToListAsync());
}
}