Blazor Component parameter should not be set outside of its component
Asked Answered
C

1

26

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?

Craniate answered 2/1, 2020 at 6:32 Comment(2)
Since .NET Core 3.1, you can put the content of your @code { ... } block into separate code-behind files. Makes it much cleaner.Altdorf
Correct way to mutate a component property in blazor: #59382288Slop
M
27

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); 
    }
}
Mallett answered 2/1, 2020 at 7:51 Comment(7)
Usually, I'm doing InvokeAsync(StateHasChanged).Altdorf
@UweKeim Thanks for your suggestion. InvokeAsync(StateHasChanged). is better. I'll update my code.Mallett
@itminus, using a method to change a parameter is considered a bad practice and should be avoided.Slop
@Slop Yes. I agree. The declarative way is always preferred. That being said, that is only an alternative walkaround when sometimes we have no way to pass the parameter in declarative way. For example, interact with a 3rd party library, e.g. a rich editor that exposes quite a lot of command.Mallett
@Slop I know this is late, but why is that a bad practice? Say I have a <Button> component that has a loading state, I thought having 2 methods like StartLoadingState and StopLoadingState makes sense. I'd appreciate it if you elaborate a little more or point me to some links on why this is a bad practice.Aurelio
Parameter properties should not be set (or mutate) through code because the OnParametersSet lifecycle methods won't get called. Only the parent component should set or mutate the child parameter properties. This also means that the parameter properties should not be mutated by the child component itself, which implies that parameter properties should not be bound to elements, as for instance an input Html element or C# objects that mutate their state.If you try to set the value of a parameter property outside of its parent component, you'll get the warning BL0005:Slop
Component parameters should not be set outside of their declared component. Sorry, but I can't redirect you to the requested sources. It is something I've gathered during the early stages of the development of Blazor in github. However, this is an excellent reading discussion: github.com/dotnet/aspnetcore/issues/…Slop

© 2022 - 2024 — McMap. All rights reserved.