12 KiB
title | author | description | monikerRange | ms.author | ms.custom | ms.date | no-loc | uid | ||
---|---|---|---|---|---|---|---|---|---|---|
ASP.NET Core Blazor data binding | guardrex | Learn about data binding features for components and DOM elements in Blazor apps. | >= aspnetcore-3.1 | riande | mvc | 03/26/2020 |
|
blazor/data-binding |
ASP.NET Core Blazor data binding
By Luke Latham and Daniel Roth
Razor components provide data binding features via an HTML element attribute named @bind
with a field, property, or Razor expression value.
The following example binds the CurrentValue
property to the text box's value:
<input @bind="CurrentValue" />
@code {
private string CurrentValue { get; set; }
}
When the text box loses focus, the property's value is updated.
The text box is updated in the UI only when the component is rendered, not in response to changing the property's value. Since components render themselves after event handler code executes, property updates are usually reflected in the UI immediately after an event handler is triggered.
Using @bind
with the CurrentValue
property (<input @bind="CurrentValue" />
) is essentially equivalent to the following:
<input value="@CurrentValue"
@onchange="@((ChangeEventArgs __e) => CurrentValue =
__e.Value.ToString())" />
@code {
private string CurrentValue { get; set; }
}
When the component is rendered, the value
of the input element comes from the CurrentValue
property. When the user types in the text box and changes element focus, the onchange
event is fired and the CurrentValue
property is set to the changed value. In reality, the code generation is more complex because @bind
handles cases where type conversions are performed. In principle, @bind
associates the current value of an expression with a value
attribute and handles changes using the registered handler.
Bind a property or field on other events by also including an @bind:event
attribute with an event
parameter. The following example binds the CurrentValue
property on the oninput
event:
<input @bind="CurrentValue" @bind:event="oninput" />
@code {
private string CurrentValue { get; set; }
}
Unlike onchange
, which fires when the element loses focus, oninput
fires when the value of the text box changes.
Use @bind-{ATTRIBUTE}
with @bind-{ATTRIBUTE}:event
syntax to bind element attributes other than value
. In the following example, the paragraph's style is updated when the _paragraphStyle
value changes:
@page "/binding-example"
<p>
<input type="text" @bind="_paragraphStyle" />
</p>
<p @bind-style="_paragraphStyle" @bind-style:event="onchange">
Blazorify the app!
</p>
@code {
private string _paragraphStyle = "color:red";
}
Attribute binding is case sensitive. For example, @bind
is valid, and @Bind
is invalid.
Unparsable values
When a user provides an unparsable value to a databound element, the unparsable value is automatically reverted to its previous value when the bind event is triggered.
Consider the following scenario:
-
An
<input>
element is bound to anint
type with an initial value of123
:<input @bind="MyProperty" /> @code { [Parameter] public int MyProperty { get; set; } = 123; }
-
The user updates the value of the element to
123.45
in the page and changes the element focus.
In the preceding scenario, the element's value is reverted to 123
. When the value 123.45
is rejected in favor of the original value of 123
, the user understands that their value wasn't accepted.
By default, binding applies to the element's onchange
event (@bind="{PROPERTY OR FIELD}"
). Use @bind="{PROPERTY OR FIELD}" @bind:event={EVENT}
to trigger binding on a different event. For the oninput
event (@bind:event="oninput"
), the reversion occurs after any keystroke that introduces an unparsable value. When targeting the oninput
event with an int
-bound type, a user is prevented from typing a .
character. A .
character is immediately removed, so the user receives immediate feedback that only whole numbers are permitted. There are scenarios where reverting the value on the oninput
event isn't ideal, such as when the user should be allowed to clear an unparsable <input>
value. Alternatives include:
- Don't use the
oninput
event. Use the defaultonchange
event (only specify@bind="{PROPERTY OR FIELD}"
), where an invalid value isn't reverted until the element loses focus. - Bind to a nullable type, such as
int?
orstring
, and provide custom logic to handle invalid entries. - Use a form validation component, such as
InputNumber
orInputDate
. Form validation components have built-in support to manage invalid inputs. Form validation components:- Permit the user to provide invalid input and receive validation errors on the associated
EditContext
. - Display validation errors in the UI without interfering with the user entering additional webform data.
- Permit the user to provide invalid input and receive validation errors on the associated
Format strings
Data binding works with xref:System.DateTime format strings using @bind:format
. Other format expressions, such as currency or number formats, aren't available at this time.
<input @bind="StartDate" @bind:format="yyyy-MM-dd" />
@code {
[Parameter]
public DateTime StartDate { get; set; } = new DateTime(2020, 1, 1);
}
In the preceding code, the <input>
element's field type (type
) defaults to text
. @bind:format
is supported for binding the following .NET types:
- xref:System.DateTime?displayProperty=fullName
- xref:System.DateTime?displayProperty=fullName?
- xref:System.DateTimeOffset?displayProperty=fullName
- xref:System.DateTimeOffset?displayProperty=fullName?
The @bind:format
attribute specifies the date format to apply to the value
of the <input>
element. The format is also used to parse the value when an onchange
event occurs.
Specifying a format for the date
field type isn't recommended because Blazor has built-in support to format dates. In spite of the recommendation, only use the yyyy-MM-dd
date format for binding to work correctly if a format is supplied with the date
field type:
<input type="date" @bind="StartDate" @bind:format="yyyy-MM-dd">
Parent-to-child binding with component parameters
Binding recognizes component parameters, where @bind-{PROPERTY}
can bind a property value from a parent component down to a child component. Binding from a child to a parent is covered in the Child-to-parent binding with chained bind section.
The following child component (ChildComponent
) has a Year
component parameter and YearChanged
callback:
<h2>Child Component</h2>
<p>Year: @Year</p>
@code {
[Parameter]
public int Year { get; set; }
[Parameter]
public EventCallback<int> YearChanged { get; set; }
}
EventCallback<T>
is explained in xref:blazor/event-handling#eventcallback.
The following parent component uses:
ChildComponent
and binds theParentYear
parameter from the parent to theYear
parameter on the child component.- The
onclick
event is used to trigger theChangeTheYear
method. For more information, see xref:blazor/event-handling.
@page "/ParentComponent"
<h1>Parent Component</h1>
<p>ParentYear: @ParentYear</p>
<ChildComponent @bind-Year="ParentYear" />
<button class="btn btn-primary" @onclick="ChangeTheYear">
Change Year to 1986
</button>
@code {
[Parameter]
public int ParentYear { get; set; } = 1978;
private void ChangeTheYear()
{
ParentYear = 1986;
}
}
Loading the ParentComponent
produces the following markup:
<h1>Parent Component</h1>
<p>ParentYear: 1978</p>
<h2>Child Component</h2>
<p>Year: 1978</p>
If the value of the ParentYear
property is changed by selecting the button in the ParentComponent
, the Year
property of the ChildComponent
is updated. The new value of Year
is rendered in the UI when the ParentComponent
is rerendered:
<h1>Parent Component</h1>
<p>ParentYear: 1986</p>
<h2>Child Component</h2>
<p>Year: 1986</p>
The Year
parameter is bindable because it has a companion YearChanged
event that matches the type of the Year
parameter.
By convention, <ChildComponent @bind-Year="ParentYear" />
is essentially equivalent to writing:
<ChildComponent @bind-Year="ParentYear" @bind-Year:event="YearChanged" />
In general, a property can be bound to a corresponding event handler by including an @bind-{PROPRETY}:event
attribute. For example, the property MyProp
can be bound to MyEventHandler
using the following two attributes:
<MyComponent @bind-MyProp="MyValue" @bind-MyProp:event="MyEventHandler" />
Child-to-parent binding with chained bind
A common scenario is chaining a data-bound parameter to a page element in the component's output. This scenario is called a chained bind because multiple levels of binding occur simultaneously.
A chained bind can't be implemented with @bind
syntax in the page's element. The event handler and value must be specified separately. A parent component, however, can use @bind
syntax with the component's parameter.
The following PasswordField
component (PasswordField.razor):
- Sets an
<input>
element's value to aPassword
property. - Exposes changes of the
Password
property to a parent component with an EventCallback. - Uses the
onclick
event is used to trigger theToggleShowPassword
method. For more information, see xref:blazor/event-handling.
<h1>Child Component</h1>
Password:
<input @oninput="OnPasswordChanged"
required
type="@(_showPassword ? "text" : "password")"
value="@Password" />
<button class="btn btn-primary" @onclick="ToggleShowPassword">
Show password
</button>
@code {
private bool _showPassword;
[Parameter]
public string Password { get; set; }
[Parameter]
public EventCallback<string> PasswordChanged { get; set; }
private Task OnPasswordChanged(ChangeEventArgs e)
{
Password = e.Value.ToString();
return PasswordChanged.InvokeAsync(Password);
}
private void ToggleShowPassword()
{
_showPassword = !_showPassword;
}
}
The PasswordField
component is used in another component:
@page "/ParentComponent"
<h1>Parent Component</h1>
<PasswordField @bind-Password="_password" />
@code {
private string _password;
}
To perform checks or trap errors on the password in the preceding example:
- Create a backing field for
Password
(_password
in the following example code). - Perform the checks or trap errors in the
Password
setter.
The following example provides immediate feedback to the user if a space is used in the password's value:
<h1>Child Component</h1>
Password:
<input @oninput="OnPasswordChanged"
required
type="@(_showPassword ? "text" : "password")"
value="@Password" />
<button class="btn btn-primary" @onclick="ToggleShowPassword">
Show password
</button>
<span class="text-danger">@_validationMessage</span>
@code {
private bool _showPassword;
private string _password;
private string _validationMessage;
[Parameter]
public string Password
{
get { return _password ?? string.Empty; }
set
{
if (_password != value)
{
if (value.Contains(' '))
{
_validationMessage = "Spaces not allowed!";
}
else
{
_password = value;
_validationMessage = string.Empty;
}
}
}
}
[Parameter]
public EventCallback<string> PasswordChanged { get; set; }
private Task OnPasswordChanged(ChangeEventArgs e)
{
Password = e.Value.ToString();
return PasswordChanged.InvokeAsync(Password);
}
private void ToggleShowPassword()
{
_showPassword = !_showPassword;
}
}
Radio buttons
For information on binding to radio buttons in a form, see xref:blazor/forms-validation#work-with-radio-buttons.