Live Chat Icon For mobile
Live Chat Icon

Blazor FAQ - Components

Find answers for the most frequently asked questions
Expand All Collapse All

SCSS, also known as Sassy CSS, is a CSS advancement that includes advanced features. It is more expressive, loads faster, uses fewer lines of code, and encourages proper rule nesting. It has all of the features of CSS and more, making it a good choice for developers to use. It is an SASS-specific file, similar to CSS, but with improved formatting.

To style your Blazor components with SCSS, follow these steps:

  1. Create a Blazor WebAssembly application by referring to this link.

  2. Create a new folder named TowerRange, and inside it, create TowerRange.razor, a new Blazor component, and define it as shown.
    [TowerRange.razor]

     <div class="tower">
        <div class="tower-range @BackgroundStyle"
             style="height: @Height"
             aria-valuenow="@CurrentValue"
             aria-valuemin="0"
             aria-valuemax="80">
        </div>
    </div>
     
    @code
    {
        [Parameter]
        public int CurrentValue { get; set; }
     
        [Parameter]
        public BackgroundColor Color { get; set; } = BackgroundColor.LightGrey;
     
        public enum BackgroundColor { LightGrey, MediumGrey, DarkGrey }
     
        private string BackgroundStyle => $"BackColor-{Color.ToString()}";
     
        private string Height => $"{CurrentValue}%";
    }

  3. Create a new SCSS file named TowerRange.scss inside the TowerRange folder and specify the style required for the TowerRange component as shown in the following.
    [TowerRange.scss]

       .tower {
        width: 15px;
        height: 200px;
        background-color: #fff;
        position: relative;
    }
     
    .tower-range {
        width: 100%;
        display: block;
        font-family: arial;
        font-size: 12px;
        background-color: white;
        color: #fff;
        position: absolute;
        bottom: 0;
    }
     
    $BackColor-LightGrey: #d4d3d2;
    $BackColor-MediumGrey: #8f9194;
    $BackColor-DarkGrey: #585959;
     
    .BackColor {
        &-LightGrey {
            background-color: $BackColor-LightGrey;
        }
     
        &-MediumGrey {
            background-color: $BackColor-MediumGrey;
        }
     
        &-DarkGrey {
            background-color: $BackColor-DarkGrey;
        }
    }

  4. Add the following code in the Helper.scss in the Shared folder to provide custom styles for the TowerRange component’s appearance in the Index.razor main page.
    [Helper.scss]

      .marginStyle {
        margin-left: 2px;
        display: inline-block;
    }

     

  5. To combine all SCSS files, create an App.scss file in the main application and add the following code.
    [App.scss]

      @import 'TowerRange/TowerRange';
    @import 'Shared/Helper';
     

  6. Now, follow this link to install the Web Compiler extension and restart Visual Studio. After restarting, right-click App.css and select Web Compiler > Compile File. The compilerconfig.json file will be generated under the main application. Add the following code to the compilerconfig.json file.  

      [
      {
        "outputFile": "wwwroot/css/site.css",
        "inputFile": "App.scss",
        "minify": {
          "enabled": true
        },
        "options": {
          "sourceMap": true
        }
      }
    ]
     

  7. Insert the site.css file created by the Web Compiler into the index.html page.

          <head>
        …………………….
        <link href="css/site.css" rel="stylesheet" />
    </head>

  8. To run Web Compiler during the build action (F5), install a NuGet package, or right-click compilerconfig.json and select Web Compiler > Enable compile on build, which automatically installs this NuGet package.  

     <Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
                 …………………….
                 …………………….
                <ItemGroup>
                            <Content Remove="compilerconfig.json" />
                </ItemGroup>
     
                <ItemGroup>
                            <None Include="compilerconfig.json" />
                </ItemGroup>
     
                <ItemGroup>
                            <PackageReference Include="BuildWebCompiler" Version="1.12.394" />
                            <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.10" />
                            <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.10" PrivateAssets="all" />
                            <PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
                </ItemGroup>
     
    </Project>
     

  9. Add the TowerRange component to the Index.razor page, as shown in the following.

    @page "/"
     
    @using SCSS.TowerRange;
     
    <h1> Blazor component styling with SCSS </h1>
     
    <div class="marginStyle">
        <TowerRange CurrentValue="20" Color="TowerRange.BackgroundColor.DarkGrey" />
    </div>
     
    <div class="marginStyle ">
        <TowerRange CurrentValue="40" Color="TowerRange.BackgroundColor.MediumGrey" />
    </div>
     
    <div class="marginStyle ">
        <TowerRange CurrentValue="60" Color="TowerRange.BackgroundColor.LightGrey" />
    </div>

    When you run the application, you will see the following output.
    Output

Permalink

