Author : MD TAREQ HASSAN | Updated : 2020/08/27
Data binding in blazor
- Razor components provide data binding features via an HTML element attribute named
@bind
with a field, property, or Razor expression value- field:
protected int count = 5
=><input @bind="count" />
- property:
protected int Count { get; set; }
=><input @bind="Count" />
- Razor Expression:
<input @bind="@(Count + 3)" />
- field:
- Ways to bind:
- Balzor Component & DOM
- one-way binding (Component -> DOM)
- two-way binding (Component <-> DOM)
- ParentComponent & ChildComponent (
[parameter]
)- one-way (ParentComponent -> ChildComponent)
- two-way (ParentComponent <-> ChildComponent)
- Balzor Component & DOM
- Links:
- https://docs.microsoft.com/en-us/aspnet/core/blazor/data-binding
- https://chrissainty.com/a-detailed-look-at-data-binding-in-blazor/
- https://blazor-university.com/components/one-way-binding/
- https://blazor-university.com/components/two-way-binding/
- http://blazorhelpwebsite.com/Blog/tabid/61/EntryId/4350/Blazor-Binding-Events-and-Parameters.aspx
One way binding to DOM
In one-way binding, we need to pass property or variable name along with “@
” i.e. “@Title
” (Title is either property or variable).
Counter.razor.cs
public class CounterBase : ComponentBase
{
protected int Count { get; set; }
protected EmployeeModel Employee { get; set; }
// ... ... ...
}
Counter.razor
@page "/counter"
@inherits CounterBase
<p>Current count: @Count</p>
<p>First Name: @Employee.FirstName</p>
Two way binding to DOM
- Two-way binding in Blazor uses a naming convention. If we want to bind to a property named SomeProperty, then we need an event call-back named SomeProperyChanged. This call-back must be invoked any time the component updates SomeProperty
- The primary use case for two way binding is in forms, although it can be used anywhere that an application requires input from the user
- The primary method of achieving two way binding in Blazor is to use the
@bind
attribute - Syntax:
<DomElement @bind-{ATTRIBUTE}="Xxx" @bind-{ATTRIBUTE}:event="yyy" />
{ATTRIBUTE}
: attribute of HTML5 elementXxx
: code behind class property/field (class Foo { string ParagraphStyle = ""; }
)yyy
: corresponds to an event- Example:
<p @bind-style="ParagraphStyle" @bind-style:event="onchange"></p>
- when ParagraphStyle value is changed i.e. (initially it was empty, but dynamically property value changed)
ParagraphStyle = "color:red"
, p tag will be red
- Default
- default
{ATTRIBUTE}
(when no attribute is mentioned i.e.<input @bind="..." >
) is “value” - default event (when
@bind-{ATTRIBUTE}:event
is not set) is “onchange
” <input @bind="..." />
is equivalent to<input @bind-value="..." @bind-value:event="onchange" />
- following 3 are all same:
@bind="Prop"
@bind-Value="Prop"
@bind-Value="Prop" @bind-Value:event="onchange"
- default
Counter.razor.cs
public class CounterBase : ComponentBase
{
protected int Count { get; set; }
// ... ... ...
}
Counter.razor
@page "/counter"
@inherits CounterBase
<input @bind="@Count" />
<input @bind="Count" />
Notes:
@bind="@Count"
=> bind to razor expression@bind="Count"
=> bind to property
Binding between components
- When one component is nested into another component, we can pass parameter
- Component parameter is property or variable in Component class with
[Parameter]
annotation - When a Component is used inside another component, it’s parameters can be set by using attribute i.e.
<MyComponent PropertyName="...">
one-way binding
Syntax: <MyComponent MyProp="@..." />
two-way binding
Syntax:
<ChildComponent @bind-{Param}="@..." /> // child should have a property (event): public EventCallback<T> {Param}Changed { get; set; }
`<ChildComponent @bind-{Param}="@..." @bind-Param:event="{Param}Changed" />`
<ChildComponent @bind-{Param}="{ParentComponentProp}" @bind-Param:event="{Param}Changed" />
- By default Blazor will look for an event on the child component using the naming convention of
{Param}Changed
{Param}Changed
: this property in child component must be marked with[Parameter]
annotation- Type of
{Param}
and{Param}Changed
must match i.e. in child component:public T Foo
public EventCallback<T> FooChanged { get; set; }
It’s also possible to use a completely different name for the EventCallback property, for example, ParentsTitleUpdated. But in this case we would need to use the long form version of bind and specify the event name like so.
`<ChildComponent @bind-{Param}="@..." @bind-Param:event="EventHandlerName" />`
So, [Parameter]
is used for:
- to bind parameter (attribute) passed from parent component
- to mark
{Param}Changed
event property - to bind route path parameter/segment to (public/protected) property of
ComponentBase
(in.razor.cs
)
One Way Binding Between Components
ParentComponent.razor.cs
public class ParentComponent : ComponentBase
{
protected int Name { get; set; } = "Foo1";
// ... ... ...
}
ParentComponent.razor
<h1>Parent name: @Name</h1>
<ChildComponent ParentName="@Name" /> <!-- Razor expression -->
<ChildComponent ParentName="Name" /> <!-- Property -->
ChildComponent.razor.cs
public class ChildComponent : ComponentBase
{
[Parameter]
protected int ParentName { get; set; }
// ... ... ...
}
ChildComponent.razor
<h1>Parent name in child: @ParentName</h1>
Two Way Binding Between Components
ParentComponent.razor.cs
public class ParentComponent : ComponentBase
{
protected int Name { get; set; } = "Foo1";
// ... ... ...
}
ParentComponent.razor
<h1>Parent name: @Name</h1>
<ChildComponent @bind-ParentName="@Name" />
ChildComponent.razor.cs
public class ChildComponent : ComponentBase
{
[Parameter]
protected int ParentName { get; set; }
[Parameter]
public EventCallback<string> ParentNameChanged { get; set; }
protected async Task UpdateParentName() {
ParentName = "Foo3"
await ParentNameChanged.InvokeAsync(ParentName);
}
// ... ... ...
}
ChildComponent.razor
<h1>Parent name in child: @ParentName</h1>
<button @onclick="@(async () => await UpdateParentName())">Update Parent Name</button>
Explanations:
@bind-ParentName="@Name"
=> two-way binding- ChildComponent:
ChildComponent.UpdateParentName()
->ChildComponent.ParentName
changed ->ParentComponent.Name
is also changed (because ofChildComponent.ParentNameChanged.InvokeAsync(ParentName)
)
Binding route path
[Parameter]
annotation is used
IetmDetails.razor
@page "/items/{ItemId}"
@inherits ItemDetailsBase
<p>Item Name: @Item.Name</p>
IetmDetails.razor.cs
public class ItemDetailsBase : ComponentBase
{
[Parameter]
protected int ItemId { get; set; }
public Item Item {get; set;}
protected override Task OnInitializedAsysnc()
{
Item = Items.FirstOrDefault(item => item.Id == int.Parse(ItemId));
}
// ... ... ...
}
Format strings
<input @bind="StartDate" @bind:format="yyyy-MM-dd" />
See: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/data-binding#format-strings