Study blazor. Net data binding

Translated from: Study Blazor .NET , reprint, please specify.

Data binding

Unidirectional binding

In blazor, one-way binding is simple and direct without UI refresh or rendering. The following example shows one-way data binding:

//Counter.razor
@page "/counter"

<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>

@functions {
    int currentCount = 0;
    void IncrementCount()
    {
        currentCount++;
    }
}

Here, the value of @ currentComponent will increase according to the number of Click me buttons< p> The value of the label element is refreshed automatically without any other component.

Bidirectional binding

Blazor provides a variety of options for two-way binding, which is more elegant than some popular JS languages.

Use bindings in the same component

In blazor, the bind feature supports two-way data binding. In the following example, the checkbox uses the bind attribute in the same component:

//TwoWayBind.razor
@page "/two-way-binding"

<input type="checkbox" 
       bind="@updateString" />
<p>This string will get value from above text field : @updateString.ToString()</p>

@functions {
    Boolean updateString {get; set;} = true;
}

Bidirectional data binding can also be implemented using lamda expressions through the onchange feature. Don't worry. Blazor provides a simple method to bind attributes. More details are as follows:

//TwoWayBind.razor
@page "/two-way-binding"

<input type="text" 
       value="@updateString" 
       onchange="@((UIChangeEventArgs __e) => updateString = __e.Value.ToString())"/>

<p>This string will get value from above text field: @updateString</p>

@functions {
    string updateString = "";
}

The bind feature can be extended with value and event bind value - < onwevent >. The above example can be rewritten as follows by using oninput instead of onchange:

//TwoWayBind.razor
@page "/two-way-binding"

<input type="text" 
       bind-value-oninput="@updateString" />
<p>This string will get value from above text field : @updateString</p>

@functions {
    string updateString = "";
}

Binding between different components

Method 1

The data transferred between components is completed through component attributes and their attribute mapping. This method uses the action < title > data type.

//ParentComponent.razor
<h3> Parent Component</h3>
<p>String in Parent: @parentString</p>
<button onclick="@PassToChild">Pass String To Child</button>

<ChildComponent 
        ToChild=@parentString
        FromChild=@ReceivedFromChild>    
</ChildComponent>

@functions{
    private string parentString = "Initial Parent String";
    private void PassToChild()
    {
        parentString += "- To Child";
    }
    private void ReceivedFromChild(string str)
    {
        parentString = str;
        StateHasChanged();
    }
}
//ChildComponent.razor
<h4>Child Component</h4>
<button onclick="@PassToParent">Pass String to Parent</button>
<p>String received from Parent : @ToChild</p>

@functions{
    [Parameter]
    private string ToChild{get;set;}
    [Parameter]
    Action<string> FromChild{get;set;} 
    
    private string childString;
    
    private void PassToParent()
    {
        childString = ToChild + "- To Parent";
        FromChild(childString);
    }
}

The FromChild attribute / attribute in the ChildComponent passes values from the child component to the parent component with the action < string > type. There is a response function with string type parameters in the parent component. The button click operation in the ChildComponent component triggers this function, and in turn notifies the PassToParent function. In order to notify the parent component that the state has changed, we use the razor built-in function StateHasChanged().

Method 2

This method uses the EventCallback data type to specify event changes to pass information instead of specific data. There is no need to call the StateHasChanged() function here.

//ParentComponent.razor
<h3> Parent Component</h3>
<p>Logging Event triggered from Child: @logString</p>

<ChildComponent 
        Trigger=@TriggerFromChild>    
</ChildComponent>

@functions{
    private string logString = "";
    private void TriggerFromChild(UIMouseEventArgs e)
    {
        logString = e.ToString();        
    }
}
//ChildComponent.razor
<h4>Child Component</h4>
<button onclick="@Trigger">Trigger Parent</button>

@functions{
    [Parameter]
    private EventCallback<UIMouseEventArgs> Trigger { get; set; }     
}

In ChildComponent, the Trigger property calls back the corresponding TriggerFromChild method with UIMouseEventArgs parameter in ParentComponent, and records it in the parent component as a string.