CORS stands for cross-origin resource sharing, and it is an HTTP header-based mechanism that allows the server to tell the browser whether to accept a request from a domain, port, or scheme other than its own. It is based on a process in which the browser sends a “preflight” request to the server, and the server responds with response headers indicating whether the request can proceed or not. The browser will either succeed or fail the request based on what these headers say. The browser sends headers that indicate the HTTP method and headers that will be used in the actual request in the preflight request.

To enable CORS in your Blazor Server application, follow these steps:

  1. Create a new Blazor Server application in Visual Studio 2019 by following this link.

  2. Once the application has been created, in the Startup.cs file, call the AddCors method under ConfigureServices to add the cross-origin resource sharing services to the service collection. To add a new policy to the configuration, call the AddPolicy within the AddCors method.
    [Startup.cs]

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
        services.AddServerSideBlazor();
        services.AddCors(options =>
        {
            options.AddPolicy("NewPolicy", builder =>
             builder.AllowAnyOrigin()
                          .AllowAnyMethod()
                          .AllowAnyHeader());
        });
    }

  3. Under the Configure method in the Startup.cs file, call the UseCors method and pass the appropriate policy name to add the CORS middleware to the application pipeline.
    [Startup.cs]

    public void   Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        …………………..
        app.UseRouting();
        app.UseCors("NewPolicy");
        app.UseAuthorization();
        …………………..
    }

Note: Call the UseCors method between the UseRouting and UseAuthorization methods.

View Sample in GitHub

Permalink

The AddDefaultPolicy method allows you to add a new policy to the CORS configuration and make it the application’s default. In the Startup.cs file, call the AddCors method under the ConfigureServices to add the cross-origin resource sharing services to the service collection. To add a default policy to the configuration, call the AddDefaultPolicy within the AddCors method.

[Startup.cs]

public void ConfigureServices(IServiceCollection services)
{
    ………….. . . .
    services.AddCors(options =>
    {
        options.AddDefaultPolicy (builder =>
         builder.AllowAnyOrigin()
                      .AllowAnyMethod()
                      .AllowAnyHeader());
    });
}

Since we are using the default policy, we do not need to include the policy name in the UseCors method, as shown.

[Startup.cs]

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ………….. . . . 
    app.UseRouting();
    app.UseCors();
    app.UseAuthorization();
}

The AddPolicy method allows you to add a custom policy to the CORS configuration and give it a name so that it can be identified. In the Startup.cs file, call the AddCors method under ConfigureServices to add the cross-origin resource sharing services to the service collection. To add a user-defined (custom) policy to the configuration, call AddPolicy within the AddCors method.

 [Startup.cs]

public void ConfigureServices(IServiceCollection services)
{
    …………… . . .
    services.AddCors(options =>
    {
        options.AddPolicy("NewPolicy", builder =>
         builder.WithOrigins("https://localhost:8080")
                      .AllowAnyHeader()
                      .WithMethods("GET");
    });
}

Under the Configure method in the Startup.cs file, call the UseCors method and pass the user-defined (custom) policy name to add the CORS middleware to the application pipeline.

[Startup.cs]

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ………….. . . .
    app.UseRouting();
    app.UseCors("NewPolicy");
    app.UseAuthorization();
}

Note: Call the UseCors method between the UseRouting and UseAuthorization methods.

Permalink

To use two-way binding in a Blazor component, add the bind attribute to a field. Two-way data binding pushes the changes to the component, gets the data from the component end, and updates its own data accordingly.

In the following example, we created a Select component and implemented two-way binding to the parent component.

Create a Select component in the Pages folder.

[SelectComponent.razor]

<div>
    <select id="Item" class="form-control-sm" @bind="@ListItem">
        @foreach (var list in SelectList)
        {
            @if (ListItem != null && String.Equals(list, ListItem, StringComparison.OrdinalIgnoreCase))
            {
                <option selected value="@list">@list</option>
            }
            else
            {
                <option value="@list">@list</option>
            }
        }
    </select>
</div>

@code {
    public IEnumerable<string> SelectList = new List<string>()
    {
        "List 1",
        "List 2",
        "List 3",
        "List 4",
        "List 5"
     };

    private string listItem { get; set; }

    [Parameter]
    public string ListItem
    {
        get { return listItem; }
        set {
            if (listItem != value)
            {
                listItem = value;
                if (ListItemChanged.HasDelegate)
                {
                    ListItemChanged.InvokeAsync(value);
                }
            }
        }
    }

    [Parameter]
    public EventCallback<string> ListItemChanged { get; set; }
}

Now define the Select component to in the Index.razor page and implement the two-way binding using the @bind attribute.

[Index.razor]

@page "/"

<div>
    <label>Bind Value</label>
    <input type="text" @bind="@Content" @bind:event="oninput" />
    <p>@Content</p>
</div>

<div>
    <SelectComponent @bind-ListItem="@Content" />
</div>

@code {
    [Parameter]
    public string Content { get; set; } = string.Empty;

}

Refer to this link for more details.

View Sample in GitHub

Permalink

