Ahmed Imam
Ahmed Imam

Reputation: 1358

Blazor Passing Data from Parent to Child

I have a razor page which depends on its parent's class and a second child which has its own class and receive data from its parent, my issue is on the second call to the api, the data is not being passed to the second child, the second child is not being render when its parent changes its data but it works on the first render and data is being passed.

Parent.razor

@inherits ParentBase;

<FirstChild/>
<SecondChild data="@data"/>

FirstChild.razor

@inherits ParentBase;

// call its parent method
<span  @onclick='(() => callApi())'/> 

ParentBase.cs

public class ParentBase : ComponentBase
{
   public Data data { get; set; }
   protected override async Task OnInitializedAsync()
   {
       data = await Services.GetData();
   }
   // call from a child
   public void callApi
   {
     data = await Services.GetData();
   }
}

SecondChild.razor

<Table data="@data"/>

SecondChildBase.cs

public class SecondChildBase : ComponentBase
{
   [Parameter]
   public Data data { get; set; }

   protected override void OnParametersSet()
   {
       // this is not getting called
       StateHasChanged();
       Console.WriteLine(data);
   }
}

Upvotes: 9

Views: 20200

Answers (3)

Brian Parker
Brian Parker

Reputation: 14523

Just move the StateHasChanged() to the base after the service call simples....

Upvotes: 1

Jason Chen
Jason Chen

Reputation: 166

I think you can try data-binding instead of CascadingParameter.

Documentation is here: https://learn.microsoft.com/en-us/aspnet/core/blazor/data-binding?view=aspnetcore-3.1

particularly on the two topics below:

  • Parent-to-child binding with component parameters
  • Child-to-parent binding with chained bind

Example: Parent Component

<PasswordField @bind-Password="password" />

@code {
    private string password;
}

Example: Child Component

<input @oninput="OnPasswordChanged" 
       required 
       type="@(showPassword ? "text" : "password")" 
       value="@Password" />

@code {
    private bool showPassword;
    private string password;
    private string validationMessage;

    [Parameter]
    public string Password
    {
        get { return password ?? string.Empty; }
        set
        {
            if (password != value)
            {
                if (value.Contains(' '))
                {
                    validationMessage = "Spaces not allowed!";
                }
                else
                {
                    password = value;
                    validationMessage = string.Empty;
                }
            }
        }
    }

    [Parameter]
    public EventCallback<string> PasswordChanged { get; set; }

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        Password = e.Value.ToString();

        return PasswordChanged.InvokeAsync(Password);
        }

    }

Your child component needs to supply a {Password}Changed where {} is your parameter. This way, when child updates, parents are also updated (as well as all other bind parameters)

Upvotes: 4

Vencovsky
Vencovsky

Reputation: 31565

Just because Parent.razor and FirstChild.razor inherits from the same class, it doesn't mean that the data of both classes (public Data data { get; set; }) will have the same value when changed.

When you call callApi in the FirstChild, it will change it's own data, if you want to change the parent's data, you need to pass a parameter to FirstChild which will be a function to call when the span is clicked and that will call the Parent's callApi.

FirstChild.razor

<span @onclick="OnClick">Call Parent function</span>

@code 
{
    // Call this EventCallback when the span is clicked
    [Parameter]
    public EventCallback OnClick { get; set; }
}

Parent.razor

@inherits ParentBase;

@* Passing OnClick Parameter to call callApi*@
<FirstChild OnClick="@callApi" />
<SecondChild data="@data" />

Upvotes: 5

Related Questions