Blazor Parameters
- Parameters can be passed as component properties: <UserName Name="Alice"></UserName>
- You can also use [CascadingParameter]
- Parameters can be passed to pages as route values (including querystring), and use route contraints: <NavLink href="@($"UserEdit/{user.Id}")">Edit</NavLink>
Passing parameters down to components uses the [Parameter] attribute on properties (just get/set, don't implement any code).
<div class="col">Event: @UserEvent.EventDetails</div>
<div class="col"> @ChildContent </div>
</div>
@code {
//a standard parameter
//default! - the ! null forgiving operator is useful for initializing something that is always passed in
[Parameter]
public UserEvent UserEvent { get; set; } = default!;
//the body - basically the innerHtml
[Parameter]
public RenderFragment? ChildContent { get; set; }
//available to all nested components- you don't have to pass them down the hierarchy.
[CascadingParameter]
public User CurrentUser { get; set; } = default!;
//nb- for real, use Microsoft.AspNetCore.Components.WebAssembly.Authentication/<CascadingAuthenticationState>
}
Binding
For two way binding, the component must have a second xChanged parameter
public Customer Customer { get; set } = default!;
[Parameter]
public EventCallback<Customer> CustomerChanged { get; set }
RenderFragment
You can have several RenderFragments but the calling components must specify the property name
@ChildContent
<h3>User rights</h3>
@UserRights
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
[Parameter]
public RenderFragment? UserRights { get; set; }
}
Call it like this:
<UserRights>
No permissions
</UserRights>
<ChildContent>
Bob
</ChildContent>
</User>
ChildContent is a magic name- you can omit the property tags (no <ChildContent>)
Bob
</User>
Foreach loops are not good with RenderFragments, so use a for with counter.
{
var user = Users[i];
<UserComponent User="@user">
<NavLink href="@($"UserEdit/{user.Id}")">Edit</NavLink>
</UserComponent>
}
RenderFragments can be generic for templates
@if(Header is not null)
{
@Header
}
@foreach (var item in Items)
{
@ItemTemplate(item)
}
@if (Footer is not null)
{
@Footer
}
@code {
[Parameter]
[EditorRequired]
public required IEnumerable<TItem> Items { get; set; }
[Parameter]
public RenderFragment? Header { get; set; } = default;
[Parameter]
public RenderFragment? Footer { get; set; } = default;
[Parameter]
[EditorRequired]
public required RenderFragment<TItem> ItemTemplate { get; set; }
}
Use it by specifying Items (your collection)- you can rename the default name from "context".
<Header>
<h1>The spice must flow</h1>
</Header>
<ItemTemplate Context="curry">
<div class="row">
<div class="col">
@curry.Name
</div>
</div>
</ItemTemplate>
</ItemList>
CascadingValue
Wrap cascading values in a parent component or layout.
@Body
</CascadingValue>
@ref
Grab a reference to a child razor component
@code
{
private Basket _basket = default!;
Attribute splatting (CaptureUnmatchedValues)
You can copy arbitrary attributes- but this is not great for performance.
Using component
Component
</div>
@code {
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, object>? InputAttributes { get; set; }
[Parameter]
[EditorRequired]
public required State State { get; set; }
}