By using browser storage in Blazor, we can save and load data within a component. The following example demonstrates that the counter value is updated with a button click and the count value stored in local storage. When you refresh the page, the saved data will load from the browser local storage.

[Index.razor]

@page "/"
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedLocalStorage LocalStorage

@if (isCount)
{
    <p>Current count: <strong>@currentCount</strong></p>
    <button class="btn btn-primary" @onclick="IncrementCount">Increment</button>
}
else
{
    <p>Loading...</p>
}

@code {
    private int currentCount;
    private bool isCount;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            isCount = true;
            // Get the count value into browser local storage.
            var countValue = await LocalStorage.GetAsync<int>("countValue");
            // Loaded the browser local storage value to currentCount.
            currentCount = countValue.Success ? countValue.Value : 0;
            StateHasChanged();
        }
    }

    private async Task IncrementCount()
    {
        currentCount++;
        // Set the count value in browser local storage.
        await LocalStorage.SetAsync("countValue", currentCount);
    }
}

Refer to this link for more details.

Permalink

Using MVC in a Blazor application is not yet possible, but we have an option to migrate an existing ASP.NET MVC application to a Blazor Server application.

Permalink

To get the page referrer of where the user came from, follow these steps:

  1. Create a JavaScript function as a separate file in your application (~/wwwroot/interop.js).

    function getPageReferrer()
     {
        return document.referrer;
    }

  2. Add the script reference in the ~/wwwroot/index.html file of the Blazor WebAssembly application.

     <script src="~/interop.js"></script> 

  3. Invoke the JavaScript function using the IJSRuntime service in a Razor page.

     @page "/"
    @inject IJSRuntime JSRuntime
    @code {
    protected override async Task OnInitializedAsync()
    {
    var pageReferrer = await jJSRuntime.InvokeAsync<string>("getPageReferrer");
    }
    }


    View Sample in GitHub

Permalink

RenderFragment is a delegate that renders a UI segment. So, it does not have an Empty state. It can be null, which is equivalent to empty in the sense that it will produce no rendered output. In the following example, see that the RenderFragments are in a null state or contain a value.

@if (childContent != null) 
{ 
    <p>@childContent</p> 
} 
else 
{ 
    <p>RenderFragment is null</p> 
} 
  
<button class="btn btn-primary" @onclick="OnButtonClick">Click</button> @*RenderFragment is null by default, click the button to update the RenderFragment*@ 
  
@code { 
    private string textContent = "Welcome to your new Blazor app."; 
    private RenderFragment childContent { get; set; } 
     
    private void OnButtonClick() 
    { 
        childContent = BuildRenderTree => BuildRenderTree.AddContent(1, textContent); 
    } 
} 
Permalink

RenderFragment is used to render components or content at run time in Blazor. The RenderFragment class allows you to create the required content or component in a dynamic manner at runtime. In the following code example, the content is created at runtime on OnInitialized.

[Index.razor]

@page "/"

@childContent

@code {
    private string textContent = "Welcome to your new Blazor app.";
    private RenderFragment childContent { get; set; }

    private RenderFragment AddContent() => builder =>
    {
        builder.AddContent(1, textContent);
    };

    protected override void OnInitialized()
    {
        childContent = AddContent();
    }
}

Refer to ASP.NET Core Blazor templated components” for more details.

Permalink

Blazor considers each .razor file as a new component. The component class is usually written in the form of a Razor markup page. So, you can create a new component and reuse it across the application. In the following example, a Blazor component is created in the Components folder and used in the Index.razor page.

[BlazorComponent.razor]

<h1>@blazorHeader</h1>

    <div class="card card-body" style="width: 18rem;">
        <h5><b>@pageName</b></h5>
        <p>@pageDescription</p>
    </div>

    @code {
        private string blazorHeader = "Blazor App!";
        private string pageName = "Blazor Page";
        private string pageDescription = "Blazor component is created";
    }

[Index.razor]

@page "/"
@using BlazorApp1.Components

<BlazorComponent></BlazorComponent>

Please refer to this documentation for more information.

Permalink

You can use data-annotation to apply the regular expression for limiting the characters and numbers in blazor app.

In the following code, allow the char and numbers in textbox component. The RegularExpression attribute validates that the property value matches a specified regular expression.

<EditForm Model="@model" OnValidSubmit="handleSubmit">
    <DataAnnotationsValidator></DataAnnotationsValidator>
    <InputText @bind-Value="@model.Name"></InputText>
    <ValidationMessage For="()=>model.Name"></ValidationMessage>
    <button type="submit">submit</button>
</EditForm>

