Best Way to Share Data Between Two Child Components in Blazor

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



Leave a reply



Submit