Passing Data Across Blazor Components

 In this article we will explore a mechanism of passing data across Blazor Components

In the previous article we have seen the Blazor Server App for performing CRUD operations using EntityFrameworkCore with .NET 5. The Blazor Server Apps runs on the server and based on the UI event the component on the server is executed and the DOM updates are serialized back on the browser. We can create a Blazor Client App which runs on the browser on .NET WebAssembly. The Blazor is a feature of the ASP.NET Core for creating interactive web applications. So we can look it  as one the possible alternative for Angular, React or Vue.js etc. 

Blazor components are autonomous, this means that it contains UI, Data (aka state), Events and Logic. These components are re-usable and we can use one component as a child of the other component. But in this situation, there might be a scenario that parent component want to pass data to child components and child component want to pass data to its parent. In this article, we will go through step by step implementation of the data communication across components.

The figure 1 explains the data component communication across components



Figure 1: Data Communication across Components 

The figure 1 shows that the Parent Component uses the Child Component. The Child Component defines public property decorated with the [Parameter] attribute. This makes sure that the Parent Component can pass data to the property decorated with [Parameter]  to the Child Component. The child component can emit data to parent component using the EventCallback property. This event has to be subscribed by the parent component so that data emitted by the child component can be subscribed by the parent component.              

To implement the application we need Visual Studio 2019 with .NET Core 3.1 SDK or .NET 5 SDK. (Please note: I have implemented this article using Visual Studio 2019 on Mac)

Step 1: Open Visual Studio 2019 and create a new Blazor WebAssembly project. Name this project as Blazor_ComponentCommunication. Make sure that  do not select ASP.NET Core Hosted options, this will generate ASP.NET Core API project and we do not need it for the current application. 

Step 2: The project contains Pages folder where we can add all components. The Shared folder contains the MainLayout, NavMenu and SurveyPrompt components. The NavMenu components contains markup which uses NavLink for routing across components. 

Step 3: In the project add a new folder and name it as Models. In this folder add a new class and name this class Employee.cs. In this class file we will add the code for Employee class as shown in the Listing 1

public class Employee

{

        public int EmpNo { get; set; }

        public string EmpName { get; set; }

        public string Designation { get; set; }

        public int Salary { get; set; }

        public string DeptName { get; set; }

    }

Listing 1: The Employee class

In the Models folder add a new class file and name it as Employees.cs. In this file we will add code for Employees class which is derived from List<Employee> and we will hardcode Employees data as shown in listing 2. (Please note that for the sake of simplicity I am not using REST API calls)

public class Employees : List<Employee>

    {

        public Employees()

        {

            Add(new Employee() {EmpNo=101, EmpName="Mahesh", Designation="Manager", Salary=72000, DeptName="SALES"  });

            Add(new Employee() { EmpNo = 102, EmpName = "Vikram", Designation = "Architect", Salary = 92000, DeptName = "IT" });

        }

    }

Listing 2: The Employees class 

Step 4: In the Pages folder add a new Razor component by right-clicking on the Pages folder as shown in the figure 2



Figure 2: Adding new Razor component   

Name this component as EmployeeDetails.razor. In this component add the code as shown in listing 3

@using Blazor_ComponentCommunication.Models

<div class="container">

         <table class="table table-striped table-bordered">

             <thead>

                 <tr>

                     <th>

                         EmpNo

                     </th>

                     <th>

                         EmpName

                     </th>

                     <th>

                         Designation

                     </th>

                     <th>

                         Salary

                     </th>

                     <th>

                         DeptName

                     </th>

                 </tr>

             </thead>  

             <tbody>

                 <tr>

                     <td>@employee.EmpNo</td>

                     <td>@employee.EmpName</td>

                     <td>@employee.Designation</td>

                     <td>@employee.Salary</td>

                     <td>@employee.DeptName</td>

                 </tr>

             </tbody>

             <tfoot>

                 <tr>

                     <td colspan="5">

                         <input type="button" value="Select"

                                @onclick="@SelectEmployee"/>

                     </td>

                 </tr>

             </tfoot>

         </table>

</div>

@code {

    [Parameter] public Employee employee { get; set; }

    [Parameter] public EventCallback<int> OnEmployeeSelected { get; set; }

    protected override void OnInitialized()

    {

        base.OnInitialized();

    }

    async void SelectEmployee()

    {

        await OnEmployeeSelected.InvokeAsync(employee.EmpNo);

    }

}


Listing 3: The EmployeeDetails component

The above component contains public property employee of the type Employee. This property is decorated with Parameter attribute. The Parameter attribute represent the employee property, as component parameter so that this property can be used to accept the data from its parent component. The EmpoyeeDetails component also defines OnEmployeeSelected property of the type EventCallBack<int>. This represent the bound event handler delegate to define an event callback which must be subscribed by the parent component. This callback is used to emit data from the child component to its parent, when an event is raised on the child component. The OnEmployeeSelected callback is applied with parameter attribute. The SelecteEmployee() asynchronous method is used to invoke the delegate associated with event binding to dispatch event from the child component to the parent component. The EmployeeDetails component renders the HTML table that generates row to show data from employee object. 