@code {

    private Countries model = new Countries();

    public class Countries
    {
        [Required]
        [RegularExpression(@"^[a-zA-Z0-9 ]+$", ErrorMessage = "Special characters are not accepted.")]
        public string Name { get; set; }
    }
Permalink

The RenderTreeBuilder class will let you create required content or component in dynamic manner at runtime. In the following code example, the Input TextBox Component has been created at runtime through button click.

<div id="component-container">
    @DynamicRender
</div>

<button @onclick="RenderComponent">Render TextBox</button>

@code {
    private RenderFragment DynamicRender { get; set; }

    private RenderFragment CreateComponent() => builder =>
    {
        builder.OpenComponent(0, typeof(InputText));
        builder.AddAttribute(1, "Placeholder", "Enter your text");
        builder.CloseComponent();
    };

    private void RenderComponent()
    {
        DynamicRender = CreateComponent();
    }
}

Permalink

Override the ShouldRender method  to suppress UI rendering. If the implementation returns true, the UI is refreshed. Initial rendering cannot be prevented using this method.

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
 
@code {
    private int currentCount = 0;
    private bool shouldRender = true;
 
    private void IncrementCount()
    {
        shouldRender = false;
        currentCount++;
    }
 
    protected override bool ShouldRender()
    {
        return shouldRender;
    }
}

More information about suppressing UI rendering can be found here.

Permalink

Components should be disposed properly to avoid memory leak and allow proper garbage collection.  Managed resources used by the application will be disposed by the Blazor framework itself.

If a component implements IDisposable, the Dispose method will be called when the component is removed from the UI. You can use Dispose method to release unmanaged resources, unhook events, dispose DotNetObjectReference instances to avoid memory leak.

Refer to the following code sample.

@implements IDisposable
@inject IJSRuntime jsRuntime
 
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
 
@code { 
 
    DotNetObjectReference<HelloClass> dotNetObject { get; set; }
 
    protected override void OnInitialized()
    {
        dotNetObject = DotNetObjectReference.Create<HelloClass>(new HelloClass());
    }
 
    async Task IncrementCount()
    {
        await jsRuntime.InvokeVoidAsync("MyJavaScriptFunction", new object[] { dotNetObject });
    }
 
    void IDisposable.Dispose()
    {
        dotNetObject?.Dispose();
    }
}
 
@code{
 
    public class HelloClass
    {
        [JSInvokable]
        public void CustomMethod() { }
    }
}

More information about component disposal can be found here.

Permalink

String values are normally converted in DOM text notes. To render encode string values as raw HTML you need to wrap the string value in a MarkupString. This will encode the given string value HTML/SVG and place it in the given location.

Refer to the following code sample.

@((MarkupString)RawString)
 
@code {
    public string RawString = "<span style='color:red'>Blazor is awesome</span>";
}
Permalink

Blazor applications are based on components. A component in Blazor is an element of UI, such as a page, input, and dialogs. The component class is usually written in the form of a Razor markup page with a .razor file extension. Components in Blazor are formally referred to as Razor components.

You can render the component at runtime using RenderFragment. The RenderFragment class allows you create the required content or component in a dynamic manner at runtime. In the following code example, the Input text Component is created at runtime on button click.

<div id="component-container">
    @DynamicRender
</div>

<button @onclick="RenderComponent">Dynamic Component</button>

@code {

    private RenderFragment DynamicRender { get; set; }

    private RenderFragment CreateComponent() => builder =>
    {
        builder.OpenComponent(0, typeof(TextBox));
        builder.AddAttribute(1, "Title", "Enter your text");
        builder.CloseComponent();
    };
}

[TextBox.razor]

<input placeholder="@Title" />

@code {

    [Parameter]
    public string Title { get; set; }
}

Permalink

You can create custom components in Blazor and reuse them across the application. You can also create a razor component in a shared or custom folder, and define it. Then, the custom component like HTML tag (FileName) can be used in the application.

[HeaderComponent.razor]

@using System.Globalization

<h1 style="font-weight:@fontweight !important">@_headingText</h1>

<form>
<div>
     <input type="checkbox" id="fontweight"
               @bind="bold" />
      <label class="form-check-label"
               for="italicsCheck">Use Bold</label>
</div>

<button type="button" class="btn btn-primary" @onclick="UpdateHeading">
        Update Font</button>
</form>

@code {
    private static TextInfo _tinfo = CultureInfo.CurrentCulture.TextInfo;
    private string _headingText =
        _tinfo.ToTitleCase("welcome to blazor!");
    private string _headingFontStyle = "normal";
    private bool bold = false;
    private int fontweight = 500;
    public void UpdateHeading()
    {
        //weight = 900;
        fontweight = bold ? 900 : 500;
    }
}

 //parent component

[index.razor]

@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

<HeaderComponent />

In the above example, the header component is used in the index page. Similarly, the component can be shared across the application as a HTML tag to improve code reusability.

Permalink

We can define specific instances for custom components by using @ref while defining the component in a Razor file.

In this sample, we have created the component reference for the card components with specific names. Using this reference, we can access the card component properties and modify them. Here we have changed the display property using the component reference.

[Card.razor]
<div class="card mb-3 @display" style="width: 18rem;">
 <div class="card-body">
      @ChildContent
 </div>
</div>

@code {
    string display = "";

    [Parameter]
    public RenderFragment ChildContent { get; set; }

    public void setVisible(bool visible)
    {
        if (visible)
        {
            display = "";
        }
        else
        {
            display = "d-none";
        }
    }
}
[index.razor]

@page "/"

<Card @ref="MyCardControl1">First Card</Card>

<Card @ref="MyCardControl2">Second Card</Card>

<button class="btn btn-primary" @onclick="Hide">Hide card</button>
<button class="btn btn-primary" @onclick="Show">Show card</button>

<button class="btn btn-primary" @onclick="Hide2">Hide card2</button>
<button class="btn btn-primary" @onclick="Show2">Show card2</button>
@code {

    Card MyCardControl1;
    Card MyCardControl2;

    private void Hide()
    {
        MyCardControl1.setVisible(false);
    }
    private void Show()
    {
        MyCardControl1.setVisible(true);
    }

    private void Hide2()
    {
        MyCardControl2.setVisible(false);
    }
    private void Show2()
    {
        MyCardControl2.setVisible(true);
    }
}
Permalink

Currently there is no direct Canvas support in WebAssembly. In order to draw using Canvas, you can use the third-party, free Blazor.Extensions.Canvas library. Add Blazor.Extensions.Canvas NuGet to your project and add the following code snippet to draw a rectangle. It draws shapes in Blazor with the reference that is created for the Canvas element in the Razor page.

[index.html/_host.cshtml]
<head>

 <script src="_content/Blazor.Extensions.Canvas/blazor.extensions.canvas.js"></script>

</head>
[index.razor]

@page "/"
@using Blazor.Extensions; 
@using Blazor.Extensions.Canvas
@using Blazor.Extensions.Canvas.Canvas2D;

<BECanvas Width="300" Height="400" @ref="_canvasReference"></BECanvas>

@code {
    private Canvas2DContext _context;

    protected BECanvasComponent _canvasReference;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        this._context = await this._canvasReference.CreateCanvas2DAsync();
        await this._context.SetFillStyleAsync("red");

        await this._context.FillRectAsync(10, 100, 100, 100);

        await this._context.SetFontAsync("38px Calibri");
        await this._context.StrokeTextAsync("Hello Blazor!!!", 5, 100);
 }
}
Permalink

