I have a detail page for some items in my application. This detail page contains an overview section and a few tabs under the overview section.
Users can update the overview section, after a successful update I need to reload the tabs under the overview sections.
I'm using MatBlazor to render tabs. I need to re-render the tabs after the parent component update. The typical way is to pass a callback to the child component. But here the child components (tabs to be specific) are RenderFragment which is a delegate. Here's the razor code portion of tabs in the parent component:
<div >
<MatTabGroup Class="jobTabs">
@foreach (var tab in tabs)
{
<MatTab>
<LabelContent>
@tab.Label
</LabelContent>
<ChildContent>
@tab.Content
</ChildContent>
</MatTab>
}
</MatTabGroup>
</div>
MatBlazor uses RenderFragment to render tab content. Here's my code in the parent component for the tabs RenderFragment
List<JobConfiguartionTabItem> tabs = new List<JobConfiguartionTabItem>();
protected override async Task OnInitializedAsync()
{
try
{
tabs.AddRange(new List<JobConfiguartionTabItem> {
new JobConfiguartionTabItem(){Label = "Scheduled Activities",Content = GetRenderFragment(typeof(JobTemplateScheduleActivityComponent))},
new JobConfiguartionTabItem(){Label = "Account Selection",Content = GetRenderFragment(typeof(AccountSelectionComponent))},
new JobConfiguartionTabItem(){Label = "Schedule",Content = GetRenderFragment(typeof(JobTemplateScheduleComponent))},
new JobConfiguartionTabItem(){Label = "Scheduled History",Content = GetRenderFragment(typeof(JobTemplateScheduledJobComponent))}
}
);
// fetching initial data for the parent component
await this.GetData();
}
catch (Exception exp)
{
Console.WriteLine("Error: " exp);
}
}
Here's the JobConfigurationTabItem
class
public class JobConfiguartionTabItem
{
public string Label { get; set; }
public RenderFragment Content { get; set; }
}
Here's the GetRenderFragment
method in the parent component
private RenderFragment GetRenderFragment(Type component)
{
RenderFragment renderFragment = renderTreeBuilder =>
{
renderTreeBuilder.OpenComponent(0, component);
renderTreeBuilder.CloseComponent();
};
return renderFragment;
}
To simplify my requirement: I need to raise an event from the parent component, and the child component should handle the event with a handler method. In my case, child components are RenderFragment. I couldn't find a way to achieve it through RenderFragment.
CodePudding user response:
Okay, I've solved the problem. My situation is Parent component needed to communicate with the child components. When the parent is updated it needs to tell the child to reload/ re-render themselves as well.
A typical way is to put a @ref
keyword in the child markup in the parent to capture the reference. Then we can call any method of the child via the ref.
In my case, I was using a RenderFragment
which is not an instance of the child rather a delegate.
I've refactored the GetRenderFragment
method to capture the reference of the target child.
private JobTemplateScheduleActivityComponent jobTemplateScheduleActivityComponent { get; set; }
private RenderFragment GetRenderFragment(Type component)
{
RenderFragment renderFragment = renderTreeBuilder =>
{
renderTreeBuilder.OpenComponent(0, component);
if (component == typeof(JobTemplateScheduleActivityComponent))
{
// capturring RenderFragment component reference
renderTreeBuilder.AddComponentReferenceCapture(1, (_value =>
{
jobTemplateScheduleActivityComponent = (JobTemplateScheduleActivityComponent)_value;
}));
}
renderTreeBuilder.CloseComponent();
};
return renderFragment;
}
I have the following method in the parent to run after the update:
protected async Task RunAfterUpdate()
{
await this.GetData();
// calling the reload method of the target child
await jobTemplateScheduleActivityComponent.Reload();
StateHasChanged();
}
RenderTreeBuilder.AddComponentReferenceCapture
is the method I was looking for to capture the reference of a RenderFragment
.