Blazor data binding fundamentals

Data binding is a core feature of practically all front-end SPA (Single-page application) frameworks, including Blazor.

Blazor provides lots of useful data-binding features that are enabled by using specific Razor syntax within components.

In this article, I will cover the fundamental concepts of data binding with Blazor. After reading the article, you will understand the difference between one-way and two-way data binding and how to bind data to form input controls.

One-way data binding

The simplest kind of data binding we can do in Blazor is one-way data binding by specifying the name of a C# member, such as a property that we want to bind to, with the name of the member prefixed with an @ symbol.

Note that this article assumes you are working from the default Blazor template project (see my Getting started with Blazor article) and are using Visual Studio. However, if your project or environment is different you can still follow along and adjust the instructions according to your specific setup.

Component example

See the UsernameDisplay component below which provides an example of one-way data binding in action.

<label class="fw-bold">Username</label>
<p>@Username</p>
 
@code {
    [ParameterEditorRequired]
    public string Username { getset; } = "";
}

The markup in the above example contains a label element with a Bootstrap class that makes the fixed ‘Username’ text bold.

Within the p tag, data binding to the Username property is configured.

The @code block defines a Username property which has been configured as a component parameter via the Parameter attribute. This allows the value of the property to be specified when using the component within another component or page.

The EditorRequired attribute has also been specified. As a result, if a consumer of the component does not specify a value for the property, a compiler warning will be raised.

Using the component

To see what the component looks like in a running Blazor application, replace the content of the ‘Index.razor’ page within the default Blazor template project with the following.

Alternatively, create a new page component in your project and update the @page route accordingly.

@page "/"
 
<PageTitle>Index</PageTitle>
 
<h3>One-way data binding</h3>
<hr />
<UsernameDisplay Username="Jonathan" />

Now run your application to see the output.

Component output

If you updated the main ‘Index.razor’ page as suggested in the previous subsection, you should see the component output as soon as the application has finished loading.

As expected, the output of the component is very basic, as shown below.


One-way data binding example
One-way data binding example

With one-way data binding, data flows in one direction; from the component to the view. Therefore, if the Username property was to change its value in the code, a component re-render would be triggered and the new value would be reflected on the view. Blazor uses a smart ‘diff mechanism’ which means that only the specific part of the DOM that needs to change will be updated, the rest of the DOM will remain static.

However, what if we want changes to a bound data value on the view to flow back to the underlying component and update the property value there? We’ll look at how to achieve this next.

Two-way data binding

Two-way data binding allows changes that are made to data in the view to flow back to the component.

Component example

Below is a UsernameEditor component which provides an example of two-way data binding in action.

<label class="fw-bold">Username</label>
<p>@Username</p>
 
<textarea class="w-100" rows="1" @bind=Username @bind:event="oninput" />
 
@code {
    [ParameterEditorRequired]
    public string Username { getset; } = "";
}

The contents of the above component are the same as the UsernameDisplay component from the previous subsection, except that a new div containing a textarea has been added.

I’ve used a textarea in the example to demonstrate that two-way data binding can be configured for regular HTML input elements, as well as Blazor-specific ‘Input’ elements which we’ll cover later.

The textarea has been given a width of 100% via the Bootstrap ‘w-100’ class and the number of rows for the textarea has been set to a value of ‘1’ so that the textarea defaults to the height of one line of text.

The key part to notice in relation to data binding is the Blazor @bind attribute. This is what configures the two-way data binding to the Username property. Additionally, the @bind:event attribute specifies that the Username property value should be updated whenever the input event for the textarea is raised. Without specifying this, the property value would only be updated when the change event is fired i.e. when the textarea loses focus.

Using the component

Now, add the following markup to the ‘Index.razor’ page and run the application again.

<h3>Two-way data binding</h3>
<hr />
<UsernameEditor Username="Jonathan" />

Alternatively, add the above markup to another page component in your project.

After doing the above, run the application to see the output of the component.

Component output

The output of this component is more interesting than the previous one, as demonstrated below.