To load a dialog on demand in Blazor, we can create a modal dialog with a conditional attribute (@if). We can load the dialog in the HTML page by using the conditional attribute, which will render based on the Boolean property.
In the following code, we render the dialog on a button-click event in which the ShowPopup property will be set as true and the dialog will be shown on the page. We can remove the dialog by setting the ShowPopup property as false.

[index.razor]

@page "/"

@using BlazorApp.Data
@inject WeatherForecastService ForecastService

<h3>Dialog</h3>
<button class="btn btn-primary"
        @onclick="OpenDialog">
    Open Dialog
</button>
@if (ShowPopup)
{
    <!-- This is the popup to create or edit a forecast -->
    <div class="modal" tabindex="-1" style="display:block" role="dialog">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h3 class="modal-title">Modal Dialog</h3>
                    <!-- Button to close the popup -->
                    <button type="button" class="close"
                            @onclick="ClosePopup">
                        <span aria-hidden="true">X</span>
                    </button>
                </div>
                <!-- Edit form for the current forecast -->
                <div class="modal-body">
                    <input class="form-control" type="text"
                           placeholder="Celsius forecast"
                           @bind="forecasts[0].TemperatureC" />
                    <input class="form-control" type="text"
                           placeholder="Summary"
                           @bind="forecasts[0].Summary" />
                    <br />
                    <!-- Button to save the forecast -->
                    <button class="btn btn-primary"
                            @onclick="Save">
                        Save
                    </button>
                </div>
            </div>
        </div>
    </div>
}
@code {

    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {

        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
    }
    bool ShowPopup = false;
    void OpenDialog()
    {
        // Open the Popup
        ShowPopup = true;
    }
    void ClosePopup()
    {
        // closes the Popup
        ShowPopup = false;
    }
    void Save()
    {
        //closes dialog after the save execution
        ShowPopup = false;
    }
}
Permalink

We can get child component values in the parent component by creating a reference to the child component using the @ref directive in the Parent component. Using the reference instance, you can access the child component values in the parent.

In the following example, textbox refers to the TextBoxComponent (child component) instance. Using textbox, we can access the properties and values in the Parent component.

[TextBoxComponent.razor]

<div class="form-group row mb-2">
    <label class="col-md-3 col-form-label"
           for="Name">@FieldName</label>
        <div class="col-md7">
            <input class="form-control"
                   type="text"
                   placeholder="@FieldName" value="@Value" @oninput="OnValueChanged" maxlength="@MaxLength" />
        </div>
    </div>

    @code {
        [Parameter]
        public string Value { get; set; }

        [Parameter]
        public string FieldName { get; set; }

        [Parameter]
        public int MaxLength { get; set; } = -1;

        [Parameter]
        public EventCallback<string> ValueChanged { get; set; }

        string LengthString;
        int TextLength;

        protected override void OnInitialized()
        {
            TextLength = Value.Length;
            LengthString = (MaxLength == -1) ? "Unlimited" : MaxLength.ToString();
        }

        private Task OnValueChanged(ChangeEventArgs e)
        {
            Value = e.Value.ToString();
            TextLength = Value.Length;
            return ValueChanged.InvokeAsync(Value);
        }
    }
