aherrick
aherrick

Reputation: 20179

Blazor (Razor Components) Refresh Child Component from Parent Component

I have a simple child Blazor component (MyModal) like so:

<div class="modal">
    <h3>@Title</h3>
    @BodyTemplate
</div>

@code
{
    [Parameter] string Title { get; set; }
    [Parameter] RenderFragment BodyTemplate { get; set; }
}

In my Parent component I'm calling it like so:

<MyModal Title="Super Cool Modal">
        <BodyTemplate>
            @MyObject.Name
        </BodyTemplate>
</MyModal>

public MyObject MyObject { get; set; } = new MyObject();

Later on after the page has initially rendered I update MyObject but the Child component itself referencing @MyObject.Name never updates.

Seems I have to force refresh on the child object after I've updated the Object (StateHasChanged) but not sure how to do this with this example.

Upvotes: 22

Views: 33171

Answers (5)

SBU
SBU

Reputation: 368

You can just use CascadingParameter.

In your parent component, just call child component like this:

<CascadingValue Value="selectedChats[0].Id" Name="chatID">
     <AdminChatComponent> </AdminChatComponent>
</CascadingValue>

Child Component:

[CascadingParameter(Name ="chatID")]
public string chatID { get; set; }

After that, all you need to do is just make a OnParametersSetAsync method in child component andjust bind your value in parent component. In my case I binded my value to datagrid row select.

After that whenever binded value changes on parent component, also your child component will trigger OnParametersSetAsync method.

Upvotes: 8

Javier Contreras
Javier Contreras

Reputation: 1133

I got a different example with a complex parameter object that has to be serialized to a form model.

OnParametersSetAsync() will update child component if parameter changes.

We need to bind child parameter using @bind-Job="_job"

Parent:

<div class="tab-pane active" id="kt_job_tab_1">
    <JobEdit @bind-Job="_job"></JobEdit>
</div>

@code
{
    private Job _job;

    protected override async Task OnInitializedAsync()
    {
        _job = await GetJob();

        await base.OnInitializedAsync();
    }

}

Child:

<EditForm Model="@_model" OnValidSubmit="HandleValidSubmit">
    <DataAnnotationsValidator />

    <div class="form-group row">
        <label class="col-xl-3 col-lg-3 col-form-label text-sm-left text-lg-right">Title</label>
        <div class="col-lg-9 col-xl-6">
            <InputText @bind-Value="_model.JobTitle" class="form-control form-control-solid form-control-lg" />
        </div>
    </div>
    <div class="form-group row">
        <label class="col-xl-3 col-lg-3 col-form-label text-sm-left text-lg-right">Department</label>
        <div class="col-lg-9 col-xl-6">
            <InputText @bind-Value="_model.Department" class="form-control form-control-solid form-control-lg" />
        </div>
    </div>
</EditForm>

@code {

    [Parameter]
    public Job Job { get; set; }

    [Parameter]
    public EventCallback<Job> JobChanged { get; set; }

    private Model _model;

    protected override async Task OnInitializedAsync()
    {
        InitializeModel();

        await base.OnInitializedAsync();
    }

    //THIS WILL UPDATE MODEL IF PARENT CHANGES
    protected override async Task OnParametersSetAsync()
    {
        InitializeModel();

        await base.OnParametersSetAsync();
    }

    private async void HandleValidSubmit()
    {
        //WE CODE HERE
        //THEN

        //THIS UPDATES PARENT IF CHILD JOB CHANGES
        await JobChanged.InvokeAsync(Job); 

        StateHasChanged();
    }

    private void InitializeModel()
    {
        _model = new Model
        {
            JobIdentifier = Job.Identifier,
            JobTitle = Job.JobTitle,
            Department = Job.Department
        };
    }

    private class Model
    {
        [Required]
        public string JobIdentifier { get; set; }

        [Required]
        public string JobTitle { get; set; }

        [Required]
        public string Department { get; set; }
    }

}

Upvotes: -1

Martin VU
Martin VU

Reputation: 151

You can do "OnParametersSetAsync()" on child component:

Parent component:

<childCompoment param="@paramParent" />

Child component:

[Parameter]
public string param{get;set;}

protected override async Task OnInitializedAsync(){await Refresh();}

async Task Refresh(){}

Upvotes: -1

hultqvist
hultqvist

Reputation: 18511

Since <MyModal> has a RenderFragment parameter it's enough to call StateHasChanged() on the parent component, it will recalculate and render all child components with parameters from the parent.

Upvotes: 1

Amine
Amine

Reputation: 1356

You can try this

Child

Create a public refresh method that you can call from parent

<div class="modal">
    <h3>@Title</h3>
    @BodyTemplate
</div>

@code
{
    [Parameter] string Title { get; set; }
    [Parameter] RenderFragment BodyTemplate { get; set; }

    public void RefreshMe()
    {
        StateHasChanged();
    }
}

Parent

Call child refresh method

<MyModal Title="Super Cool Modal"
         @ref="ChildComponent">
        <BodyTemplate>
            @MyObject.Name
        </BodyTemplate>
</MyModal>
@code
{
   public MyObject MyObject { get; set; } = new MyObject();
   protected UploadDownloadComponent ChildComponent;

   //Call this method to update the child
   private void Change(TreeEventArgs args)
   {
       ChildComponent.RefreshMe();
   }
}

Upvotes: 28

Related Questions