Blazor: Is it possible to trigger OnParametersSet method for a specific parameter?

173 views Asked by At

If there is a Blazor component and it has three parameters, is it possible to only trigger logic within OnParametersSet method when a specific one of the three parameters is changed? Is there a way to check which parameters were changed while inside OnParametersSet?

4

There are 4 answers

0
Qiang Fu On

You could try use c# properties {get;set;} to trigger an action when parameter is set. Try following: Child.razor

//disable prerender here, or prameter will set twice.
@rendermode @(new InteractiveServerRenderMode(false))

@Para1

@code {
    private string para1;
    [Parameter]
    public string? Para1 
    {
        get
        {
            return this.para1;
        }
        set
        {
            MyAction(); 
            para1 = value;
        } 
    }

    private void MyAction()
    {
        Console.WriteLine("action when para1 is set");
    }
}

Home.razor

@page "/"
<Child Para1="test"></Child>

Test
enter image description here

0
MrC aka Shaun Curtis On

You can do something like this in SetParametersAsync

    [Parameter] public int MessageId { get; set; }
    [Parameter] public string? Text { get; set; }

    private int _messageId;
    private bool _notFirstRender;

    public override Task SetParametersAsync(ParameterView parameters)
    {
        // You must consume parameters immediately
        parameters.SetParameterProperties(this);

        // short circuit if we've already rendered once and the messageid is the same
        if (this.MessageId == _messageId && _notFirstRender)
            return Task.CompletedTask;

        _messageId = this.MessageId;
        _notFirstRender = true;

        // Run the lifecycle events
        // Note passing on an empty ParameterView to the base.  We've already set them
        return base.SetParametersAsync(ParameterView.Empty);
    }

For a more general approach see this MS document - https://learn.microsoft.com/en-us/aspnet/core/blazor/performance?view=aspnetcore-8.0#implement-setparametersasync-manually

2
Ruikai Feng On

is it possible to only trigger logic within OnParametersSet method when a specific one of the three parameters is changed?

OnParametersSet is part of lifecycle events,I don't think it would be triggered without triggering other lifecycle events

Is there a way to check which parameters were changed while inside OnParametersSet?

You could check which parameter has changed within SetParametersAsync method:

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        foreach (var parameter in parameters)
        {
            var currentVal = this.GetType().GetProperty(parameter.Name)?.GetValue(this, null);
            var newVal = parameter.Value;
            // In some cases,you could set the properties one by one 
manually as mentioned in the document
            this.GetType().GetProperty(parameter.Name).SetValue(this, newVal);
        }
    
        await base.SetParametersAsync(ParameterView.Empty);
    }

A whole example:

Child component:

    <h1>@Title</h1>
    <p role="status">Current count: @Count</p>
    
    @code {
    
        [Parameter]
        public int Count{ get; set; }
        [Parameter]
        public string? Title { get; set; }
    
   

        public override async Task SetParametersAsync(ParameterView parameters)
    {
        foreach (var parameter in parameters)
        {
            var currentVal = this.GetType().GetProperty(parameter.Name)?.GetValue(this, null);
            var newVal = parameter.Value;
            this.GetType().GetProperty(parameter.Name).SetValue(this, newVal);
        }

    await base.SetParametersAsync(ParameterView.Empty);
}

    
    }

parent component:

<ChildComponent Count="@currentCount" Title="@title"></ChildComponent>

<button class="btn btn-primary" @onclick="IncrementCount">Count</button>
<button class="btn btn-primary" @onclick="Title">NewTitle</button>

@code {
    private int currentCount = 0;
    private string title = "MyTitle";

    private void IncrementCount()
    {
        currentCount++;
    }
    private void Title()
    {
        title = "NewTitle";
    }
}

Once I click Count button:

enter image description here

Once I click Title button:

enter image description here

0
pgsounds9006 On
  1. Using a prev field with the OnParametersSet() method
@page "/showcount1"
<span>@Count</span> <span>@Postfix</span>
@code {
    [Parameter] public int Count { get; set; }
    int prevCount;
    [Parameter] public string Postfix { get; set; } = "time(s)";

    protected override void OnParametersSet()
    {
        if (prevCount != Count)
        {
            prevCount = Count;
            AdditionalAction();
        }
    }
    void AdditionalAction() { }
}
  1. Overriding the SetParametersAsync() method
@page "/showcount2"
<span>@Count</span> <span>@Postfix</span>
@code {
    [Parameter] public int Count { get; set; }
    [Parameter] public string Postfix { get; set; } = "time(s)";

    public override async Task SetParametersAsync(ParameterView parameters)
    {
        // Get the value before it changes. This must be done before calling base.SetParametersAsync
        var countChanged = parameters.GetValueOrDefault<int>(nameof(Count)) != Count;
        
        await base.SetParametersAsync(parameters); // Use the default implementation to set parameters
        
        if (countChanged)
        {
            AdditionalAction();
        }
    }
    
    void AdditionalAction() { }
}