[Parent.razor]

@page "/parent"

<TextBoxComponent @ref="textbox" @bind-Value="name" FieldName="Name" MaxLength="20" />
<TextBoxComponent @bind-Value="address" FieldName="Address" />
<button @onclick="Click">Click </button>
@code {
    TextBoxComponent textbox;
    string name = "Rafael Nadal";
    string address = "New York";
    private void Click()
    {
        var fNme = textbox.FieldName;
        var maxLen = textbox.MaxLength;
    }
}  
Permalink

We can specify what event the bind attribute should use to handle updating the value. But, in components, we need to define the event in the child component, for example, the oninput event on the child component, which triggers a method to update the value and invokes the ValueChanged EventCallback. The parent component has also been updated to use bind-Value when passing its Value parameter to the child component.

In the sample, we’re able to type in the text box on the parent component, both the values will be updated on every input change since we have bound the oninput event.

[CustomInput.razor]

<input value="@Value" @oninput="@OnInputChange" />
<h4>Welcome to Blazor Application, @Value</h4>

@code {
    [Parameter]
    public string Value { get; set; }

    [Parameter]
    public EventCallback<string> ValueChanged { get; set; }
    private async Task OnInputChange(ChangeEventArgs args )
    {
        Value = (string)args.Value;
        await ValueChanged.InvokeAsync(Value);
    }
}
[Index.razor]

@page "/"

<CustomInput @bind-Value="@InputValue" @bind-Value:event="ValueChanged"></CustomInput>

@code { 
       public string InputValue = "Example";
}
Permalink

To create a reference for dynamically generated components in Blazor, use the dictionary to create the reference for dynamically created elements at runtime.

[index.razor]

@page "/"

@foreach (var id in identifiers)
{
    <button @ref="myComponents[id]" @onclick="onclick">@id</button>
}

@code {
    private List<string> identifiers = new List<string> { "Button1", "Button2", "Button3" };
    private Dictionary<string, ElementReference> myComponents = new Dictionary<string, ElementReference>();
    private void onclick(MouseEventArgs args)
    {
        var d = myComponents;
        var a = args;
    }
}

Permalink

To disable a button in Blazor after it is clicked, set the disabled property to true for the button element by binding the property. In the sample, the disabled property of a button element is set to true on button click.

<button class="btn btn-primary" disabled=@IsTaskRunning @onclick="Clicked" > @ButtonName</button>

@code {

    bool IsTaskRunning = false;
    string ButtonName = "Click Me";
    async void Clicked()
    {
        IsTaskRunning = true;
        ButtonName = "Disabled";
        await OnButtonClick();

        //IsTaskRunning = false; use this to enable the button after the button click function executed
        StateHasChanged();
    }

    Task OnButtonClick()
    {
        //here user can perform buton click function
        return Task.Delay(6000);
    }

}
Permalink

We can create elements dynamically in server-side Blazor applications by following this example.

@page "/render-fragment"
 
<button type="button" @onclick="@RenderComponent">
    Trigger rendering
</button>
 
@DynamicFragment
 
 
@code {
    private string dynamicContent = "This is a long text...";
    private RenderFragment DynamicFragment;
 
    private RenderFragment CreateComponent() => builder =>
    {
        dynamicContent = dynamicContent.Replace("long", "long long");
 
        builder.OpenElement(1, "p");
        builder.AddContent(2, dynamicContent);
        builder.CloseElement();
    };
 
    private void RenderComponent()
    {
        DynamicFragment = CreateComponent();
    }
}

Reference link

https://learn-blazor.com/pages/dynamic-content/

Permalink

When creating a cascading value, specify the name attribute in the CascadingValue component. Then specify the name in the child component.

Parent component

@page "/cascading"
 
<CascadingValue Value="@Id" Name="EmpId">
	<CascadingValue Value="@Name" Name="EmpName">
    	<CascadingChild></CascadingChild>
	</CascadingValue>
</CascadingValue>
 
@code{
	int Id = 1;
	string Name = "Test";
}

Child component

<p>Employee Id:@EmployeeId </p>
<p>Employee Name:@EmployeeName </p>
 
@code{
	[CascadingParameter(Name = "EmpId")]
	private int EmployeeId { get; set; }
	[CascadingParameter(Name = "EmpName")]
	private string EmployeeName { get; set; }
}

Reference link

https://chrissainty.com/understanding-cascading-values-and-cascading-parameters/

Permalink

