asp.netasp.net-coreblazorrazor-components

Blazor Component parameter should not be set outside of its component


I am learning Blazor. I have no experience with component-based programming.

I have two components: a DateRangePicker and a RadzenCheckBox.

<RadzenFieldset Text="Test Component">
    <DateRangePicker @ref="calendar" />
    <div>
        <Radzen.Blazor.RadzenCheckBox TValue="bool" Change="@((args) => txtBoxChange(args))" />
        <RadzenLabel Text="Check" />
    </div>
</RadzenFieldset>

Now, the requirement is simple. If the checkbox is clicked, show two calendars and show one calendar if it's unchecked.

I wrote the following code:

@code{
    DateRangePicker calendar;

    public void txtBoxChange(bool args) 
    {
        if (args == true) //shows one calendar when checked
            calendar.ShowOnlyOneCalendar = true;
        else //shows two calendars when unchecked
            calendar.ShowOnlyOneCalendar = false;
    }
}

This works fine.

But I get a warning:

Component parameter 'ShowOnlyOneCalendar' should not be set outside of its component.

I have read some blogs about this warning, which suggest making parent and child component relationship for communication between components. But these are not parent and child.

What am I doing wrong? What is the best way to achieve such a requirement and not have this warning?


Solution

  • What am I doing wrong?

    Instead of using an imperative programming (component.Parameter1=v1) way, a Component Parameter is supposed be passed in a declarative syntax :

    <Component Parameter1="@v1"  Parameter2="@v2" />
    

    Note that you're assigning values to [Parameter] directly:

    calendar.ShowOnlyOneCalendar = true;
    

    That's why Blazor complains. In other words, you need change it in following way:

    <DateRangePicker ShowOnlyOneCalendar="@showOnlyOne"  />
    

    How to fix

    Always follow this pattern like other SPA:

          (render)
    Data -----------> View
    

    For example, your code could be rewritten as below:

    <DateRangePicker ShowOnlyOneCalendar="@flag" />
    ...
    
    @code{
        private bool flag = false;
        public void txtBoxChange(bool args)=> flag = args;
    }
    

    (Here we have a flag data, and we should render the view according to the data)

    Or if you do want to use an imperative programming way, you need to invoke a method and avoid assigning values to the [Parameter] properties directly.

    <DateRangePicker @ref="calendar" />
    ...
    
    
    @code{
        DateRangePicker calendar;
        public void txtBoxChange(bool args) 
        {
             calendar.A_Wrapper_Method_That_Changes_The_Parameter(args);
             // as suggested by @Uwe Keim, 
             //    `InvokeAsync(StateHasChanged)` is better than `StateHasChanged()`
             InvokeAsync(StateHasChanged); 
        }
    }