Reload child component after updating parent in Blazor

2.2k Views Asked by At

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 class="jds-shadow-soft-xxs jds-radius-l min-height100p pt1">
        <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.

1

There are 1 best solutions below

0
On BEST ANSWER

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.