Templated components are often generically typed. To define a generic component, use the @typeparam directive to specify type parameters

Generic template component

@typeparam TItem

<table class="table">
    <thead>
<tr>@TableHeader</tr>
    </thead>
    <tbody>
        @foreach (var item in Items)
        {
            <tr>@RowTemplate(item)</tr>
        }
    </tbody>
    <tfoot>
        <tr>@TableFooter</tr>
    </tfoot>
</table>

@code {
    [Parameter]
    public RenderFragment TableHeader { get; set; }

    [Parameter]
    public RenderFragment<TItem> RowTemplate { get; set; }

    [Parameter]
    public RenderFragment TableFooter { get; set; }

    [Parameter]
    public IReadOnlyList<TItem> Items { get; set; }
}

When using generically typed components, the type parameter is inferred if possible.

<GenericTemplate Items="@forecasts">
    <TableHeader>
        <th>Date</th>
        <th>Temp. (C)</th>
        <th>Temp. (F)</th>
        <th>Summary</th>
    </TableHeader>
    <RowTemplate Context="forecast">
        <td>@forecast.Date.ToShortDateString()</td>
        <td>@forecast.TemperatureC</td>
        <td>@forecast.TemperatureF</td>
        <td>@forecast.Summary</td>
    </RowTemplate>
</GenericTemplate>
@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
    }
}

Otherwise, the type parameter must be explicitly specified using an attribute that matches the name of the type parameter. In the following example, TItem=" WeatherForecast "specifies the type.

<GenericTemplate Items="@forecasts" TItem="WeatherForecast">
    <TableHeader>
        <th>Date</th>
        <th>Temp. (C)</th>
        <th>Temp. (F)</th>
        <th>Summary</th>
    </TableHeader>
    <RowTemplate Context="forecast">
        <td>@forecast.Date.ToShortDateString()</td>
        <td>@forecast.TemperatureC</td>
        <td>@forecast.TemperatureF</td>
        <td>@forecast.Summary</td>
    </RowTemplate>
</GenericTemplate>

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
    }
}

Reference: https://docs.microsoft.com/en-us/aspnet/core/blazor/templated-components?view=aspnetcore-3.1

Permalink

To pass values from a child to a parent component, see the following.

Parent component

[Parent.razor]
@page "/ParentComponent"

<h1>Parent Component</h1>

<ChildComponent @bind-Password="_password" />

@code {
    private string _password;
 }

Child component

[ChildComponent.razor]
<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;
    }
}

Reference link:  https://docs.microsoft.com/en-us/aspnet/core/blazor/data-binding#child-to-parent-binding-with-chained-bind

Permalink

When a cascading value is changed, the new value will be sent down the component tree and all components that use it will be updated. Therefore, Blazor has to keep a watch on the value continuously. This takes up resources and, in a large application, could end up causing performance issues.

If the cascading value will never change, we can stop keeping watch continuously. There is a IsFixed parameter in the CascadingValue component. It is set to false by default but if set it to true, Blazor will not monitor it for changes.

<CascadingValue Value="@Id" Name="EmpId" IsFixed="true">
	<CascadingValue Value="@Name" Name="EmpName" IsFixed="true">
    	<CascadingChild OnNameChange="@ChangeName"></CascadingChild>
    	<CascadingChild1></CascadingChild1>
	</CascadingValue>
</CascadingValue>

Reference link: https://chrissainty.com/understanding-cascading-values-and-cascading-parameters/

Permalink

The cascading values can be updated using an event, as in the following example.

Parent component

@page "/cascading"
 
<CascadingValue Value="@Id" Name="EmpId">
	<CascadingValue Value="@Name" Name="EmpName">
    	<CascadingChild OnNameChange="@ChangeName"></CascadingChild>
    	<CascadingChild1></CascadingChild1>
	</CascadingValue>
</CascadingValue>
 
@code {
	int Id = 1;
	string Name = "Test";
	private void ChangeName(string newName)
	{
    	Name = newName;
    	StateHasChanged();
	}
}

CascadingChild.razor

<p>Employee Id:@EmployeeId </p>
<p>Employee Name:@EmployeeName </p>
 
<button @onclick="@ChangeName">Change Name</button>
 
@code {
	[CascadingParameter(Name = "EmpId")]
	private int EmployeeId { get; set; }
	[CascadingParameter(Name = "EmpName")]
	private string EmployeeName { get; set; }
 
	[Parameter] Action<string> OnNameChange { get; set; }
 
	private void ChangeName()
	{
    	OnNameChange?.Invoke("Test2");
	}
}

CascadingChild1.razor

<p>Employee Id:@EmployeeId </p>
<p>Employee Name:@EmployeeName </p>
 
@code {
[CascadingParameter(Name = "EmpId")]
private int EmployeeId { get; set; }
[CascadingParameter(Name = "EmpName")]
private string EmployeeName { get; set; }
}

Reference link

https://chrissainty.com/understanding-cascading-values-and-cascading-parameters/

