Perform Master Detail CRUD operations in ASP.NET Core (Part 4)

In Part 2 and
Part 3 of this article
series we completed TeamsComtroller and TeamMembersController respectively. All
of the controller actions that we wrote so far return Main view. They also
supply a MasterDetailViewModel object to the Main view. In this part we will
begin developing a set of views and partials that renders the UI of the
application.
The following figure shows how various items are organized:

As you can see, the Views folder has three sub-folders namely Teams,
TeamMembers, and Shared.
The Teams folder contains three partials namely _ShowTeam, _InsertTeam, and _UpdateTeam.
These partials display a Team in readonly, insert, and update mode respectively.
The TeamMembers folder contains three partials namely _ShowTeamMember, _InsertTeamMember,
and _UpdateTeamMember. These partials display a TeamMember in readonly, insert,
and update mode respectively.
The Shared folder contains the Main view and two partials viz. _Teams and _TeamMembers.
All the actions of TeamsController and TeamMembersController return Main view.
The Main view, in turn, renders _Teams and _TeamMembers partials as needed. The
_Teams and _TeamMembers partials render the master and detail grids
respectively.
Now that you know what makes the UI of the application, let's add these
pieces one-by-one.
First of all, add the Main.cshtml view file using Add New Item dialog.

Then add the following markup to the Main.cshtml file.
@model MasterDetailViewModel
...
<body>
<partial name="_Teams" model="@Model" />
<br /><br />
<partial name="_TeamMembers" model="@Model" />
<br /><br />
</body>
</html>
Notice the code shown in bold letters. The @model directive specifies the
MasterDetailViewModel class as the model for Main view.
Recollect that we created this class in the earlier parts of this series. All
the actions of TeamsController and TeamMembersController pass an
MasterDetailViewModel object to the Main view.
Main view then renders _Teams partial and _TeamMembers partial such that
master grid is displayed at the top followed by the detail grid. We also pass
the Model object to these partials using model property of the <partial> tag
helper.
The _Teams partial used by the above markup is discussed in the following
section.
Firstly, add the _Teams.cshtml partial to the Shared folder and then write
the following code and markup into it.
@model MasterDetailViewModel
<h1>List of Teams</h1>
<form method="post">
<input type="submit"
value="Insert Team"
asp-controller="Teams"
asp-action="InsertEntry" />
<br /><br />
<table border="1" cellpadding="10">
<tr>
<th>Team ID</th>
<th>Name</th>
<th>Description</th>
<th colspan="2">Actions</th>
</tr>
@foreach (var item in Model.Teams)
{
if (Model.SelectedTeam != null)
{
if (item.TeamID ==
Model.SelectedTeam.TeamID)
{
@:<tr class="SelectedRow">
}
else
{
@:<tr>
}
}
else
{
@:<tr>
}
<td>@item.TeamID</td>
<td>@item.Name</td>
<td>@item.Description</td>
<td>
<input type="submit"
value="Manage Team"
asp-controller="Teams"
asp-action="Select"
asp-route-teamid="@item.TeamID" />
</td>
<td>
<input type="submit"
value="Manage Members"
asp-controller="TeamMembers"
asp-action="List"
asp-route-teamid="@item.TeamID" />
</td>
@:</tr>
}
</table>
</form>
<br /><br />
@{
if (Model.DataEntryTarget == DataEntryTargets.Teams)
{
if (Model.SelectedTeam != null)
{
if (Model.DataDisplayMode ==
DataDisplayModes.Read)
{
await Html.RenderPartialAsync
("_ShowTeam", Model.SelectedTeam);
}
if (Model.DataDisplayMode ==
DataDisplayModes.Update)
{
await Html.RenderPartialAsync
("_UpdateTeam", Model.SelectedTeam);
}
}
if (Model.DataDisplayMode == DataDisplayModes.Insert)
{
await Html.RenderPartialAsync
("_InsertTeam", new Team());
}
}
}
The _Teams partial receives the same MasterDetailViewModel model object that
you passed to the Main view. Notice that the <form> tag helper doesn't specify
any controller or action. That's because based upon the button clicked by the
user (Insert, Edit, Save etc.) the action is going to change. Hence, we
configure the asp-controller and asp-action on the submit buttons rather than
form element.
The _Teams partial renders the master grid as shown below:

