I'm trying to render dynamic content in Blazor Wasm using DynamicComponent from .Net 6. The component to render is defined in a JSON file with the following structure.
{
"type":"MyButton",
"parameters": {
"Label":"My Buttom",
"OnClicked": "DoAction"
}
}
DynamicComponent allows us to pass parameters to the rendered Component using Dictionary<string, object> like the code below where we can define component.parameters as Dictionary<string,object>
<DynamicComponent [email protected] [email protected] />
In my razor file, I have defined the "DoAction()" method. I want the this method to be called when the MyButton component is clicked. But how can we pass this DoAction() method as EventCallBack to the rendered Component?
MyButton.razor component:
<button class="btn btn-primary" @onclick="HandledClicked">@LabelText</button>
@code{
[Parameter]
public string LabelText {get; set;}
[Parameter]
public EventCallback OnClicked { get; set; }
private void HandleClicked()
{
OnClicked.InvokeAsync();
}
}
DynamicPage.razor: (Update #1)
@page "/DynamicPage"
@foreach (var component in components)
{
<DynamicComponent Type="component.Type" Parameters="component.Parameters" />
}
@code{
List<JsonComponent> components = new();
protected async override Task OnInitializedAsync()
{
var jsonComponentList = await Http.GetFromJsonAsync<List<JsonComponent>>("/data.json");
foreach (var item in jsonComponentList)
{
JsonComponent componentItem = new();
componentItem.Type = Type.GetType($"{nameSpaceComponents}{item.Type}");
componentItem.Parameters = new();
// below code to populate the component parameters as Dictionary<string, object>.
// the problem here is how to pass "DoAction()" method which is defined in the
// Json file to the rendered component by adding it to the paramater Dictionary<string, object>?
foreach (var kvp in item.Parameters)
{
var jsonElement = ((JsonElement)kvp.Value).GetString();
componentItem.Parameters.Add(kvp.Key, jsonElement);
}
}
}
public void DoAction()
{
//.. codes to perform some custom logic here when Button component is clicked.
}
}
JsonComponent.cs Class:
public class JsonComponent
{
public JsonComponent()
{
}
public Type Type { get; set; }
public Dictionary<string, object> Parameters { get; set; }
}
In order to pass the method or function at runtime to the dynamically generated Component via the Dictionary<string, object> Parameters, we need to create an EventCallBack by using EventCallback.Factory.Create()
method.
I use the foreach
loop to get the list of parameters defined in the Json file that we need to add into the Dictionary<string, object> Parameters.
Then I have an if
condition to check whether the parameter to be passed to the Component is an Event. Here I predefined all Event Key name should prefix with 'On' e.g. 'OnClicked'. If the parameter is an Event then we create an EventCallback
callback = EventCallBack.Factory.Create<string>(this, (Action<string>) this.GetType().GetMethod(kvp.Value.ToString()).CreateDelegate(typeof(Action<string>), this));
componentItem.Parameters.Add(kvp.Key, callback);
Below is the codes for the DynamicPage.razor:
@page "/DynamicPage"
@foreach (var component in components)
{
<DynamicComponent Type="component.Type" Parameters="component.Parameters" />
}
@code{
List<JsonComponent> components = new();
EventCallBack<string> callback; // Declare a EventCallBack variable use to pass to the generated Component
protected async override Task OnInitializedAsync()
{
var jsonComponentList = await Http.GetFromJsonAsync<List<JsonComponent>>("/data.json");
foreach (var item in jsonComponentList)
{
JsonComponent componentItem = new();
componentItem.Type = Type.GetType($"{nameSpaceComponents}{item.Type}");
componentItem.Parameters = new();
foreach (var kvp in item.Parameters)
{
var jsonElement = ((JsonElement)kvp.Value).GetString();
if (kvp.Key.ToString().StartsWith("On"))
{
callback = EventCallBack.Factory.Create<string>(this, (Action<string>) this.GetType().GetMethod(kvp.Value.ToString()).CreateDelegate(typeof(Action<string>), this));
componentItem.Parameters.Add(kvp.Key, callback);
}
else
{
componentItem.Parameters.Add(kvp.Key, jsonElement);
}
}
components.Add(componentItem);
}
}
}