Today I will briefly discuss 5 different ways or methods of passing/sharing data from one Blazor component to another. At least, these are the 5 methods that I know of – route parameters, querystring, component parameters, cascading parameters, and state containers.
Contents
- Route parameters
- Querystring
- State containers
- Component parameters
- Cascading parameters
- When to use each method
- Conclusion
Route Parameters
The first way of passing data between Blazor components is via route parameters. As the name implies, you pass a value to another component via that component’s URL, as in the following URL:
https://localhost/mycomponent/Johnson
in which “mycomponent” is the name of the component, and “Johnson”
is the string that you are passing to mycomponent
.
Now, to give a more specific example, consider two components – Index.razor and UpdateEmployee.razor, as illustrated below.
For this example, I want to pass employee Id and employee last name from Index to UpdateEmployee. To accomplish this goal, we want these objects as route parameters.
To understand route parameters, it is important to understand the @page directive and route templates first. A @page directive is normally placed in the very beginning of your .razor file to define the URL(or route template) for your component. You can define as many route templates as you like for your component. The example below is a @page directive defined for UpdateEmployee component.
@page "/updateemployee"
This route template designates the URL for UpdateEmployee, and resolves to
https://localhost/updateemployee
which loads the UpdateEmployee page.
If you want UpdateEmployee to receive a value, then you need to add a route parameter to the route template, like so:
@page "/updateemployee/{parameter1}"
The {parameter1}
is the route parameter that you desire to capture from another component. If the captured string was “Smith”, then this route template resolves to
https://localhost/updateemployee/Smith
thereby allowing us to pass the value via the component’s URL.
As mentioned earlier, we want to define employee’s Id and last name as route parameters in UpdateEmployee, the receiving component. This implementation is shown below:
@page "/updateemployee"
@page "/updateemployee/{Id:int}"
@page "/updateemployee/{LName}"
<h3>Update Employee</h3>
<p>Updating Employee Id: @Id</p>
<p>Updating Employee Last Name: @LName</p>
@code {
[Parameter]
public int? Id { get; set; }
[Parameter]
public string? LName { get; set; }
}
As you can see on lines 1-3, there are three route templates defined for this component.
"/updateemployee"
– default route or URL for UpdateEmployee component."/updateemployee/{Id:int}"
– theId
parameter captures the value for employee Id. Also note theint
in{Id:int}
– this enforces the data type constraint for this parameter, in this case an integer, so that a numeric value in the URL will resolve to this route parameter. If this were a string, you don’t need to specify a data type because the route parameter in the template is assumed to be a string type by default.-
"/updateemployee/{LName}"
– theLName
parameter captures the value for the employee’s last name, in this case a string value.
In the @code
block, we are also defining two properties, Id
and LName
, which correspond to the route parameters. It is important to note that the route parameter names are not case-sensitive, so, a route parameter named lname
matches the property called LName
. BUT the spellings need to match! A route parameter named lastname
does not match LName
, and will give you a runtime error!
Now, that we understand how a component receives data via route parameters, how does a sender component pass the data then? Specifically, how does Index.razor (or any component that uses UpdateEmployee, for that matter ) pass those values to UpdateEmployee? The answer is via the NavigationManager
class. Check out the implementation of Index below:
@page "/"
@inject NavigationManager navigationManager
<h2>Employee Management System</h2>
<button @onclick="() => ButtonHandler()">Submit</button>
@code {
private int employeeId = 12345;
private string lastName = "vasay";
private void ButtonHandler()
{
navigationManager
.NavigateTo($"/updateemployee/{employeeId}");
}
}
Line 11 shows you how to use NavigationManager.NavigateTo()
to navigate to another component. Inside the NavigateTo()
method you pass a URL that corresponds to a component’s route template. In the example above, I want to pass a variable that contains the employee Id.
When you run the program, this is how it looks like:
When you click on the button you are taken to the page shown below:
Take note of the URL in which we are passing a value of “12345”. Obviously, last name is not being displayed because only Id is being passed. With this method of passing data, you can see that you can only send one value at a time. To send the last name, you need to send it separately like this:
navigationManager
.NavigateTo($"/updateemployee/{lastName}");
Which brings us to the next question. What if you want to send multiple values at one time?
What if you want to send multiple values at the same time?
An alternative implementation of the @page directive allows you to send multiple values at the same time. This is accomplished by specifying multiple parameters in one route template as demonstrated in the receiving component below:
@page "/updateemployee/{Id:int?}/{LName?}"
@code {
[Parameter]
public int? Id { get; set; }
[Parameter]
public string? LName { get; set; }
}
The question mark(?) after the parameter means that it is optional.
And then, the sending component is implemented like this: :
int employeeId = 12345;
string lastName = "Smith"
:
navigationManager.NavigateTo($"/updateemployee/{employeeId}/{lastName}");
The output of the program looks like this:
Again, take note of the values being passed via the URL. Before I end this discussion of route parameters, let’s discuss the confusion about them, specifically about the optional parameters.
The trickiness of optional parameters
You might be asking, “Since, Id
is optional, what if I omit Id
and ONLY provide lastName
?” As in,
.NavigateTo($"/updateemployee/{lastName}");
Will this work? The answer is No. You’ll get Sorry, there’s nothing at this address message!
This is because that URL does not match the order of route parameters – it was expecting a numeric value after “/updateemployee
“. The resulting URL resolves to
https://localhost/updateemployee/Smith
which seems to follow the rule of our @page directive of "/updateemployee/{Id:int?}/{LName?}"
, but, interestingly enough it doesn’t. The framework actually follows the order from left to right, and only accepts optionality from right to left, which, technically, is how web servers resolve incoming URL requests.
Hence, the code below works:
.NavigateTo($"/updateemployee/{employeeId}");
This works because the URL resolves
https://localhost/updateemployee/12345
which matches the order of our route template.
More examples of multiple route parameters
To confuse you even more (LOL), here is a use case scenario of a route template having four parameters, . Consider the code below:
@page "/updateemployee/{Id:int?}/{Department:int?}/{LName?}/{FName?}"
@code {
[Parameter]
public int? Id { get; set; }
[Parameter]
public int? Department { get; set; }
[Parameter]
public string? LName { get; set; }
[Parameter]
public string? FName { get; set; }
}
We have four parameters – Id
(numeric), Department
(numeric), LName
(string), and FName
(string).
Below, I am showing various calls to NavigationManager.NavigateTo()
with different combinations of values in the URLs (technically speaking, you can only call one NavigateTo()
at a time). The first four calls were a success, and the last four calls failed.
// Success
navigationManager.NavigateTo($"/updateemployee");
navigationManager.NavigateTo($"/updateemployee/{employeeId}");
navigationManager.NavigateTo($"/updateemployee/{employeeId}/{departmentId}");
navigationManager.NavigateTo($"/updateemployee/{employeeId}/{departmentId}/{lastName}");
// Error message - "Sorry, there'es nothing at this address."
navigationManager.NavigateTo($"/updateemployee/{employeeId}/{lastName}");
navigationManager.NavigateTo($"/updateemployee/{firstName}/{lastName}");
navigationManager.NavigateTo($"/updateemployee/{employeeId}/{lastName}/{firstName}");
navigationManager.NavigateTo($"/updateemployee/{departmentId}/{lastName}");
You can probably tell why those that failed failed based on my explanations above. Feel free to study them, and play around with route parameters in your free time. Let me know, though, if you have questions about this.
I would suggest that you use route parameters when you are passing one or two values to a component. More than that, you might have to use another method, something that allows you to specify what parameter goes with which value. And this is where querystring parameters come in!
QueryString Parameters
Querystring parameters allow you to attach the values as querystrings in a URL – in a key=value
format. This is more precise than using route parameters, in that you know which value goes with what parameter name. For example,
http://localhost:5186/displayemployee?Id=555&Department=2&LName=Hart&FName=Kevin
The querystrings begin after “?” in the URL. As you can see, we actually specify the parameter names, not just the values, like Id=555
. Id
is the parameter name and 555
is the value. Even if you do not pass any key=value
pair, the URL will resolve every time because the querystring is truly optional in this context.
As an example, say we have two components – Index.razor and DisplayEmployee.razor.
There are four values that we want to pass from Index to DisplayEmployee – Id, Department, LName and FName. And like before, I want to implement the receiving component first, in this case, DisplayEmployee. The code is shown below:
@page "/displayemployee"
<h3>Display Employee</h3>
<p>Employee Id: @Id</p>
<p>Department: @Department</p>
<p>Employee First Name: @FName</p>
<p>Employee Last Name: @LName</p>
@code {
[Parameter]
[SupplyParameterFromQuery]
public int? Id { get; set; }
[Parameter]
[SupplyParameterFromQuery]
public int? Department { get; set; }
[Parameter]
[SupplyParameterFromQuery]
public string? LName { get; set; }
[Parameter]
[SupplyParameterFromQuery]
public string? FName { get; set; }
}
As you can see, to make this work, all we need to do is specify the default @page
directive, and then declare the parameters inside the @code
block. This is very similar to the implementation of route parameters, with one difference – we need to add the [SupplyParameterFromQuery]
attribute for each parameter to tell the framework that the values are coming as querystring values. Simple and straightforward!
Now, for the the sending component, Index, we need to do a little bit of work. Here is the source code for Index.razor.
@page "/"
@using Microsoft.AspNetCore.WebUtilities
@inject NavigationManager navigationManager
<h3>Employee Management System</h3>
<button @onclick="() => HandleButton()">Display Employee</button>
@code {
private void HandleButton()
{
var queryStrDict= new Dictionary<string, string>
{
["Id"] = "555",
["Department"] = "2",
["LName"] = "Hart",
["FName"] = "Kevin"
};
navigationManager.NavigateTo(
QueryHelpers.AddQueryString("/displayemployee", queryStrDict)
);
}
}
To send the values of querystrings, we need to create a Dictionary of key=value pairs, as shown on line 9.
On line 16, we also use NavigationManager.NavigateTo() as before to navigate to DisplayEmployee. This time though, we use the QueryHelpers class of Microsoft.AspNetCore.WebUtilities to get the URL+querystrings format, shown on line 17.
Below is the output of the application:
When we click the “Display Employee” button, we are calling the DisplayEmployee component and passing it 4 values. Below is DisplayEmployee component displaying the 4 values.
At this point, you may be wondering, “What if you want to pass an object, such as Employee model, for instance? I can’t pass a complex object in the URL.” And you are right. This is where State Containers come in! And this is next!
State Containers
The problem with passing data via route parameters or querystring is that you can’t pass a complex object in the URL, because these methods are restricted to numeric and string types. And, generally speaking, it is not realistic to only pass either a string or integer. Sometimes you want to share complex objects with other components in the application.
What we want is to be able to pass or share a complex object to another component as illustrated below:
If Index modifies Employee instance, and wants to pass or share the state of that instance to DisplayEmployee via
NavigationManager.NavigateTo("/displayemployee")
then the best way to do this is wrap the Employee model inside a state container service, and register that service in the main program. This is exactly what I’m going to describe now.
In this example, I created a project called BlazorStateContainer
. I also created Model
directory, under Shared
directory. Inside Model
directory, I created a file called Employee.cs, which will server as our Employee
model, as shown below:
namespace BlazorStateContainer.Shared.Model
{
public class Employee
{
public int Id { get; set; } = 1;
public int Department { get; set; } = 0;
public string LName { get; set; } = string.Empty;
public string FName { get; set; } = string.Empty;
}
}
Then, inside the Shared
directory, I created MyStateContainer
class, as shown below:
using BlazorStateContainer.Shared.Model;
namespace BlazorStateContainer.Shared
{
public class MyStateContainer
{
public Employee Value { get; set; }
public event Action OnStateChange;
public void SetValue(Employee value)
{
this.Value = value;
NotifyStateChanged();
}
private void NotifyStateChanged() => OnStateChange?.Invoke();
}
}
As you can see above, MyStateContainer
is our state container service, and inside it, we declare an Employee
property called Value
.
OnStateChange
is an event that is raised when the Employee object is modified. NotifyStateChanged()
is a method that we define to raise the OnStateChange
event. SetValue()
is a method that sets the value of the Value property.
Now, we need to register MyStateContainer
as a service inside Program.cs
.
builder.Services.AddSingleton<MyStateContainer>();
As you can see, all you need to do is add MyStateContainer
as a singleton service. Also, make sure you BlazorStateContainer.Shared
namespace, otherwise you will get a compiler error.
Now, that we have established the state container or state object, how do components such as Index
and DisplayEmployee
use this container service?
As shown in the code below, the Index component will use the MyStateContainer
service to set the values of the Employee properties.
@page "/"
@inject NavigationManager navigationManager
@inject MyStateContainer myStateContainer
@implements IDisposable
<PageTitle> Employee Management System</PageTitle>
<h1> Employee Management System</h1>
<button @onclick="() => HandleButton()">Display Employee</button>
@code {
private Employee employee = new Employee { Id = 700, Department = 3, LName = "Johnson", FName = "Dwayne" };
protected override void OnInitialized()
{
myStateContainer.OnStateChange += StateHasChanged;
}
private void HandleButton()
{
myStateContainer.SetValue(employee);
navigationManager.NavigateTo("/displayemployee");
}
public void Dispose()
{
myStateContainer.OnStateChange -= StateHasChanged;
}
}
Line 3 shows you how to use MyStateContainer – we inject it into our component! We can inject it because we registered it as a service in our man program, and by doing so it is now a global object that can be accessed anywhere in our application.
Line 9 instantiates a new Employee object and initializes its properties to some random values. These are the values that we want other components to see.
Line 12 is executed when our component is first loaded. With this, our component “subscribes” to the OnStateChange event.
On line 16 you see:
myStateContainer.SetValue(employee)
which shows you how to set the Value property of MyStateContainer to the new instance of Employee.
We are now ready to navigate to DisplayEmployee with
navigationManager.NavigateTo("/displayemployee")
on line 17. At this point, even though we are not explicitly passing any data in the URL, we are confident that the component we are navigating to will have access to our data in our state container object.
Finally, I want to point out that Index is implementing the IDisposable interface because this allows us to do some explicit cleanup when we created our MyStateObject as a global object. Hence, on line 4, we do this: @implements IDisposable
. The cleanup code happens on lines 19-22 when we implement Dispose()
in which we we explicitly “unsubscribe” to the OnstateChange
event.
How does DisplayComponent access the values of Employee
object that was set by Index? It’s a lot more simple because all we need to do is inject the state object in our component, then access the Value
property. Check out the code below:
@page "/displayemployee"
@inject MyStateContainer myStateContainer
<h3>DisplayEmployee</h3>
<p>Employee Id: @employee.Id</p>
<p>Employee Department: @employee.Department</p>
<p>Employee First Name: @employee.FName</p>
<p>Employee Last Name: @employee.LName</p>
@code {
private Employee employee;
protected override void OnInitialized()
{
base.OnInitialized();
employee = myStateContainer.Value;
}
}
Just like before we inject MyStateContainer
shown on line 2. On line 13, you can see that all we need to do to access the employee object is call myStateContainer.Value
which will give us the Employee object.
And that’s pretty much how you implement state containers. It looks like a lot of work, but it really just involves creating a state container, adding it as a singleton service and injecting this service in components that want to access the state container.
Component Parameters
The next method of passing data to a component is via component parameter. You use this method when you want to pass data to a nested component. Let’s say that I have two components – Index.razor and DisplayEmployee.razor. Let’s say that DisplayEmployee component is nested within Index component, as illustrated below.
Say, I want to pass employee id and/or last name from Index down to DisplayEmployee. First, let’s declare Id and email add as parameters of DisplayEmployee as shown below:
@page "/displayemployee"
<h3>Display Employee</h3>
<p>Employee Id: @Id</p>
<p>Employee Last Name: @LName</p>
@code {
[Parameter]
public int? Id { get; set; } = 0;
[Parameter]
public string? LName { get; set; } = "Coder Schmoder";
}
As you can see, you simply define two properties – Id
on line 7 and LName
on line 10, and decorate each of them with [Parameter
] attributes. Note that I also initialized them to some default values, in case no values are passed down from the parent component.
Another thing I want to point out is the @page directive that I added on line 1. You need to have at least one default @page directive for your component if you want your component to be reached via a URL.
Then, implement Index as shown below:
@page "/"
<h2> Employee Management System</h2>
<DisplayEmployee Id="@employeeId"
LName = "@lastName" />
@code {
private int employeeId = 12345;
private string lastName = "Alejandrio Vasay";
}
As you can see, line 4 is where you are nest DisplayEmployee within Index, and pass two arguments – Id="@employeeId"
and LName="@lastName"
, which should match the properties defined in DisplayEmployee component. When you run the program, it should look like this:
And that is pretty much it for component parameters. Very simple and straightforward!
What if you want to pass a complex object?
I you want to pass a complex object from Index to DisplayEmployee, for instnce, it’s really no different than passing an int or string, except you are passing a complex data type. Let’s say you want to pass an Employee object. First make sure you have defined your Employee model as shown below:
public class Employee
{
public int Id { get; set; } = 1;
public int Department { get; set; } = 0;
public string LName { get; set; } = string.Empty;
public string FName { get; set; } = string.Empty;
}
Then, in your index component, do the following:
<DisplayEmployee Employee = "@employee" />
@code {
private Employee employee = new Employee { Id = 700, Department = 3, LName = "Johnson", FName = "Dwayne" };
}
As shown above, you nest DisplayEmployee as usual and pass the Employee to it. It its Important, inside the @code
block, that you instantiate an Employee model and initialize the properties of Employee.
And finally, in DisplayEmployee you do the following:
<p>Employee Department: @Employee.Department</p>
@code {
[Parameter]
public Employee? Employee { get; set; }
}
As you can see above inside the @coe block, we declare Employee as property of DisplayEmployee, and also add the [Parameter]
attribute. Then, in the markup area, it is just as simple as accessing the object property via object.property
, as in my example above in which I call @Employee.Department
.
Cascading Parameters
What if you have a hierarchy of nesting? This is where cascading parameters come in!
In this example, we have 3 components – Index.razor, DisplayDepartment.razor, and DisplayEmployee.razor. As shown above, DisplayEmployee is nested inside DisplayDepartment, which in turn, is nested inside Index. We need to pass down two values – department id and minimum salary.
These are the requirements for our application:
- Index – passes values of department id and minimum salary to DisplayDepartment, and it also nest DisplayDepartment.
- DisplayDeparment – captures value of department id, and display it on page. In addition, it nests DisplayEmployee component.
- DisplayEmployee – captures values of department id and minimum salary, and display them on page.
The first thing that we need to do is implement DisplayDepartment and DisplayEmployee components, and the implementation to capture the values from parent is very similar to Component Parameters that we discussed earlier. However, instead of using [Parameters]
attribute, we will use [CascadingParameter]
in all the descendants that want to access the values from the top parent.
Following the requirements listed above, here is the implementation of DisplayDepartment component:
@page "/displaydepartment"
<h3>Display Department - @Department</h3>
<p></p>
<DisplayEmployee></DisplayEmployee>
@code {
[CascadingParameter(Name = "Department")]
public int Department { get; set; }
}
The most important part of this code is line 6. As you can see, you need to attach (or prefix) the [CascadingParameter(Name = "Department")]
to the property declaration. By declaring the Department
property as a cascading parameter, the DisplayDepartment component is able to capture the department value from its parent, the Index component. The (Name = "Department")
part is optional, but I will show you in a minute why this is important. Line 2 shows you that I’m displaying the value of Department inside the <h3> tag. Line 4 shows you how to nest the DisplayEmployee inside our DisplayDepartment.
Now, here is the implementation of DisplayEmployee component:
@page "/displayemployee"
<h3>Display Employee - Department @Department has min salary of @MinSalary</h3>
<p></p>
@code {
[CascadingParameter(Name = "Department")]
public int Department { get; set; }
[CascadingParameter(Name = "MinSalary")]
public int MinSalary { get; set; }
}
As you can see, this is very similar to the DisplayDepartment component from earlier, except, we are declaring a second property called MinSalary
, on line 8. And as usual, notice (Name = "MinSalary")
. On line 2, we are displaying the values of Department
and MinSalary
, inside the <h3>
tag.
Now, for the Index component! How does Index pass the values cascadingly? Check out the implementation of Index below:
@page "/"
<PageTitle>Employee Management System</PageTitle>
<h1>Employee Management System</h1>
<p></p>
<CascadingValue Value="@id" Name="Department">
<CascadingValue Value="@minSal" Name="MinSalary">
<DisplayDepartment></DisplayDepartment>
</CascadingValue>
</CascadingValue>
@code
{
private int id = 3;
private int minSal = 60000;
}
The most important part of this code is lines 5-9. As the name implies, <CascadingValue>
is a Blazor component where you declare or specify values that you want to cascade to nested components. There are two <CascadingValue>
components , one for Department
, and one for MinSalary
. Notice, that if you have multiple values like we do, how we need to nest one <CascadingValue>
within another. This becomes a gigantic mess, of course, if you have multiple of them! If you know of a way to cascade multiple values without multiple nested <CascadingValue>
, let me know!
Line 7 shows you how <DisplayDepartment>
component is nested With this, we completed the nesting requirements – Index is nesting DisplayDepartment which in turn is nesting DisplayEmployee.
Previously, I mentioned that attaching the Name attribute such Name="Department"
on line 5 and Name="MinSalary"
on line 6 is optional. But I also said that there is a reason why this is important. When you have multiple parameters with same data type, like int
in our example, you need to help the framework resolve which value goes to which parameter. For multiple values with different data types, for example if Department
is declared string
and MinSalary
is int
, then you don’t need to add the Name attribute.
When you run the program, it would like this:
When to use each method
I created a table below that gives you a summary and a general idea of when to use each of these methods. The scenario below assumes there are three components: #1, #2, and #3.
METHOD | SCENARIO | DATA TYPE |
---|---|---|
Route parameters |
• #1 navigates to #2 (data in URL) |
integer/ string |
Querystring | • #1 navigates to #2 (data in URL) | integer/ string |
Component parameters | • Nested components • #1 passes value to #2 • #2 is nested inside #1 |
complex/ integer/ string |
Cascading parameters | • Nested components in hierarchy • #1 passes value to #2 • Only #2 is nested inside #1 • #3 is nested inside #2 • #2 or #3 needs to capture the value |
complex/ integer/ string |
State containers | • Share a global object between components. • Suitable for complex objects • No nested components |
complex/ integer/ string |
Conclusion
Blazor has at least five methods of passing or sharing data between components. The route parameters and querystring methods allow you to pass data in a component’s URL. The component parameters and cascading parameters methods allow you to pass data from parent component to child components when nesting is involved. The last one, which is the state containers, allows components to share complex objects by registering a state container as a singleton service that all components can share.
In the state container example, why did you register it as a singleton service?
In that case, the same instance will be passed to all users. In my reading it should be registered as scoped.
Thanks,
Ray
Hi Ray. It depends on what your application wants to do. You need to ask two questions:
1) What does your application want to do?
2) What type of Blazor application do you want to create?
For question #1, I’m using Singleton because I wanted the same state all throughout the lifetime of the application. I want all users to see use the same instance.
For question #2, I’m using Blazor WASM in my tutorial, so I am using Singleton. Are you creating a client-side(WASM) application or server-side Blazor application? I explain more below the difference in behavior of lifetimes between a WASM and server-side applications.
If you have a Blazor WASM application, the Singleton and Scope lifetimes behave the same way since the app runs in the browser without the need for server. With Blazor WASM you can only have two behaviors – a singleton or transient. You can explicitly use scope but, like I said, it will behave like singleton and vice-versa. So, it doesn’t matter whether you use a singleton or scope.
If you have a Blazor Server, a singleton and scope ALMOST behave the same way. I say “ALMOST” because singleton and scope behave the same way until you re-load (or re-fresh) your app. When you reload the page(or open a new tab), a Singleton lifetime will use the same instance, while Scope will create a new one. In a scope lifetime, reloading a page (or opening a new tab) is considered a new request. You must ask yourself, is this what your users need to expect from your application in which opening a new browser or tab will create a new state object? Or do you want your users to share the same state object. Honestly though, if you’re not sure, use either one because during your user testing, you can switch from another lifetime to another depending on how your application must behave.
Checkout my little illustration below:
In Blazor WASM
* Go to Index page – app creates a new state (Singleton or Scope)
* Go to DisplayEmployee page – app uses same state (Singleton or Scope)
* Reload DisplayEmployee (or new tab) – app create a new state (Singleton or Scope)
In Blazor Server
* Go to Index page – app creates a new state (Singleton or Scope)
* Go to DisplayEmployee page – app uses state (Singleton or Scope)
* Reload DisplayEmployee (or new tab) – In Singleton, app uses same state (but in Scope, it creates a new state)
Notice that WASM and Server only differ on reload.
So, determine if you want WASM or Server, and determine what you want your users to expect from your application, and go from there. I hope this helps.
Thank you, I appreciate your post. Very comprehensive and reduced to the essence. E.g. it took me 5 seconds to understand what CascadingParameters are with your simple example. Maybe you should write the Doc’s for MSFT? 😇
Great content, thanks for sharing, it helped me a lot
Thank you, this is very helpful!
A couple of questions, if I may.
Why did you use @onclick=”() => ButtonHandler()” instead of @onclick=”@ButtonHandler”? Is there any advantage of doing it this way?
And another one. What do you think is a better way to get data from a DB in a child component – by passing the dataset (IEnumerable) from the parent component via a parameter, or getting the dataset in the child component itself in OnInitializedAsync event? The difference I noticed so far is ErrorBoundary I wrap around a child component does not function if I get a dataset in the parent component and something happens in that method. Whereas if I move the same method into the child component, then the ErrorBoundary in the parent catches the exception.
Note: I do use try/catch. I just want to through the exception to display my custom ErrorContent component.
I hope you have time to share your thought on this.
Hi, sorry for responding late, I have been busy at my fulltime job lately. But to respond to your first question about onclick, there really is no difference between @onclick=”() => ButtonHandler()” and of @onclick=”@ButtonHandler”.
Both of those event handlers are delegates – they both point to a function. In my tutorial, I used the lambda function because I was experimentin with putting all my code inline(e.g., @onclick=”() => navigationManager.NavigateTo ($”/updateemployee/{employeeId}”)”). Thus, my use of a lambda function as an even handler delegate. But seriously you can use either one as event handlers are delegates.
For your next question about passing IEnumerable from parent component to child component, I would suggest to just access the dataset directly in the child component, or whichever component needs that dataset needs to fetch it. And yes, the data is fetched inside OnInitializedAsync. Is there a reason to pass in a DBSet? Even when the parent had modified the DBContext, the child component who will display the data still needs to fetch the data anew from DBContext. Without knowing what your application is doing, my simpleton answer is based off of my own experience with simple Blazor applications with CRUD components. I probably did not answer your concerns, but thanks for visiting my website, and even dropping some comments. THANKS!
Thanks, Alejandrio!
No, you answered perfectly.
I hope to see more content like this on your blog.