Permalink

Blazor will look at the type of the EmployeeId and EmployeeName parameters and try to find cascading values that match. In this case, EmployeeId will match Id and EmployeeName will match Name.

Parent component

@page "/cascading"
 
<CascadingValue Value="@Id">
	<CascadingValue Value="@Name">
    	<CascadingChild></CascadingChild>
	</CascadingValue>
</CascadingValue>
 
@code {
	int Id = 1;
	string Name = "Test";
}

Child component

<p>Employee Id:@EmployeeId </p>
<p>Employee Name:@EmployeeName </p>
 
@code {
	[CascadingParameter]
	private int EmployeeId { get; set; }
	[CascadingParameter]
	private string EmployeeName { get; set; }
}
Permalink

Cascading values and parameters are used to pass a value from a component to all its descendants without having to use traditional component parameters. Blazor comes with a special component called CascadingValue. This component allows whatever value is passed to it to be cascaded down its component tree to all of its descendants. The descendant components can then choose to collect the value by declaring a property of the same type, decorated with the [CascadingParameter] attribute.

Parent component

@page "/cascading"
 
<CascadingValue Value="@Name">
	<CascadingChild></CascadingChild>
</CascadingValue>
@code {
	string Name = "Steve";
}

Child component

<p>Employee Name:@Name </p>
@code {
	[CascadingParameter]
	private string Name { get; set; }
 }

Reference link:https://chrissainty.com/understanding-cascading-values-and-cascading-parameters/

Permalink

The better solution is to invoke the method in the set value of the parameter.

@code {

    string _myString;
    [Parameter]
    public string MyString
    {
        get {return _myString; }
        set {
            _myString = value;
            this.ValueChange();
        }

    }

    private void ValueChange()
    {
        Console.WriteLine("Parameter value has changed");
    }
}

You can also override the OnParameterSet or OnParameterSetAsync lifecycle methods. Those methods are triggered every time any parameter value changes.

@code
{
    [Parameter]
    protected string MyString {get;set;}

    protected override void OnParametersSet()
    {
        this.ValueChange();
    }
    private void ValueChange()
    {
        Console.WriteLine("Parameter value has changed");
    }
}
Permalink

You have to access the DOM elements in OnAfterRender or OnAfterRenderAsync of the Blazor component lifecycle.

[JS Helper]

window.methods = {    
    accessDOM: function () {
        // access DOM here
        $(".btn").text();
    }
}

[Razor]

@inject IJSRuntime JSRuntime

<button type="button" class="btn btn-primary">Submit</button>
@code{
    protected override void OnAfterRender(bool firstRender)
    {
        base.OnAfterRender(firstRender);
        JSRuntime.InvokeAsync<object>("methods.accessDOM");
    }
}

Have a look at the Blazor component lifecycle for more information.

Permalink

The component instance filed is populated along with the component after rendering completion. You must access the component instance in the OnAfterRenderAsync or OnAfterRender methods of the Blazor lifecycle.

@page "/"
  
 <Counter IncrementValue="10" @ref="counter"></Counter>
  
 @code {
  
     private Counter counter;    
  
     protected override void OnAfterRender()
     {
         base.OnAfterRender();
         counter.increase(); //access counter instance here
     }
 } 
Permalink

Component references are used to invoke methods from underlying components. Use the ref attribute for a component and define it filed with the same name and same type of component.

 @page "/"
  
 <Counter IncrementValue="10" @ref="counter"></Counter>
  
 @code {
  
     private Counter counter;    
  
 } 

While the Counter component is rendered, the field counter is populated along with the component instance.

For more information, refer to the link capture-references-to-components.

Permalink

Generally, we are using lambda expressions to create DOM elements dynamically like in the following code snippet.

<div class="buttons">
     @for (int i = 0; i < 5; i++)
     {
         <button type="button" class="btn btn-primary" onclick="@((e) => ButtonClicked(i))">Button @i</button>
     }
 </div> 

The lambda expressions access variables instead of their values. The button click is triggered with the number 5.

You have to include local variables while rendering the button element to properly get the index value of the clicked button element.

 

<div class="buttons">
     @for (int i = 0; i < 5; i++)
     {
         var index = i;
         <button type="button" class="btn btn-primary" onclick="@((e) => ButtonClicked(index))">Button @i</button>
     }
 </div>
 @code {
  
     private void ButtonClicked(int index)
     {
         Console.WriteLine("Button clicked with index:" + index);
     }
 } 

Permalink

The RenderFragment is used to create a component dynamically.

 @page "/"
  
 @CreateDynamicComponent();
 @code {
     RenderFragment CreateDynamicComponent() => builder =>
     {
         builder.OpenComponent(0, typeof(SurveyPrompt));
         builder.AddAttribute(1, "Title", "Some title");
         builder.CloseComponent();
     };
 } 

Permalink

Share with

Couldn't find the FAQs you're looking for?

Please submit your question and answer.