Introduction
In this article, let’s see how to create our own ASP.NET Core Blazor Master Detail HTML CRUD (Insert
, Update
, Select
and Delete
) for both Master and Detail Grid with Sorting and Filtering using Entity Framework, and Web API.
Kindly read my previous articles which explain in depth about getting started with ASP.NET Core Blazor.
This article will explain:
- How to Create Order Master and Order Detail table with sample records inserted
- How to create an ASP.NET Core Blazor Web application
- How to install the Package for using Entity Framework and creating DBContext class
- Create a separate WEB API for both Order Master and Order Detail
- How to get result from Web API and bind result in Blazor client Razor view to display our Master/Detail HTML grid
- Add Sorting /Filtering features for Master HTML grid
- Add/Edit/ and Delete each Order Master and Order Detail from grid
Background
Prerequisites
Make sure that you have installed all the prerequisites in your computer. If not, then download and install all, one by one. Note that since Blazor is the new framework and we must have installed preview of Visual Studio 2017 (15.7) or above.
Using the Code
We will create an Order
Master
and Order Detail
table to be used for the Master
and Detail Grid
data binding. The following is the script to create a database, table and sample insert query. Run this script in your SQL Server.
use master
IF EXISTS (SELECT [name] FROM sys.databases WHERE [name] = 'OrderManagement' )
DROP DATABASE OrderManagement
GO
CREATE DATABASE OrderManagement
GO
USE OrderManagement
GO
CREATE TABLE [dbo].[OrderMasters](
[Order_No] INT IDENTITY PRIMARY KEY,
[Table_ID] [varchar](20) NOT NULL,
[Description] [varchar](200) NOT NULL,
[Order_DATE] [datetime] NOT NULL,
[Waiter_Name] [varchar](20) NOT NULL
)
INSERT INTO [OrderMasters]
([Table_ID] ,[Description],[Order_DATE],[Waiter_Name])
VALUES
('T1','Order for Table T1',GETDATE(),'SHANU' )
INSERT INTO [OrderMasters]
([Table_ID] ,[Description],[Order_DATE],[Waiter_Name])
VALUES
('T2','Order for Table T2',GETDATE(),'Afraz' )
INSERT INTO [OrderMasters]
([Table_ID] ,[Description],[Order_DATE],[Waiter_Name])
VALUES
('T3','Order for Table T3',GETDATE(),'Afreen')
CREATE TABLE [dbo].[OrderDetails](
[Order_Detail_No] INT IDENTITY PRIMARY KEY,
[Order_No] INT,
[Item_Name] [varchar](20) NOT NULL,
[Notes] [varchar](200) NOT NULL,
[QTY] INT NOT NULL,
[Price] INT NOT NULL
)
INSERT INTO [OrderDetails]
( [Order_No],[Item_Name],[Notes],[QTY] ,[Price])
VALUES
(1,'Ice Cream','Need very Cold',2 ,160)
INSERT INTO [OrderDetails]
([Order_No],[Item_Name],[Notes],[QTY] ,[Price])
VALUES
(1,'Coffee','Hot and more Suger',1 ,80)
INSERT INTO [OrderDetails]
([Order_No],[Item_Name],[Notes],[QTY] ,[Price])
VALUES
(1,'Burger','Spicy',3 ,140)
INSERT INTO [OrderDetails]
([Order_No],[Item_Name],[Notes],[QTY] ,[Price])
VALUES
(2,'Pizza','More Chees and Large',1 ,350)
INSERT INTO [OrderDetails]
([Order_No],[Item_Name],[Notes],[QTY] ,[Price])
VALUES
(2,'Cola','Need very Cold',3 ,50)
INSERT INTO [OrderDetails]
([Order_No],[Item_Name],[Notes],[QTY] ,[Price])
VALUES
(3,'IDLY','Hot',3 ,40)
INSERT INTO [OrderDetails]
([Order_No],[Item_Name],[Notes],[QTY] ,[Price])
VALUES
(3,'Thosa','Hot',3 ,50)
Select * FROM OrderMasters
Select * From OrderDetails
Step 2 - Create ASP.NET Core Blazor Application
After installing all the prerequisites listed above and ASP.NET Core Blazor Language Services, click Start >> Programs >> Visual Studio 2017 >> Visual Studio 2017 on your desktop. Click New >> Project. Select Web >> ASP.NET Core Angular Web Application. Enter your project name and click OK.
Select Blazor (ASP.NET Core hosted) and click ok.
After creating ASP.NET Core Blazor Application, wait for few seconds. You will see the below structure in solution explorer.
What is New in ASP.NET Core Blazor Solution?
When we create our new ASP.NET Core Blazor application, we can see as there will be 3 projects that will be automatically created in the solution Explorer.
Client Project
The first project created is the Client project and it will be as our Solutionname.Client
and here, we can see our Solutionname
as “BlazorASPCORE
”. As the project named as client and this project will be mainly focused for all the client-side view. Here, we will be adding all our page view to be displayed in the client side in browser.
We can see a few sample pages have been already added here and we can also see a shared folder which is the same as our MVC application where will be having the Sharedfolder
and Layout
page for the Master
page. Here in Blazor, we have the MainLayout
which will work like the Master
page and NavMenu
for the left side menu display.
Server Project
As the name indicates, this project will be used as a Server project. This project is mainly used to create all our Controllers and WEB API Controllers to perform all business logic and perform CRUD operation using WEB APIs. In our demo application, we will be adding a Web API in this Server project and all the WEB API in our Client application. This Server project will work like get
/set
the data from database and from our Client
project, we bind or send the result to this server to perform the CRUD operation in database.
Shared Project
As the name indicates, this project works like a shared project. This project works as a Model for our Server project and for the Client project. The Model declared in this Shared project will be used in both the Server and in the Client project. We also install all the packages needed for our project here, for example to use the Entity Framework, we install all the packages in this Shared project.
Run to Test the Application
When we run the application, we can see that the left side has navigation and the right side contains the data. We can see as the default sample pages and menus will be displayed in our Blazor web site. We can use the pages or remove it and start with our own page.
Now let’s see how to add new page perform the CRUD operation for maintain Order
details.
Using Entity Framework
To use the Entity Framework in our Blazor application, we need to install the below packages.
Install the Packages
Go to Tools and then select -> NuGet Package Manager -> Package Manager Console.
You can see the Console at the bottom of the VS 2017 IDE and at the right side of the combobox on the console, select the Default project as your shared project ”Select Shared”.
- You can see the PM> and copy and paste the below line to install the Database Provider package. This package is used to set the database provider as SQL Server.
Install-Package Microsoft.EntityFrameworkCore.SqlServer
We can see as the package is installed in our Shared folder.
Install the Entity Framework.
You can see the PM> and copy and paste the below line to install the EF package.
Install-Package Microsoft.EntityFrameworkCore.Tools
To create DB Context and set the DB Connection string:
You can see the PM> and copy and paste the below line set the Connection string and create DB Context. This is an important part as we give our SQL Server name, Database Name and SQL server UID and SQL Server Password to connect to our database to display our Master/Detail Grid. We also give our both SQL Table name “OrderMasters
, OrderDetails
” to create the Model
class in our Shared project.
Scaffold-DbContext "Server= SQLServerName;Database=OrderManagement;
user id=SQLID;password=SQLPWD;Trusted_Connection=True;MultipleActiveResultSets=true"
Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables OrderMasters ,OrderDetails
Press enter create connection string, Model Class and Database Context.
We can see OrderMasters
and OrderDetails Model
class and OrderManagementContext
class has been created in our Shared project. We will be using this Model
and DBContext
in our Server project to create our Web API to perform the CRUD operations.
Creating Web API for Get Order Details
To create our WEB API Controller, right click Controllers folder. Click Add New Controller.
Here, we will be using Scaffold
method to create our WEB API. We select API Controller with actions, using Entity Framework.
Select our Model
and DatabaseContext
from the Shared project.
Select our OrderMasters
Model from the Shared Project for performing the CRUD operation.
Select the Data Context Class as our OrderManagementContext
from the Shared project. Our Controller
name will be automatically added if you need, you can change it and click the ADD.
We will be using all the Get
/Post
/Put
and Delete
methods from our Web API.
Same like this, we also create a Web API for our OrderDetails
.
To test Get
method, we can run our project and copy the GET
method API path. Here, we can see our API path to get api/OrderMasters/.
Run the program and paste API path to test our output.
For OrderDetails
, we can pass the Order No
to get only one Order
details. Here, we can see the result for Order No
as “1
” ,we call the Web API as /api/OrderDetails/1.
Now we will bind all this WEB API Json result in our Razor View page from our Client
project for displaying the Master
/Detail
HTML table for performing CRUD operations and also with Filtering and Sorting options.
Working with Client Project
Note: In this article, we will create 2 Razor pages. In one Razor page, we will create the Master Details
HTML table with normal binding method and in another Razor page, we bind the Detail
table using Blazor Dynamic Content.
Razor Page with Normal Binding
First, we need to add the new Razor view page.
Add Razor View
To add the Razor view page, right click the Pages folder from the Client
project. Click on Add >> New Item
Select Razor View >> Enter your page name. Here, we have given the name as Orders.cshtml.
In Razor view Page, we have 3 parts of code as first is the Import part where we import all the references and models for using in the view, HTML design and data bind part and finally, we have the function part to call all the web API to bind in our HTML page and also to perform client-side business logic to be displayed in View page.
Import Part
First, we import all the needed support files and references in our Razor View page. Here, we have first imported our Model
class to be used in our view and also imported HTTPClient
for calling the Web API to perform the CRUD operations.
@using MasterDetailCRUD.Shared
@using MasterDetailCRUD.Shared.Models
@page "/Orders"
@using Microsoft.AspNetCore.Blazor.Browser.Interop
@using System.Collections.Generic
@using Microsoft.AspNetCore.Blazor
Master HTML Grid Data Bind Part
Next, we design our Order
page to bind the Order Master
and Order Detail
results from the Web API to HTML table.
Binding Order Master Details
In the Init
method, we get the Order Master
from Web API and bind the result in HTML table using foreach
loop. Here, we bind the result for Order Master
Grid and in each row first column, we add the Toggle image and, in this Toggle image click event, we call the getOrderDetails(OrderNo)
method to display the Detail
HTML grid for the related Order
. We pass the Order No
to the function and we get the related Order details
for the Order
and bind the result in detail grid
. Also, we will show the detail grid
only when the toggle image button is clicked and if the toggle button clicked again, we hide the detail grid
. We also have Edit and Delete buttons to edit and delete the Order Master
record from database.
@foreach (var OrderMasterobj in ordMaster)
{
<tr style="border-style:dashed;border-width:2px;border-color:
@(OrderMasterobj.OrderNo == orderIDs ? "#ff6a00": "#a2aabe")">
<td align="center" style="border:
solid 1px #659EC7; padding: 5px;table-layout:fixed;">
@if (@OrderMasterobj.OrderNo == orderIDs)
{
<img src="@Imagename" onclick="@(async () =>
await getOrderDetails(@OrderMasterobj.OrderNo))" />
}
else
{
<img src="Images/toggle.png" onclick="@(async () =>
await getOrderDetails(@OrderMasterobj.OrderNo))" />
}
</td>
<td align="center" style="border: solid 1px #659EC7;
padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
<img src="Images/edit.gif" alt="Edit"
width="24px" height="24px" onclick="@(async () =>
await EditOrderMaster(@OrderMasterobj.OrderNo))" />
</span>
</td>
<td align="center" style="border: solid 1px #659EC7;
padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
<img src="Images/delete.gif" alt="Delete"
width="24px" height="24px" onclick="@(async () =>
await DeleteOrderMaster(@OrderMasterobj.OrderNo))" />
</span>
</td>
<td align="left" style="border: solid 1px #659EC7;
padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
@OrderMasterobj.OrderNo
</span>
</td>
<td align="left" style="border: solid 1px #659EC7;
padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
@OrderMasterobj.TableId
</span>
</td>
<td align="left" style="border: solid 1px #659EC7;
padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
@OrderMasterobj.Description
</span>
</td>
<td align="left" style="border: solid 1px #659EC7;
padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
@OrderMasterobj.OrderDate
</span>
</td>
<td align="left" style="border: solid 1px #659EC7;
padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
@OrderMasterobj.WaiterName
</span>
</td>
</tr>
Function Part
Function part to call all the web API to bind in our HTML page and also to perform client-side business logic to be displayed in View page.
Init Method
In the Init
method, we get the result of Web API for Order Master
and store it in the ordMaster
object and we are using this object to be bind in our HTML table using the foreach
statement.
@functions {
OrderMasters[] ordMaster;
OrderDetails[] ordDetail;
OrderMasters ordsM = new OrderMasters();
OrderDetails ordsD = new OrderDetails();
Boolean showAddMaster = false;
Boolean showAddDetail = false;
int showDetailStatus = 0;
int sortStatus = 0;
int orderIDs = 0;
string Imagename = "Images/toggle.png";
string ImageSortname = "Images/sortAsc.png";
string Messages = "";
protected override async Task OnInitAsync()
{
ordMaster = await Http.GetJsonAsync<OrderMasters[]>("/api/OrderMasters/");
ordsD = new OrderDetails();
ordsM = new OrderMasters();
Messages = "";
}
Adding Sorting Features in Table Heading
Here, we have added the Sorting and Filtering features only for the Master HTML table. If needed, then we can implement this same feature for Detail grid as well.
In the Master Table heading part for each heading, we add the Sorting Image. In Sorting Image Button Click event, we call the Sorting
function and pass each Sorting Column name to the click event. In Function code part, we sort the Web API and display the result by ascending and in descending order by each column header sorting image click.
<table style=" background-color:#FFFFFF; border: solid 2px #6D7B8D;
padding: 5px;width: 99%;table-layout:fixed;" cellpadding="2" cellspacing="2">
<tr style="height: 30px; background-color:#336699 ; color:#FFFFFF ;border: solid 1px #659EC7;">
<td width="120"></td>
<td width="40" align="center"><b>Edit</b></td>
<td width="40" align="center"><b>Delete</b></td>
<td width="120" align="center" style="cursor: pointer;">
<b>OrderNo</b>
<img src="@ImageSortname" onclick="@(async () =>
await OrderMasterSorting("OrderNo"))" height="24" width="24" />
</td>
<td width="240" align="center" style="cursor: pointer;">
<b>Table Name</b>
<img src="@ImageSortname" onclick="@(async () =>
await OrderMasterSorting("TableId"))" height="24" width="24" />
</td>
<td width="240" align="center" style="cursor: pointer;">
<b>Description</b>
<img src="@ImageSortname" onclick="@(async () =>
await OrderMasterSorting("Description"))" height="24" width="24" />
</td>
<td width="120" align="center" style="cursor: pointer;">
<b> Order Date</b>
<img src="@ImageSortname" onclick="@(async () =>
await OrderMasterSorting("OrderDate"))" height="24" width="24" />
</td>
<td width="340" align="center" style="cursor: pointer;">
<b> Waiter Name</b>
<img src="@ImageSortname" onclick="@(async () =>
await OrderMasterSorting("WaiterName"))" height="24" width="24" />
</td>
</tr>
Sorting Method
In Sorting image click on each column heading, we call this method and pass the column name to this method. In this method depending on column name, we do Sorting the Web API result and bind the result in the HTML table. We also do the vice versa sorting of Ascending and descending.
protected async Task OrderMasterSorting(string SortColumn)
{
ordMaster = await Http.GetJsonAsync<OrderMasters[]>("/api/OrderMasters/");
Messages = "";
if (sortStatus == 1)
{
ImageSortname = "Images/sortDec.png";
sortStatus = 0;
switch (SortColumn)
{
case "OrderNo":
ordMaster = ordMaster.OrderBy(x => x.OrderNo).ToArray();
break;
case "TableId":
ordMaster = ordMaster.OrderBy(x => x.TableId).ToArray();
break;
case "Description":
ordMaster = ordMaster.OrderBy(x => x.Description).ToArray();
break;
case "OrderDate":
ordMaster = ordMaster.OrderBy(x => x.OrderDate).ToArray();
break;
case "WaiterName":
ordMaster = ordMaster.OrderBy(x => x.WaiterName).ToArray();
break;
}
}
else
{
ImageSortname = "Images/sortAsc.png";
sortStatus = 1;
switch (SortColumn)
{
case "OrderNo":
ordMaster = ordMaster.OrderByDescending(x => x.OrderNo).ToArray();
break;
case "TableId":
ordMaster = ordMaster.OrderByDescending(x => x.TableId).ToArray();
break;
case "Description":
ordMaster = ordMaster.OrderByDescending(x => x.Description).ToArray();
break;
case "OrderDate":
ordMaster = ordMaster.OrderByDescending(x => x.OrderDate).ToArray();
break;
case "WaiterName":
ordMaster = ordMaster.OrderByDescending(x => x.WaiterName).ToArray();
break;
}
}
}
Adding Filtering Features in Table Heading
In the Table heading part, we add a new row. In table row, we add the Textbox
for each column to perform the filtering for the binded result. In Textbox onChange
event, we call the method to perform the Filtering operation from the code function part.
<tr style="height: 30px; background-color:#336699 ; color:#FFFFFF ;">
<td width="140" align="center" colspan="4">
<img src="Images/filter.png" width="24" height="24" /> Filter By
</td>
<td width="180" align="center" style="border:
solid 1px #FFFFFF; padding: 5px;table-layout:fixed;">
<input width="70"
onchange=@OnTableIdChanged oninput="
(this.dispatchEvent(new CustomEvent('change', {bubbles: true})))" />
</td>
<td width="180" align="center" style="border:
solid 1px #FFFFFF; padding: 5px;table-layout:fixed;">
<input width="70" onchange=@OnDescriptionChanged
oninput="(this.dispatchEvent(new CustomEvent('change', {bubbles: true})))" />
</td>
<td width="180" align="center"
style="border: solid 1px #FFFFFF; padding: 5px;table-layout:fixed;"></td>
<td width="180" align="center"
style="border: solid 1px #FFFFFF; padding: 5px;table-layout:fixed;">
<input width="70"
onchange=@OnWaiterNameChanged oninput="
(this.dispatchEvent(new CustomEvent('change', {bubbles: true})))" />
</td>
</tr>
Filtering Method
In each column heading part, we have added a new row for performing the Filtering of the HTML grid. In each column filter Textbox Change event, we pass the Textbox
value. We call a common filtering method OrderMasterFilteringList
and in this method, we pass the filtering column Textbox
value and column Name.
void OnOrderNoChanged(UIChangeEventArgs args)
{
string values = args.Value.ToString();
OrderMasterFilteringList(values, "OrderNo");
}
void OnTableIdChanged(UIChangeEventArgs args)
{
string values = args.Value.ToString();
OrderMasterFilteringList(values, "TableId");
}
void OnDescriptionChanged(UIChangeEventArgs args)
{
string values = args.Value.ToString();
OrderMasterFilteringList(values, "Description");
}
void OnOrderDateChanged(UIChangeEventArgs args)
{
string values = args.Value.ToString();
OrderMasterFilteringList(values, "OrderDate");
}
void OnWaiterNameChanged(UIChangeEventArgs args)
{
string values = args.Value.ToString();
OrderMasterFilteringList(values, "WaiterName");
}
Here, we create a common function named as OrderMasterFilteringList
and in this method, we get the filtering column Textbox
value and column Name. We do filtering from the Web API and bind the filtering result to the HTML Table.
protected async Task OrderMasterFilteringList(String Value, string columnName)
{
ordMaster = await Http.GetJsonAsync<OrderMasters[]>("/api/OrderMasters/");
Messages = "";
if (Value.Trim().Length > 0)
{
switch (columnName)
{
case "TableId":
ordMaster = ordMaster.Where(x => x.TableId.Contains(Value)).ToArray();
break;
case "Description":
ordMaster = ordMaster.Where(x => x.Description.Contains(Value)).ToArray();
break;
case "WaiterName":
ordMaster = ordMaster.Where(x => x.WaiterName.Contains(Value)).ToArray();
break;
}
}
else
{
ordMaster = await Http.GetJsonAsync<OrderMasters[]>("/api/OrderMasters/");
}
}
Insert New Order Master
In the ADD New Order Master
button click, we will make visible the New Order Master Add
table, where the user can enter the new Order
information.
<table width="100%" style="background:#05163D;color:honeydew">
<tr>
<td width="20"> </td>
<td>
<h2> Add New Order Master Information</h2>
</td>
<td> </td>
<td align="right">
<button class="btn btn-info"
onclick="@AddNewOrderMasters">Add New Order</button>
</td>
<td width="10"> </td>
</tr>
<tr>
<td colspan="2"></td>
</tr>
</table>
For a new Order Master
, we will make the OrderNo
as 0
. In the New Order Master save button click, we will call the save method.
When Add New Order button is clicked, we show the Add/Edit Order Master, here user can update or add new Order Master.
@if (showAddMaster == true)
{
<table style=" background-color:#FFFFFF; border: dashed 3px #6D7B8D;
padding: 5px;width: 99%;table-layout:fixed;" cellpadding="2" cellspacing="2">
<tr style="height: 30px; background-color:#336699 ;
color:#FFFFFF ;border: solid 1px #659EC7;">
<td>
<h3> Add/Edit Order Master</h3>
</td>
</tr>
<tr>
<td>
<table class="form-group">
<tr>
<td>
<label for="Name"
class="control-label">Order No</label>
</td>
<td>
<input type="text"
class="form-control" bind="@ordsM.OrderNo" readonly />
</td>
<td width="20"> </td>
<td>
<label for="Name"
class="control-label">Table Name</label>
</td>
<td>
<input type="text"
class="form-control" bind="@ordsM.TableId" />
</td>
</tr>
<tr>
<td>
<label for="Email"
class="control-label">Description</label>
</td>
<td>
<input type="text" class="form-control"
bind="@ordsM.Description" />
</td>
<td width="20"> </td>
<td>
<label for="Name" class="control-label">Date</label>
</td>
<td>
<input type="text" class="form-control"
bind="@ordsM.OrderDate" />
</td>
</tr>
<tr>
<td>
<label for="Name" class="control-label">Waiter Name</label>
</td>
<td>
<input type="text" class="form-control"
bind="@ordsM.WaiterName" />
</td>
<td width="20"> </td>
<td></td>
<td>
<button type="submit" class="btn btn-success"
onclick="@(async () => await SaveOrderMasters())"
style="width:220px;">Save</button>
</td>
</tr>
</table>
</td>
</tr>
</table>
Save Method
In the Save method, we will check for the OrderNo
. If the OrderNo
is “0
”, then it will insert the new Order Master
. Here, we will call the Insert Web API method and if the OrderNo
is > 0
, then it means to update the Order
record.
protected async Task SaveOrderDetails()
{
if (ordsD.OrderDetailNo == 0)
{
await Http.SendJsonAsync(HttpMethod.Post, "/api/OrderDetails/", ordsD);
}
else
{
await Http.SendJsonAsync(HttpMethod.Put, "/api/OrderDetails/" + ordsD.OrderDetailNo, ordsD);
}
ordDetail = await Http.GetJsonAsync<OrderDetails[]>
("/api/OrderDetails/" + Convert.ToInt32(ordsD.OrderNo));
ordsD = new OrderDetails();
showAddDetail = false;
showAddMaster = false;
Messages = "Order Detail Saved to Database !";
}
Update Order Master
The same as Insert
, we will display the update details for the user to edit the Order Master
and save it. In the Edit
method, we will get all the details for the row where the user clicks on the Edit Icon and sets all the results to the appropriate TextBox
. In the Save button click, we will call the save method to save all the changes to the database like Insert
.
protected async Task EditOrderMaster(int OrderNos)
{
showAddMaster = true;
ordsM = await Http.GetJsonAsync<OrderMasters>("/api/OrderMasters/" +
Convert.ToInt32(OrderNos));
}
Delete Order Master Details
In the Delete button click, we will delete the Order
by passing the OrderNo
to the delete
method of the Web API to delete the record from the database.
protected async Task DeleteOrderMaster(int OrderNos)
{
await Http.DeleteAsync("/api/OrderMasters/" + Convert.ToInt32(OrderNos));
ordMaster = await Http.GetJsonAsync<OrderMasters[]>("/api/OrderMasters/");
Messages = "Order Master Deleted from Database !";
}
Detail Grid
Bind the Detail Grid Result
Firstly, we check the OrderDetail
result is null
, if it’s not null
then we bind the result in HTML Table, before binding the result, we also check for the showDetailStatus ==1
which means to show or hide the Detail
Grid. By default, we set the showDetailStatus
as 0
and in Master grid Toggle image click event, we change the status to 1
and if the showDetailStatus
is 1
then we display the Detail
grid, we also check the Master grid OrderNo
with Order
detail and bind the result in Detail
Grid.
@if (ordDetail != null)
{
@if (showDetailStatus == 1)
{
@if (@OrderMasterobj.OrderNo == orderIDs)
{
<tr style="background-color:#6D7B8D ;
color:honeydew ;
border-style:dashed;border-width:2px;
border-color:#ECF3F4;">
<td colspan="8"
align="center">
Order Details of
Order NO - <strong> @OrderMasterobj.OrderNo
</strong> ,
Total @ordDetail.Length details for this Order
</td>
</tr>
<tr>
<td valign="top">
<button class="btn btn-info"
onclick="@(async () =>
await AddNewOrderDetails
(@OrderMasterobj.OrderNo))">Add New Detail</button>
</td>
<td colspan="7">
<table style="background-color:#ECF3F4; border: solid 2px #3273d5;
padding: 5px;width: 99%;table-layout:fixed;">
<tr style="height: 30px; background-color:#336699 ;
color:#FFFFFF ;">
<td width="40"
align="center"><b>Edit</b></td>
<td width="40"
align="center"><b>Delete</b></td>
<td width="240"
align="center">
<b> Order Number</b>
</td>
<td width="240" align="center">
<b> Order Detail Number</b>
</td>
<td width="120" align="center">
<b> Item Name</b>
</td>
<td width="340" align="center">
<b>Comments</b>
</td>
<td width="120" align="center">
<b> QTY</b>
</td>
<td width="120" align="center">
<b> Price</b>
</td>
</tr>
@foreach (var orderDetailsObj in ordDetail)
{
<tr>
<td align="center" style="border:
solid 1px #659EC7; padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
<img src="Images/edit.gif" alt="Edit"
width="24px" height="24px"
onclick="@(async () =>
await EditOrderDetails(@orderDetailsObj.OrderDetailNo))" />
</span>
</td>
<td align="center" style="border:
solid 1px #659EC7; padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
<img src="Images/delete.gif" alt="Delete"
width="24px" height="24px"
onclick="@(async () =>
await DeleteOrderDetails
(@orderDetailsObj.OrderDetailNo))" />
</span>
</td>
<td align="center" style="border:
solid 1px #659EC7; padding: 5px;table-layout:fixed;">
@orderDetailsObj.OrderNo
</td>
<td align="center" style="border:
solid 1px #659EC7; padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
@orderDetailsObj.OrderDetailNo
</span>
</td>
<td align="center" style="border:
solid 1px #659EC7; padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
@orderDetailsObj.ItemName
</span>
</td>
<td align="center" style="border:
solid 1px #659EC7; padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
@orderDetailsObj.Notes
</span>
</td>
<td align="right" style="border:
solid 1px #659EC7; padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
@orderDetailsObj.Qty
</span>
</td>
<td align="right" style="border:
solid 1px #659EC7; padding: 5px;table-layout:fixed;">
<span style="color:#9F000F">
@orderDetailsObj.Price
</span>
</td>
</tr>
}
</table>
</td>
</tr>
}
}
}
Detail Grid bind, Hide/Show method
In the Master grid Toggle image click event, we call this below method and pass the Order NO
to get the appropriate Order
details from the Web API and bind the result in the detail HTML grid.
protected async Task getOrderDetails(int ordID)
{
showAddMaster = false;
showAddDetail = false;
Messages = "";
if (orderIDs != ordID)
{
Imagename = "Images/expand.png";
showDetailStatus = 1;
}
else
{
if (showDetailStatus == 0)
{
Imagename = "Images/expand.png";
showDetailStatus = 1;
}
else
{
Imagename = "Images/toggle.png";
showDetailStatus = 0;
}
}
orderIDs = ordID;
ordDetail = await Http.GetJsonAsync<OrderDetails[]>
("/api/OrderDetails/" + Convert.ToInt32(ordID));
}
Order Detail Add/Edit and Delete
Same like the Order Master
CRUD, we also do Insert/Edit and Delete for the Order Details
. Here, from below gif image, we can see the Detail
grid bind, Insert
, Update
and Delete
operations.
Navigation Menu
Now we need to add this newly added Orders Razor page to our left Navigation. For adding this, open the Shared Folder and open the NavMenu.cshtml page and add the menu.
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match=NavLinkMatch.All>
<span class="oi oi-home"
aria-hidden="true"></span> Home
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="Orders">
<span class="oi oi-plus"
aria-hidden="true"></span> Orders Master Detail
</NavLink>
</li>
Build and Run the Application
Points of Interest
In this article, we have added only one level of Hierarchy of grid, you can extend this to create multilevel Hierarchy of HTML grid. Note as when creating the DBContext
and setting the connection string, don’t forget to add your SQL connection string. Hope you all like this article and in the next article, we will see more examples to work with Blazor and it's really very cool and awesome to work with Blazor.
History
- 2018-07-09: MasterDetailCRUD.zip