Author : HASSAN MD TAREQ

Data binding in blazor

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 element
    • Xxx: 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"

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

Component parameter

  • 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 Param="...">
  • Binding:
    • one-way binding: <MyComponent MyProp="..." />
    • two-way binding: <MyComponent @bind-MyProp="..." @bind-MyProp:event="MyEventHandler" />

Two way binding (between components) syntax:
<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 event property must be marked with [Parameter] annotation
  • However, 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.

[Parameter] is used for:

  • to bind parameter (attribute) passed from parent component
  • to mark {Param}Changed event property
  • to bind route path parameter to (public/protected) property of XxxComponentBase

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";
	
    protected void UpdateName()
    {
        Name = "Foo2";
    }
	
	// ... ... ...
}

ParentComponent.razor


<h1>Parent name: @Name</h1>

<button @onclick="UpdateName">Update Name</button>

<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 void UpdateParentName() {
        ParentName = "Foo3"
        ParentNameChanged.InvokeAsync(ParentName);
    }

    // ... ... ...
}

ChildComponent.razor

<h1>Parent name in child: @ParentName</h1>

<button @onclick="UpdateParentName">Update Parent Name</button>

Explanations:

  • @bind-ParentName="@Name" => two-way binding
  • ParentComponent: ParentComponent.UpdateName() -> ParentComponent.Name changed -> ChildComponent.ParentName is also changed
  • ChildComponent: ChildComponent.UpdateParentName() -> ChildComponent.ParentName changed -> ParentComponent.Name is also changed (because of ChildComponent.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