Reputation: 42229
Assume Row
is a component like so:
<div class="row">
<div class="col-6">
@Column1
</div>
<div class="col-6">
@Column2
</div>
</div>
@code
{
[Parameter]
public ComponentBase Column1 { get; set; }
[Parameter]
public ComponentBase Column2 { get; set; }
}
Then assume that we use this like so:
<Row Column1="foo" Column2="foo"></Row>
@code {
private readonly SomeComponent foo = new();
private readonly SomeComponent bar = new();
}
I'd expect a row containing two columns containing the rendered components for foo
and bar
, but instead I get two columns containing "Example.Shared.Components.SomeComponent"
How then do you render sub-components passed into other components? Is there a better way to do this (i.e. something like ng-content
in Angular?
As a side note, I'm looking for solutions that allow this programatically (as above), and using markup (as below):
<Row>
<Column>
<Foo></Foo>
</Column>
<Column>
<Bar></Bar>
</Column>
</Row>
Upvotes: 1
Views: 361
Reputation: 273179
What you want is templated components
You still can't use SomeComponent foo = new();
.
Instantiation is left to the renderer. But consider that a good thing, it lets you slip in an (item) context.
You'll also want to look at Cascading values, to expose the Row to the Columns.
And finally, there are plenty of commercial and Open versions of a Blazor DataGrid out there. Don't reinvent the whole wheel.
Upvotes: 2
Reputation: 4208
I'd recommend not thinking of filling objects with data and passing the objects around. I'd think of Components as the expression of existing data into the html space. Note how for each layer of data, I have nested Razor components. So you pass DATA into the Table
component, not RenderFragments
or any other kind of object. The following is simplified for clarity.
class TableData {
public List<RowData> Rows;
}
class RowData {
public List<ColumnData> Columns;
}
class ColumnData {
public string DisplayString;
}
TableComponent.razor
@foreach (var row in TableData.Rows){
<DataRowComponent Data=row />
}
@code {
[Parameter]
public TableData TableData{get; set;}
}
DataRowComponent.razor
@foreach (var column in Data.Columns ){
<DataColumnComponent Data=column />
}
@code {
[Parameter]
public RowData Data {get; set;}
}
DataColumnComponent.razor
<div>
@Data.DisplayString
</div>
@code {
[Parameter]
public ColumnData Data {get; set;}
}
Upvotes: 1
Reputation: 30001
How about:
<div class="row">
<div class="col-6">
@Column1
</div>
<div class="col-6">
@Column2
</div>
</div>
@code
{
[Parameter]
public RenderFragment Column1 { get; set; }
[Parameter]
public RenderFragment Column2 { get; set; }
}
And then:
<Row>
<Column1>
<SomeComponent value="@somevalue"/>
</Column1>
<Column2>
<SomeOtherComponent/>
</Column2>
</Row>
As already stated, the Renderer instantiates all components and attaches them to the RenderTree.
Also note that all components don't necessarily inherit from ComponentBase
, but they do all implement IComponent
.
Upvotes: 2
Reputation: 2080
Blazor is mostly declarative. So you should:
<Row>
<Column1>
<Foo></Foo>
</Column1>
<Column2>
<Bar></Bar>
</Column2>
</Row>
You don't need to do new Foo() / new Bar()
Of course, you can take the very circuitous route of programmatically populating the RenderFragment
. But it is generally not worth it. Instead, use Generic components and Polymorphism.
Upvotes: 1