Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
   }
}
like image 750
Ahmed Imam Avatar asked Jun 03 '20 12:06

Ahmed Imam


People also ask

How do you pass data from child to parent in Blazor?

Child component to parent component communication Child component (DisplayEmployee Component) should notify the parent component (EmployeeList Component) that a record is deleted so the parent component can remove the respective employee card from the list of employees. For this the child component exposes an event.

How do I move data from one page to another in Blazor?

By using Blazor route parameters, you can pass values from one page to another page. Use NavigationManager to pass a value and route the parameter to another page. Follow this example to achieve passing values from one page to another. Get the passed Page1 parameter value in Page2.

What does @bind do Blazor?

To use two-way binding on a parameter simply prefix the HTML attribute with the text @bind- . This tells Blazor it should not only push changes to the component, but should also observe the component for any changes and update its own state accordingly.


2 Answers

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" />
like image 149
Vencovsky Avatar answered Oct 05 '22 03:10

Vencovsky


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

Documentation is here: https://docs.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)

like image 30
Jason Chen Avatar answered Oct 05 '22 03:10

Jason Chen