The following are the supported event parameters:

  • UIEventArgs
  • UIChangeEventArgs
  • UIKeyboardEventArgs
  • UIMouseEventArgs

Method 3

Here is another method of two-way binding between components. We can manually trigger an Action based on the execution of any event / method,

//ParentComponent.razor
<h3> Parent Component</h3>
<p>Logging Event triggered from Child: @logString</p>

<ChildComponent 
        EventFromChild=@TriggerFromChild>    
</ChildComponent>

@functions{
    private string logString = "";
    private void TriggerFromChild()
    {
        logString = "Triggered From Child using Action and Invoke";  
        StateHasChanged();      
    }
}
//ChildComponent.razor
<h4>Child Component</h4>
<button onclick="@Trigger">Trigger Parent</button>

@functions{
    [Parameter]
    private Action EventFromChild{get;set;}

    private void Trigger()
    {
        EventFromChild?.Invoke();
    }       
}

In the ChildComponent, manually trigger the EventFromChild Action property with the built-in function Invoke, and call back the corresponding TriggerFromChild method in the parent component. In the parent component, notify the state has changed through StateHasChanged().

Cascade values and parameters

Blazor provides a way to pass data across the entire RenderTree (all components), using CascadingValue and CascadingParameter instead of passing component properties. The value passed can be received by RenderTree (sub component) instead of Parameter through the decorative attribute CascadingParameter.

//RootComponent.razor
@page "/base-component"
<h3> App Base Component</h3>

<CascadingValue Value="@pName" Name="ProfileName">
    <CascadingValue Value="@pAge" Name="ProfileAge">
        <ParentComponent/>
    </CascadingValue>    
</CascadingValue>

@functions {
    private string pName {get;set;} = "New To Blazor";
    private int pAge {get;set;} =  35;
}
//ParentComponent.razor
<h3> Parent Component</h3>
<p> Profile Name is : @Name  and Age is : @Age.ToString(); </p>

@functions{
    [CascadingParameter(Name = "ProfileName")] 
    string Name { get; set; }
    [CascadingParameter(Name = "ProfileAge")] 
    int Age {get;set;}
}

In CascadingParameter, the Name parameter must match the Name property of the component with CascadingValue. If we do not declare Name, the variable type in CascadingParameter matches the Value property in CascadingValue.

It is best to declare the Name parameter to avoid confusion, which is useful when the application grows in size.

Render clips, dynamic content

In addition to passing content from the parent component to the child component with attributes, content can also be passed in the tag element of the component, and can be rendered in the child component using the RenderFragment attribute.

Mode 1

ChildContent is the naming convention we need to use in the child component to obtain the content of the parent component,

//ParentComponent.razor
<h3> Parent Component</h3>
<ChildComponent>
    The line here is passed to child from Parent!!!
</ChildComponent>
//ChildComponent.razor
<h4>Child Component</h4>
<p>@ChildContent</p>

@functions{
    [Parameter]
    private RenderFragment ChildContent { get; set; }   
}

Mode 2

RenderFragment is mainly used for templating purposes and presents content based on the logic inside the sub component.

//ParentComponent.razor
<h3> Parent Component</h3>
<ChildComponent>
    <SampleText>
        <p>
            <b>Bold Text here!!!</b>
        </p>
    </SampleText>    
</ChildComponent>
//ChildComponent.razor
<h4>Child Component</h4>
<div>
    @for(var i = 1; i <= 3; i++)
    {
        <h5>Line No : @i</h5>
        <div>@SampleText</div>
    }
</div>

@functions{
    [Parameter]
    private RenderFragment SampleText { get; set; }   
}

At this time, SampleText is not an existing component, it is newly generated in the ChildComponent tag element in the parent component, and the same attribute named SampleText is declared in the child component.

The text in SampleText is rendered three times in the sub component, which is very helpful to create template components, tables, etc.

Tags: Blazor

Posted on Mon, 22 Nov 2021 22:30:02 -0500 by said_r3000