I have a class that represents the necessary data for creating a DynamicComponent
:
public class ComponentMetadata
{
public string? Name { get; set; }
public Dictionary<string, object> Parameters { get; set; } =
new Dictionary<string, object>();
}
I have a custom table component that uses ComponentMetadata
to add some dynamic component to the table:
TableTemplate.razor:
<table >
<thead>
<tr>@TableHeader</tr>
</thead>
<tbody>
@foreach (var RowTemplateConfig in RowTemplateConfigs)
{
if (RowTemplateConfig.DataItem is not null)
{
<tr>
<td> @RowTemplateConfig.DataItem </td>
@if(RowTemplateConfig.ComponentMetadata is not null)
{
<td>
<DynamicComponent
Type= RowTemplateConfig.ComponentMetadata.Name
Parameters= RowTemplateConfig.ComponentMetadata.Parameters />
</td>
}
</tr>
}
}
</tbody>
</table>
@code {
public class RowTemplateConfig
{
public ComponentMetadata ComponentMetadata { get; set;}
public string DataItem { get; set; }
}
[Parameter]
public RenderFragment? TableHeader { get; set; }
[Parameter]
public List<RowTemplateConfig> RowTemplateConfigs {get; set;}
}
I have also other custom components for example Button custom component:
MyButton.razor
<button type="button"
@onclick="BtnClick">
@Text
</button>
@code {
[Parameter]
public string Style { get; set; }
[Parameter]
public string Text { get; set; }
[Parameter]
public EventCallback<object> OnBtnClick { get; set; }
private async Task BtnClick(object item)
{
await OnBtnClick.InvokeAsync(item);
}
}
I want to use my TableTemplate.razor
in some razor page:
pets1.razor
@page "/pets1"
<h1>Pets</h1>
<TableTemplate RowTemplateConfigs =RowTemplateConfigs TItem =string>
<TableHeader>
<th>Name</th>
</TableHeader>
</TableTemplate>
@code {
private List<RowTemplateConfig> RowTemplateConfigs = new()
{
RowTemplateConfig = new ()
{
DataItem = "Bigglesworth",
ComponentMetadata = new()
{
Name= typeof(MyButton).
Parameters = new Dictionary<string, object>()
{
{ nameof(MyButton.Style), "btn btn-outline-success" }
{ nameof(MyButton.OnBtnClick), EventCallback.Factory.Create<object>(this, OnTestClick)},
{ nameof(MyButton.Text), "Hi"}
}
}
},
RowTemplateConfig = new ()
{
DataItem = "Saberhagen",
ComponentMetadata = new()
{
Name= typeof(MyButton).
Parameters = new Dictionary<string, object>()
{
{ nameof(MyButton.Style), "btn btn-outline-success" }
{ nameof(MyButton.OnBtnClick), EventCallback.Factory.Create<object>(this, OnTestClick)},
{ nameof(MyButton.Text), "Hi"}
}
}
},
//rest of the lest ...
}
private async Task OnTestClick(object sender)
{
// I want to catch the name of the pet here when user click on the button
await Task.Delay(20);
}
}
My Question:
When user clicks on MyButton
in TableTemplate
in pets1.razor
I want to catch the element (name of pet) in the event OnTestClick
.
Thanks and sorry for long question, I appreciate any suggestion.
CodePudding user response:
You need to add a Pet Name parameter to the button component, load it and then submit the property back on the callback event.
Here's a modified version of your code (with a few typo and type fixes). Note: I code with Nullable enabled.
ComponentMetadata
public class ComponentMetadata
{
public Type Name { get; set; } = default!;
public Dictionary<string, object> Parameters { get; set; } =
new Dictionary<string, object>();
}
MyButton.razor
<button type="button" @onclick=BtnClick>
@Text
</button>
@code {
[Parameter] public string? Style { get; set; }
[Parameter] public string? Name { get; set; }
[Parameter] public string? Text { get; set; }
[Parameter] public EventCallback<string> OnBtnClick { get; set; }
private async Task BtnClick()
=> await OnBtnClick.InvokeAsync(this.Name);
}
And then the rest of the code rolled into my test page:
@page "/"
@foreach (var component in myDynamicComponents)
{
<DynamicComponent Type="@component.ComponentMetadata.Name" Parameters=component.ComponentMetadata.Parameters />
}
<div >
<strong>Message:</strong> @message
</div>
@code {
private string message = string.Empty;
private RowTemplateConfig GetRowTemplate(string petName)
=> new RowTemplateConfig
{
DataItem = petName,
ComponentMetadata =
new ComponentMetadata()
{
Name = typeof(MyButton),
Parameters = new Dictionary<string, object>()
{
{ nameof(MyButton.Style), "btn btn-outline-success ms-1" },
{ nameof(MyButton.Name), petName },
{ nameof(MyButton.OnBtnClick), EventCallback.Factory.Create<string>(this, OnTestClick)},
{ nameof(MyButton.Text), $"Hi {petName}"}
}
}
};
private List<RowTemplateConfig> myDynamicComponents => new List<RowTemplateConfig> {
GetRowTemplate("Ginger"),
GetRowTemplate("Tiger"),
GetRowTemplate("Felix")
};
private async Task OnTestClick(string name)
{
await Task.Delay(20);
message = $"{name} Clicked at {DateTime.Now.ToLongTimeString()}";
}
public class RowTemplateConfig
{
public ComponentMetadata ComponentMetadata { get; set; } = default!;
public string? DataItem { get; set; }
}
}