Home > OS >  Reload child component after updating parent in Blazor
Reload child component after updating parent in Blazor

Time:05-26

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.

  • Related