There are three submit buttons - Insert Team, Manage Team, and manage
Members.
The Insert Team button submits the form to the InsertEntry() action of
TeamsController. The Manage Team button submits the form to the Select() action
of TeamsController. It also passes the TeamID route parameter.
The Manage Members button submits the form to the List() action of
TeamMembersController. A TeamID is also passed to the List() action so that
members for a specific team can be shown in the detail grid.
The Team records are displayed in a table by iterating through the Teams
property of MasterDetailViewModel. While rendering the table rows we check
whether TeamID being rendered is same as SelectedItem.TeamID. If so, we display
that row in highlighted color. Otherwise, we render that row without any
highlight.
Observe the @code block below the table and the form. This code block
displays a Team record for the selected Team (if any). It uses the
DataDisplayMode property to decide how the Team record is to be displayed.
Depending on the value of DataDisplayMode we render _ShowTeam, _InsertTeam, or _UpdateTeam
partials. We will create these partials in the later parts of this article
series. For example, a Team is shown in read-only fashion using _ShowTeam
partial like this:

This completes _Teams partial. The _TeamMembers partial follows a similar
pattern and is shown below:
@model MasterDetailViewModel
@{
if (Model.DataEntryTarget ==
DataEntryTargets.TeamMembers)
{
if (Model.SelectedTeam != null)
{
<h2>List of Members :
@Model.SelectedTeam.Name</h2>
<form method="post">
<input type="submit"
value="Insert Member"
asp-controller="TeamMembers"
asp-action="InsertEntry"
asp-route-teamid=
"@Model.SelectedTeam.TeamID"/>
<br /><br />
<table border="1" cellpadding="10">
<tr>
<th>Team ID</th>
<th>Member ID</th>
<th>Name</th>
<th>Email</th>
<th colspan="2">Actions</th>
</tr>
@foreach (var item in
Model.SelectedTeam.Members)
{
if (Model.SelectedTeamMember != null)
{
if (item.TeamMemberID ==
Model.SelectedTeamMember.TeamMemberID)
{
@:<tr class="SelectedRow">
}
else
{
@:<tr>
}
}
else
{
@:<tr>
}
<td>@item.TeamID</td>
<td>@item.TeamMemberID</td>
<td>@item.Name</td>
<td>@item.Email</td>
<td>
<input type="submit"
value="Manage Member"
asp-controller="TeamMembers"
asp-action="Select"
asp-route-teamid="@item.TeamID"
asp-route-memberid="@item.TeamMemberID"/>
</td>
@:</tr>
}
</table>
</form>
}
if (Model.SelectedTeamMember != null)
{
if (Model.DataDisplayMode ==
DataDisplayModes.Read)
{
await Html.RenderPartialAsync
("_ShowTeamMember", Model.SelectedTeamMember);
}
if (Model.DataDisplayMode ==
DataDisplayModes.Update)
{
await Html.RenderPartialAsync
("_UpdateTeamMember", Model.SelectedTeamMember);
}
}
if (Model.DataDisplayMode ==
DataDisplayModes.Insert)
{
await Html.RenderPartialAsync
("_InsertTeamMember", new TeamMember()
{ TeamID = Model.SelectedTeam.TeamID });
}
}
}
The _TeamMembers partial renders the detail grid as shown below:

There are two buttons - Insert Member and Manage Member. Clicking on the
Insert Member button submits the form to the InsertEntry() action of
TeamMembersController. TeamID route parameter is also passed to the InsertEntry()
action. Similarly, clicking on the Manage Member button submits the form to the
Select() action of TeamMembersController. TeamID and MemberID route parameters
are passed to the Select() action.
Since this is a detail grid, we iterate through the SelectedTeam.Members
property and display a list of team members in the table. The selection marker
is shows as in the previous case.
Also notice a series of if statements at the bottom. Here, we check the
DataDisplayMode of the SelectedTeam and accordingly render _ShowTeamMember,
_InsertTeamMember, or _UpdateTeamMember partials. These partials are discussed
in the next part of this article series. For example, a team member record is
shown in read-only mode by _ShowTeamMember partial like this:

This completes the _TeamMembers partial. In the next part of this series we
will discuss the partials from Teams and TeamMembers folders.
That's it for now! Keep coding!!