Last updated on April 16th, 2023
Estimated reading time: 8 minutes
In web applications there is often an requirement to display data in modal up. Traditionally modal pop ups are implemented using JavaScript frameworks. In this article you will learn to Custom Modal Pop up component using Blazor Web Assembly and .NET6 using C#.
Note: Basic working knowledge of Blazor web assembly and .NET Core is required for this working demo. If you are new to Blazor read article on creating a fully functional application in Blazor web assembly with Add/Edit/Delete operations.
Output
Modal popup with validation messages would be display as below.
Create custom modal pop up component
Create a new Blazor web assembly project with .NET Core hosted . Select .NET 6 Framework . The basic project structure is as shown below.
- EmployeePortal.Client is Blazor Web assembly Project
- EmployeePortal.Server is .NET6 server Project to host API and Database Repository
- EmployeePoral.Shared is .NET Standard Library Project. Entity models would reside in this project and it would be shared by client and server project
Create a new component folder in our client project and add new Razor component. The detailed structure of client folder is mentioned below.
Add the below code in AddEmployeeDialog.razor
@if (ShowDialog)
{
<div class="modal fade show d-block" id="exampleModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="titleLabel">Add Employee</h5>
<button type="button" class="close" @onclick="@Close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<EditForm Model="@Employee" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="form-group">
<label for="lastName">Last name: </label>
<InputText id="lastName" class="form-control" @bind-Value="@Employee.LastName" placeholder="Enter last name"></InputText>
<ValidationMessage For="@(() => Employee.LastName)" />
</div>
<div class="form-group">
<label for="firstName">First name: </label>
<InputText id="firstName" class="form-control" @bind-Value="@Employee.FirstName" placeholder="Enter first name"></InputText>
<ValidationMessage For="@(() => Employee.FirstName)" />
</div>
<div class="form-group">
<label for="email">Email: </label>
<InputText id="email" class="form-control" @bind-Value="@Employee.Email" placeholder="Enter email"></InputText>
<ValidationMessage For="@(() => Employee.Email)" />
</div>
<button type="submit" class="btn btn-primary">Save employee</button>
<a class="btn btn-outline-primary" @onclick="@Close">Close</a>
</EditForm>
</div>
</div>
</div>
</div>
}
DataAnnotationsValidator
is a built-in validation component in Blazor, which is used to validate user input using data annotations. Data annotations are attributes that are applied to model properties to specify validation rules.
To use the DataAnnotationsValidator
component in Blazor, you need to follow these steps:
Apply data annotations to the model properties that you want to validate. For example, you can apply the Required
attribute to a property to indicate that it cannot be empty. In your Blazor component, add the DataAnnotationsValidator
component. Use the ValidationMessage
component to display validation messages for each property. Validation Summary displays summary of all validation messages
Add the below code in AddEmployeeDialog.cs
- This is component class which would invoke EmployeeDataservice
- Employee Data service would call .NET Core API
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EmployeePortal.Shared;
using EmployeePortal.Client.Services;
using Microsoft.AspNetCore.Components;
namespace EmployeePortal.Client.Components {
public partial class AddEmployeeDialog: ComponentBase {
public Employee Employee {
get;
set;
} = new Employee {};
[Inject]
public IEmployeeDataService EmployeeDataService {
get;
set;
}
public bool ShowDialog {
get;
set;
}
[Parameter]
public EventCallback <bool> CloseEventCallback {
get;
set;
}
public void Show() {
ResetDialog();
ShowDialog = true;
StateHasChanged();
}
public void Close() {
ShowDialog = false;
StateHasChanged();
}
private void ResetDialog() {
Employee = new Employee {};
}
protected async Task HandleValidSubmit() {
await EmployeeDataService.AddEmployee(Employee);
ShowDialog = false;
await CloseEventCallback.InvokeAsync(true);
StateHasChanged();
}
}
}
Based on ShowDialog property pop up would be toggle hide/show.
Implement the service: Implement the service and register it with the dependency injection container. In Blazor, dependency injection is used to manage the lifecycle of services and provide them to components or other services when needed.
- Define the service interface: Create an interface that defines the contract for the service you want to inject.
- Implement the service: Implement the service and register it with the dependency injection container.
- Register the service: In the
Program.cs
file, register the service with the dependency injection container using theservices
collection. - Inject the service: In a component or other service, inject the service using the
@inject
directive.
Employee model
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace EmployeePortal.Shared {
[Table("Employee")]
public partial class Employee {
public int EmployeeId {
get;
set;
}
[Required]
[StringLength(50, ErrorMessage = "First name is too long.")]
public string FirstName {
get;
set;
}
[Required]
[StringLength(50, ErrorMessage = "Last name is too long.")]
public string LastName {
get;
set;
}
[Required]
[EmailAddress]
public string Email {
get;
set;
}
public string Street {
get;
set;
}
public string Zip {
get;
set;
}
public string City {
get;
set;
}
public string PhoneNumber {
get;
set;
}
[StringLength(1000, ErrorMessage = "Comment length can't exceed 1000 characters.")]
public string Comment {
get;
set;
}
}
}
Validate modal data and save using Data service and .NET Core API
Create a new Service Folder and Add new Employee Service
builder.Services.AddHttpClient<IEmployeeDataService, EmployeeDataService>(client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
Data Service would have AddEmployee function as below which would call the .NET Core API
public async Task < Employee > AddEmployee(Employee employee) {
var employeeJson = new StringContent(JsonSerializer.Serialize(employee), Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($ "api/employee", employeeJson);
if (response.IsSuccessStatusCode) {
return await JsonSerializer.DeserializeAsync < Employee > (await response.Content.ReadAsStreamAsync());
}
return null;
}
In .NET Core Project create a new API controller as below
[Route("api/employee")]
[HttpPost]
public IActionResult CreateEmployee([FromBody] Employee employee) {
if (employee == null) return BadRequest();
if (employee.FirstName == string.Empty || employee.LastName == string.Empty) {
ModelState.AddModelError("Name/FirstName", "The name or first name shouldn't be empty");
}
if (!ModelState.IsValid) return BadRequest(ModelState);
var createdEmployee = _employeeRepository.AddEmployee(employee);
return Created("employee", createdEmployee);
}
Register Repository in Startup.cs
services.AddScoped<IEmployeeRepository, EmployeeRepository>();
Repository to save data in database
public Employee AddEmployee(Employee employee) {
var addedEntity = _appDbContext.Employees.Add(employee);
_appDbContext.SaveChanges();
return addedEntity.Entity;
}
How to use modal custom component on home page
Create a new razor page Employee and import component using this syntax
@page"/"
@using EmployeePortal.Client.Components;
<button@onclick="QuickAddEmployee"class="btn btn-dark table-btn quick-add-btn"> + </button>
<AddEmployeeDialog @ref="AddEmployeeDialog"></AddEmployeeDialog>
@ref
is a built-in directive in Blazor that allows you to create a reference to a component.
Employee Page class file.
Inherit it from component base .StateHasChanged
is a method in Blazor that is used to trigger a re-rendering of a component and its child components. Whenever there is a change in the state of a component that requires the UI to be updated, the StateHasChanged
method needs to be called.
public partial class EmployeePage:ComponentBase
{
public IEnumerable<EmployeePortal.Shared.Employee> Employees { get; set; }
[Inject]
public IEmployeeDataService EmployeeDataService { get; set; }
[Inject]
public ToastService ToastService { get; set; }
public AddEmployeeDialog AddEmployeeDialog { get; set; }
protected async override Task OnInitializedAsync()
{
Employees = (await EmployeeDataService.GetAllEmployees()).ToList();
if (Employees != null)
{
ToastService.ShowToast("Employee data loaded", ToastLevel.Info);
}
}
protected void QuickAddEmployee()
{
AddEmployeeDialog.Show();
}
public async void AddEmployeeDialog_OnDialogClose()
{
Employees = (await EmployeeDataService.GetAllEmployees()).ToList();
StateHasChanged();
}
}
Run the application locally and click on Add Employee. Add new employee modal pop up would be displayed. If user tries to submit blank form validation messages would be display.