Reputation: 335
I have a side drawer in my MainLayout.razor
component, which is used to set/change certain values which are then used throughout the app.
<CascadingValue Value="@appValues" Name="AppValue">
<SideDrawer OnUpdate="@RefreshPage"></SideDrawer>
<div class="content px-4">
@Body
</div>
</CascadingValue>
When I update the values in the SideDrawer, I do an EventCallback
, through which I can update the variables which can then be used as cascading values throughout the page components.
@code{
public AppValues appValues = new AppValues();
protected void RefreshPage()
{
appValues.value1 = somevaluefromsidedrawer;
appValues.value2 = someothervaluefromsidedrawer;
StateHasChanged();
}
}
And these cascading values get updated just fine in the page components. But the problem is, in the page components, there is a method (let's say LoadData()
) in which certain datasets should be updated based on these cascading values.
@code{
[CascadingParameter(Name = "AppValue")]
protected AppValues appValues { get; set; }
protected void RefreshCurrentPage()
{
LoadData(appValues.value1);
}
}
Ideally, I would like to be able to call the RefreshCurrentPage()
method in the page component from the RefreshPage()
method in the MainLayout.razor
component, so that all the datasets in the page component are refreshed based on the updated values.
Is it possible to do something like this?
Upvotes: 0
Views: 1788
Reputation:
I'm new to Blazor (Server), and thanks to the accepted answer, I was able to resolve a similar problem I had, where I wanted a component to trigger a re-render of the parent page.
I ended up doing it as follows.
// My Parent Page (ParentPage.razor)
<Component ParentPage=this/>
public void StateHasChanged()
{
// Call the StateHasChanged method in the page's base class
base.StateHasChanged();
}
Then in my component, for which the page has many (Component.razor)
[Parameter]
private ParentPage ParentPage { get; set; }
private void RefreshParent()
{
this.ParentPage.StateHasChanged();
}
I'm now able to call the RefreshParent() method from my component which nicely triggers a re-render of the page when the state has changed.
For good measure, I added a null check to ensure the parameter is always set when the component is instantiated using the overloaded OnParametersSet() method.
Upvotes: 0
Reputation: 45596
You can do that in various ways:
You can pass a reference to the MainLayout component to interested child components in the form of a CascadingValue vomponent, like this:
<CascadingValue Value="this" Name="TheMainLayout">
</CascadingValue>
And a child component should grab the reference like this:
@code{
[CascadingParameter(Name = "TheMainLayout")]
public MainLayout MainLayout { get; set; }
}
And add itself to a list of components defined in the MainLayout component:
// Child component adds itself to the MainLayout component
protected override void OnInitialized()
{
MainLayout.AddPage(this);
}
And in the MainLayout component you'll define a list of ComponentBase objects, and the AddPage method as follows:
public void AddPage(ComponentBase page)
{
// Code to add the page component to the list
}
Now that the MainLayout holds references to components, it can directly call the RefreshCurrentPage defined in each added page components (I guess it can only be one as we are talking about routable components, right).
Note: The above was only the outline of a solution. You may extend it to provide an event that is raised each time there is a need to refresh the data, and each page component should subscribe to the event, which when raised, call the RefreshCurrentPage method. This is a better and more sophisticated way than calling the RefreshCurrentPage directly from the MainLayout.
You should provide code to remove the added component reference from the list of components, when those components are killed, etc.
Note that the CascadingValue for appValues is not needed any longer, as the child component hold a reference to the MainLayout and can directly access those values.
Note: All the above procedure can be implemented by a service class injected into the MainLayout component and its children.
So long, buddy...
Upvotes: 2