Two-way data binding example
Two-way data binding example

As you can see from the above animation when the username is edited via the textarea, the underlying value of the property is also updated and this is reflected in the paragraph above the control on each keystroke.

Form input data binding

Data binding within a form in a Blazor application is achieved in a similar manner to what was covered in the previous subsection, using a variant of the @bind syntax.

Component example

Below is a UserForm component which provides an example of form data binding in action.

Note that this form has been kept as simple as possible and therefore doesn’t include any form submission capability, as we are focusing purely on the data-binding aspects of the form.

<EditForm Model=_model>
    <div>
        <label class="fw-bold" for="username">
            Username
        </label>
        <div id="username">
            <InputText @bind-Value=_model.Username />
        </div>
    </div>
    <div class="pt-2">
        <label class="fw-bold" for="email">
            Email
        </label>
        <div id="email">
            <InputText @bind-Value=_model.Email />
        </div>
    </div>
</EditForm>

<p class="pt-3">
Username is <b>@(_model.Username.Length > 0 ? _model.Username : "blank")</b> and
Email is <b>@(_model.Email.Length > 0 ? _model.Email : "blank")</b>
</p>
@code {     private readonly UserModel _model = new();     public class UserModel     {         public string Username { getset; } = "";         public string Email { getset; } = "";     } }

In the above example, an EditForm component is used to build the form. EditForm is a built-in Blazor component that outputs a standard HTML form, but offers additional benefits such as simplified validation.

The EditForm accepts a data model to bind to via its Model parameter. In this case, a UserModel object is bound to the form.

Note that the UserModel class has been defined within the @code block to keep things simple for the example. Usually, you would define classes like this in a separate ‘.cs’ file.

Within the EditForm there are some div and label elements. The label elements specify a for attribute which links the label to an associated input control via its id attribute (doing this means that when the label is clicked on it will focus on the corresponding input control).

The InputText component is used as the input control for capturing data from the user. This component wraps a standard HTML input element with a type of text and exposes a Value property that we can bind to. The Razor syntax to bind to a specific component property is @bind-PropertyName. In this case, @bind-Value.

Within the p tag below the form, the @() syntax is used to allow some C# code to be evaluated. If the length of the Username or Email properties are greater than zero, their respective property values will be rendered, otherwise the text ‘blank’ will be rendered.

When the bound data is updated via the form input controls, the updated values will flow back to the properties in the code and the text on the screen will be updated accordingly.

Using the component

Now, add the following markup to the ‘Index.razor’ page and run the application again.

<h3 class="pt-3">Form data binding</h3>
<hr />
<UserForm />

Alternatively, add the above markup to another page component in your project.

Following this, run the application again to see the output of the component.

Component output

The output and behaviour of the component are demonstrated below.


Form data binding example
Form data binding example

In the above demonstration, the ‘Username’ field is populated and the Tab key is pressed to shift focus to the ‘Email’ field. Doing so causes the value of the Username property to be updated and this is reflected in the text below the form.

The ‘Email’ field is then populated and the Tab key is pressed again, causing the ‘change’ event to fire and the text below the form to be updated with the value of the Email property.

Note that if you want to update the value of the bound data when a different event such as ‘oninput’ is fired, you’ll need to use inheritance to derive a subclass from the InputText component and override its default behaviour.

Summary

In this article, I have covered the fundamentals of how data binding works in Blazor.

I’ve covered simple one-way data binding to properties and compared this with how two-way data binding works using the @bind syntax. Additionally, I’ve shown how you can data bind to form InputText controls using the @bind-Value syntax.

At this stage, you’ve seen the basics of how data binding works and the examples shown in this article should cover what you need to know regarding data binding for most day-to-day coding in Blazor. However, some additional things you may want to explore next are using @bind:get and @bind:set to bind to properties with get and set accessors, and using @bind:format to specify the display format of bound data e.g. @bind:format="yyyy-MM-dd".


I hope you enjoyed this post! Comments are always welcome and I respond to all questions.

If you like my content and it helped you out, please check out the button below 🙂

Comments