Step 5: In the Pages folder add a new Razor Component and name it as EmployeeComponent.razor. IN this file add the code as shown in listing 4

@page "/employeecomponent"

@using Blazor_ComponentCommunication.Models

<h3>Employee Component</h3>

<EditForm Model="@employee" OnValidSubmit="@save">

    <div class="container">

        <div class="form-group">

            <label>Employee No.</label>

            <InputNumber @bind-Value="@employee.EmpNo" class="form-control"></InputNumber>

        </div>

        <div class="form-group">

            <label>Employee Name</label>

            <InputText @bind-Value="@employee.EmpName" class="form-control"></InputText>

        </div>

        <div class="form-group">

            <label>Designation</label>

            <InputSelect @bind-Value="@employee.Designation" class="form-control">

                @foreach (var item in designations)

                {

                    <option value="@item">@item</option>

                }

            </InputSelect>

        </div>

        <div class="form-group">

            <label>Salary</label>

            <InputNumber @bind-Value="@employee.Salary" class="form-control"></InputNumber>

        </div>

        <div class="form-group">

            <label>Department</label>

            <InputSelect @bind-Value="@employee.DeptName" class="form-control">

                @foreach (var item in departments)

                {

                    <option value="@item">@item</option>

                }

            </InputSelect>

        </div>

        <div class="form-group">

            <input type="button" value="Clear" class="btn btn-warning" @onclick="@clear"/>

            <input type="button" value="Save" class="btn btn-success" @onclick="@save"/>

        </div>

    </div>

</EditForm>

 <hr/>

@foreach (var emp in employees)

{

    <EmployeeDetails  employee="emp"

                      OnEmployeeSelected="@receiveEmployee"></EmployeeDetails>

}

@code {

    private Employee employee;

    private Employees employees;

    List<string> designations = new List<string>()

    {

        "Manager", "Director", "Engineer", "Architect"

    };

    List<string> departments = new List<string>()

    {

        "IT", "HRD", "SALES"

    };


    protected override void OnInitialized()

    {

        employee = new Employee();

        employees = new Employees();

        base.OnInitialized();

    }

    void clear()

    {

        employee = new Employee();

    }

    void save()

    {

        employees.Add(employee);

    }

    void receiveEmployee(int id)

    {

        employee = employees.Where(e => e.EmpNo == id).FirstOrDefault();

    }

}


Listing 5: The EmployeeComponent code  

The code of listing 5 defines employee and employees properties. The employee property will be bound to the InputText, InputNumber, InputSelect components to accept data from end-user for the Employee properties.  This component contains List properties for designations and departments. These lists will be used to generate options for the InputSelect element for showing list of Departments and Designations. The OnInitialized() method defines an instance of employee and employees object. The clear() method re-initializes the employee object. The clear() method is bound with the Clear button. The save() method add a new employee object in the employees list, this method is bound with the Save button. The receiveEmployee() will select the employee from employees list based on EmpNo. The HTML markup of this component uses the EmployeeDetails component as child component . This component is rendered in the foreach loop to show employee from employees list. Each employee is passed to the employee parameter attribute property of the EmployeeDetails component. The OnEmployeeSelected event callback is bound with the receiveEmployee() method. This binding will receive the employee data fro the EmployeeDetails child component to the EmployeeComponent which is a parent component. This is how the Parent component pass data to child component.

Step 6: Modify the NavMenu.razor file from the Shared folder to define routing for employeecomponent as shown in listing  6

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">

    <ul class="nav flex-column">        

        <li class="nav-item px-3">

            <NavLink class="nav-link" href="employeecomponent">

                <span class="oi oi-list-rich" aria-hidden="true"></span> Employees

            </NavLink>

        </li>

    </ul>

</div>


Listing 6: The Routing for the employeecomponent 


Run the application and click on the Employees routing link this will render the EmployeeComponent and EmployeeDetails component will be rendered as shown in figure 3





Figure 3: The Parent child component rendering    

Add Employee details in text boxes and select DeptName and Designation from select element. Click on the Save button, the new employee will be created and it will be shown in the EmployeeDetails component as shown in figure 4



Figure 4: Adding new Employee            

The new Employee record with EmpNo as 103 is passed from the EmployeeComponent to EmployeeDetails component. Click on the Clear button to clear all Text elements. Click on the Select button of the EmployeeDetails, the selected employee record will be displayed in EmployeeComponent in TextBoxes.  The Select button emits the employee data using EmpNo so that the selected Employee data will be displayed in the TextBoxes.  That's how the child component sends data to parent component.  

As per the needs the child component can have multiple parameters to accept data from  parent component and can have multiple event callback to emit data to parent component.  


The code for this article is available on this link.

Conclusion: The parent-child relationship of the Blazor application helps to build the compositional UI with an easy mechanism to pass data across them.  


   

  

Comments

Popular posts from this blog

Understanding Token Based Authentication in ASP.NET Core 3.1 using JSON WEB TOKENS

Using Model Binders in ASP.NET Core

Using Session State in ASP.NET Core