Reputation: 1358
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
Reputation: 14523
Just move the StateHasChanged() to the base after the service call simples....
Upvotes: 1
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:
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
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