ASP.NET Core 5.0 : MVC, Razor Pages, Web API, EF Core, Blazor, Design Patterns, and more. Private online coaching for software developers. Click here for more details.

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!!


Bipin Joshi is an independent software consultant, trainer, author, yoga mentor, and meditation teacher. He has been programming, meditating, and teaching for 24+ years. He conducts instructor-led online training courses in ASP.NET family of technologies for individuals and small groups. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Facebook  Twitter  LinkedIn  YouTube

Posted On : 05 April 2021


Tags : ASP.NET ASP.NET Core SQL Server MVC .NET Framework C# Visual Studio


Subscribe to our newsletter

Get monthly email updates about new articles, tutorials, code samples, and how-tos getting added to our knowledge base.

  

Receive Weekly Updates