Best way to share data between two child components in Blazor
You may define a class service that implements the State pattern and the Notifier pattern to handle the state of your objects, pass state to objects, and notify subscriber objects of changes.
Here's a simplified example of such service, which enables a parent component to communicate with his children.
NotifierService.cs
public class NotifierService
{
private readonly List<string> values = new List<string>();
public IReadOnlyList<string> ValuesList => values;
public NotifierService()
{
}
public async Task AddTolist(string value)
{
values.Add(value);
await Notify?.Invoke();
}
public event Func<Task> Notify;
}
Child1.razor
@inject NotifierService Notifier
@implements IDisposable
<div>User puts in something</div>
<input type="text" @bind="@value" />
<button @onclick="@AddValue">Add value</button>
@foreach (var value in Notifier.ValuesList)
{
<p>@value</p>
}
@code {
private string value { get; set; }
public async Task AddValue()
{
await Notifier.AddTolist(value);
}
public async Task OnNotify()
{
await InvokeAsync(() =>
{
StateHasChanged();
});
}
protected override void OnInitialized()
{
Notifier.Notify += OnNotify;
}
public void Dispose()
{
Notifier.Notify -= OnNotify;
}
}
Child2.razor
@inject NotifierService Notifier
<div>Displays Value from service and lets user put in new value</div>
<input type="text" @bind="@value" />
<button @onclick="@AddValue">Set Value</button>
@code {
private string value { get; set; }
public async Task AddValue()
{
await Notifier.AddTolist(value);
}
}
Usage
@page "/"
<p>
<Child1></Child1>
</p>
<p></p>
<p>
<Child2></Child2>
</p>
Startup.ConfigureServices
services.AddScoped<NotifierService>();
Hope this helps...
How to communicate between 3 nested components of blazor C# in two-way binding asp.net core (from parent to its grandchild vice versa)
I founded the case and came up with answer in terms of blazor. Refer below example
Child2.razor
@code{//some code}
Child1.razor
//No UI, only methods in code behind
@code{
public void Show()
{
// TODO actual implementation for calling child 2 component
}
}
Parent.razor
<button @onclick="callChildOne">Submit<button/>
@*Add a @ref to the component *@
<Child1 @ref="childObj"></Child1 >
@code {
//Hold the reference to the component
private Child1 childObj;
// Call the public methods of the component
private void callChildOne() => childObj.Show();
}
This is how I mapped relationship with 3 components without any service. I read this example from blog of Blazor here
How do I communicate between two sibling Blazor components?
The best solution, to my mind, is to create a service which implements the state pattern and the notifier pattern. The following code describes how communication between two sibling can be done through an intermediary
NotifierService.cs
public class NotifierService
{
public NotifierService()
{
}
int rnd;
public int RandomNumber
{
get => rnd;
set
{
if (rnd != value)
{
rnd= value;
if (Notify != null)
{
Notify?.Invoke();
}
}
}
}
public event Func<Task> Notify;
}
Add this: services.AddScoped<NotifierService>();
ProvideNumberComponent.razor
@inject NotifierService Notifier
@implements IDisposable
<h3>Provides Number</h3>
<button class="btn btn-primary" @onclick="CalculateNumber">Provide
Number</button>
@code
{
private void CalculateNumber(MouseEventArgs e)
{
Random rnd = new Random();
Int32 nextNumber = rnd.Next();
Notifier.RandomNumber = nextNumber;
}
public async Task OnNotify()
{
await InvokeAsync(() =>
{
StateHasChanged();
});
}
protected override void OnInitialized()
{
Notifier.Notify += OnNotify;
}
public void Dispose()
{
Notifier.Notify -= OnNotify;
}
}
DisplayNumberComponent.cs
@inject NotifierService Notifier
@implements IDisposable
<hr />
<h3>Displays number</h3>
<textarea cols="9" rows="1" readonly style="font-family:monospace;">
@Notifier.RandomNumber
</textarea>
@code {
public async Task OnNotify()
{
await InvokeAsync(() =>
{
StateHasChanged();
});
}
protected override void OnInitialized()
{
Notifier.Notify += OnNotify;
}
public void Dispose()
{
Notifier.Notify -= OnNotify;
}
}
Of course you can inject and use the service in multiple components, as well as adding more features that the service can provide.
Implementing communication by means of event handlers may be problematic, unless it is between a parent and its child...
Hope this works...
Best way to communicate between Siblings components in Blazor Assembly
The desired design should be as follows:
A parent: component named ClientList
which displays a list (selected fields only) of client objects in a tabular
form ( datagrid ).
A child: component named ClientInfo
which displays the client info object in a form
form for a selected client, when the Edit
button is clicked. You may pass the complete client info object or the id of the client to the created ClientInfo
component. After the user has edited the client info form, and pressed the "Save" button, you should pass back the updated object to the parent component, that is, to the ClientList
component for further processing, as for instance, saving the newly edited data to a data store, etc. This sending and getting procedure between a parent component and its child is named Two-way Component data-binding, and should be made according to the following pattern:
@bind-Value="ClientInfoObject"
for the the parameter property Value defined in the child component.
You also need to define the mechanism to return the edited client info object to the parent component by defining a call back parameter property:
[Parameter]
public EventCallback<ClientInfoObject> ValueChanged {get; set;}
And now you can call the ValueChanged 'delegate' from your code to pass back the edited client info object to the parent component. This can be done form a "Save" method.
Note: Another two ways to implement the above is to use cascading parameters and services. Search my answers in stackoverflow. Neither is recommended here, and you should do it as I describe above.
Note also that you may display your ClientInfo
component in-line; that is, immediately below the row of the selected client in the ClientList
How to send data from Child to Parent component in Blazor (when a list is clicked)
Here's a slightly modified version of @Enet's answer that demonstrates how to use the built in razor bind framework used in the out-of-the-box Blazor input controls.
The modified BookComponent:
<ul>
@foreach (var book in Books)
{
<li class="@this.Selected(book)" @key="book" @onclick="@(() => this.SelectBook(book))"> @book.Title</li>
}
</ul>
@code
{
[Parameter] public Book Value { get; set; }
[Parameter] public EventCallback<Book> ValueChanged { get; set; }
[Parameter, EditorRequired] public List<Book> Books { get; set; }
public async Task SelectBook(Book book)
=> await ValueChanged.InvokeAsync(book);
// If you want to highlight the selected book
private string Selected(Book item)
=> item.ID == this.Value.ID
? "selected"
: string.Empty;
}
And used like this:
@page "/"
<PageTitle>Index</PageTitle>
@if (_selectedBook != null)
{
<div>@_selectedBook.Title </div>
}
<BookComponent Books="books" @bind-Value=this._selectedBook />
@code
{
private List<Book> books = Enumerable.Range(1, 10)
.Select(i => new Book {ID = i, Title = $"Title{i}"}).ToList();
private Book? _selectedBook;
}
Blazor Server Side - sharing values from Parent (Mainlayout) to Child Component (Pages)
Add class like
public class DataService
{
public Dictionary<string, EmpDetails> EmpDetails { get; set; }
}
register service in Program.cs, it may be Startup.cs
builder.Services.AddSingleton<DataService>();
now in MainLayout
[Inject]
private DataService DataService { get; set; }
if (DataService.EmpDetails.ContainsKey(EmpLoginId))
DataService.EmpDetails.Remove(EmpLoginId);
DataService.EmpDetails.Add(EmpLoginId, EmpDetails);
Now in any blazor component
[Inject]
private DataService DataService { get; set; }
and you can get user like
var empDetails = DataService.EmpDetails[EmpLoginId];
Related Topics
Why "Decimal" Is Not a Valid Attribute Parameter Type
How Better to Resolve Dependencies in Object Created by Factory
How to Use System.Net.Httpclient to Post a Complex Type
External Handler for Msiexec Msisetexternalui
Assert an Exception Using Xunit
Using a Pagedlist with a Viewmodel ASP.NET MVC
C# - Outputting Image to Response Output Stream Giving Gdi+ Error
The Requested Resource Does Not Support Http Method 'Get'
Using C# to Search a CSV File and Pull the Value in the Column Next to It
Project a Can't Reference a Class in Project B
How to Open a Web Page from My Application
How to Create "Embedded" SQL 2008 Database File If It Doesn't Exist
How to Check If a Class Inherits Another Class Without Instantiating It