v.a.v
v.a.v

Reputation: 65

Passing parameters to a Blazor component

I need pass a collection (or array) of parameters to my Blazor component. The parameters passing are Blazor components. The collection of parameters must be passed as a nested tag. It is necessary to be able to call the rendering of each passed parameter-component separately.

That is, I want something like this:

<MyComponent>
  <ParameterCollection>
    <MyParameterComponent1>Caption1</MyParameterComponent1>
    <MyParameterComponent2>Caption2</MyParameterComponent2>
    <MyParameterComponent3>Caption3</MyParameterComponent3>
  </ParameterCollection>
</MyComponent>

MyComponent code:

@code{
    [Parameter]
    public RenderFragment[] ParameterCollection {get; set;} //Runtime error
}

That I want to get is apparently implemented here commercial Blazor component (select the VIEW SOURCE tab). The GridColumns parameter is passed a collection of GridColumn components. More precisely, as I think, it is a collection of their corresponding RenderFragments. The question is how is it done?

Upvotes: 4

Views: 13176

Answers (2)

Kristian.mariyanov
Kristian.mariyanov

Reputation: 345

Blazor cannot get a collection of render fragment as parameters. Here are two different approaches you can pass dynamic components count as a parameter

  1. If you want just to pass multiple components but it's ok they to be rendered at the same order as you passing them:
<MyComponent>
    <ParameterCollection>
        <MyParameterComponent1>Caption1</MyParameterComponent1>
        <MyParameterComponent2>Caption2</MyParameterComponent2>
        <MyParameterComponent3>Caption3</MyParameterComponent3>
    </ParameterCollection>
</MyComponent>
@code{
    [Parameter]
    public RenderFragment ParameterCollection {get; set;} 
}

and you can just render them placing @ParameterCollection anywhere in your .razor file.

Here is a working example of this approach: https://blazorrepl.com/repl/QaFEadlQ52kWHVkX13

  1. When you want to have both dynamic components count and you want to have control over where they are placed.

In this approach you are using the component only to pass some metadata - similar to @Henk Holterman suggestion:

<MyComponent>
    <ParameterCollection>
        <MyParameterComponent1>Caption1</MyParameterComponent1>
        <MyParameterComponent2>Caption2</MyParameterComponent2>
        <MyParameterComponent3>Caption3</MyParameterComponent3>
    </ParameterCollection>
</MyComponent>
@code{
    [Parameter]
    public RenderFragment ParameterCollection {get; set;} 
}

in this way, you can just put the @ParameterCollection at the start of your .razor file wrapped in CascadingValue of the Parent component. This will trigger the rendering for all the child components.

In the init of each of the components you will need to trigger populating metadata to the parent:

@code {
    [CascadingParameter]
    private MyComponent Parent { get; set; }
    protected override void OnInitialized()
    {
        if (Parent != null)  Parent.AddChild(this);    
    }
}

After receiving the metadata, you just need to trigger rendering again and use this data in

Here is a working example: https://blazorrepl.com/repl/wuPOOxvd06vFcWFG21

Upvotes: 7

Henk Holterman
Henk Holterman

Reputation: 273691

Turn it around: the DatagGridColumnCollection component inserts itself as a CascadingValue and the DatagGridColumn components just call an Add method.

ColumnCollection

<CascadingValue Value="this">
  @ChildContent
</CascadingValue>

@code
{ 
    public void Add(DataGridColumn colum) { ... }
}

DataGridColumn

@code {
  [CascadingParameter]
  private ColumnCollection Parent { get; set; }
  protected override void OnInitialized()
  {
    if (Parent != null)  Parent.Add(this);    
  }
}

Upvotes: 5

Related Questions