-
Notifications
You must be signed in to change notification settings - Fork 9.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Need a way to access a layout from a page #16009
Comments
Ideally the page could pass parameters to the layout. Or vice-versa, but then the layout would need to be able to get [Parameter] injection and then pass parameters to the rendering of the body. For what it's worth, I'm trying to make my SPA support deep linking, so I can't rely on some internal object store independent of the page load to transfer the information. |
In general the parameter flow goes downwards, i.e., from parent to child, not in the other direction, because the rendering flow goes in that direction. That's why there isn't a way to pass parameters upstream (e.g., to a layout), because then there's be no single defined render order. So for what you're trying to do I'd recommend using a regular component with
Since this is no longer a native layout, also go to your Then for each page that wants to use the layout, you can wrap its output in
I'd be interested to know how you get on with this approach since it is quite unusual. |
Before I get in to a more thorough response: Thank you for taking the time to look at this issue and to comment so extensively on it. I know your time is precious and I wanted you to know it's appreciated. You did even answer my own internal question of "does the page own the layout, or does the layout own the page", so much appreciated there too! Anyway.... I found the Blazor/Redux component (https://github.com/torhovland/blazor-redux) and this suits my needs, so far. I don't really agree with your assertion that what I'm doing is "quite unusual", though. (I don't want to devolve in to an argument, I'd just like to state my case) I suppose it could be unusual in the Razor style of page building, which I admit I'm not terribly up to date on. I come from a React/Redux world, where the router is an explicit component like any other, rather than the somewhat implicit routing we have here in Blazor. (Not knocking it! Just saying it's different!) When you have the control to declare the router and the routes as a custom component, it's quite trivial to implement the top-down flow of props for your pages. With Blazor I'm able to fake that ability through a common root custom component that injects my store rather than each component receiving it, but it works well enough. Incidentally, if the routing is going to be made more flexible to be a component we can declare and implement, then that would help tremendously in supporting those transferring over from ReactLand. |
The router is also an explicit component in Blazor. In the default template, you'll find it in |
I'd like to add a comment on this topic. In MVC I used ViewBag in the _Layout to dynamically show the title depending on the current page. The ViewBag's title property is set in the page. It seems there is currently no way to modify a property in a layout component from a page. |
For cross-component state updates, consider implementing something like the "AppState" pattern. This can be as simple as a static class holding the "Title" string, and have it raise a normal C# event when it changes. Example: https://github.com/aspnet/samples/blob/master/samples/aspnetcore/blazor/FlightFinder/FlightFinder.Client/Services/AppState.cs We're also working on a simplified way of doing this (any many other things that involve components sharing data or collaborating based on ancestor/descendant relationships) for the 0.7.0 release. |
Hi @SteveSandersonMS , thanks for your fast reply. I currently got it working as you described. I will post my demo code here: I found a possible workaround. I only wanted to pass a headline/title from the page to the layout. Define a simple ViewData class that implements INotifyPropertyChanged (I call it ViewDataService):
Register this class as a singleton service to the DI container in Startup.cs: Inject the service into your page: And set the title in the page's code accordingly:
Now inject the service into your layout (MainLayout) with Usage of property Caption: And attach the PropertyChangedHandler to register for property changes:
That's it. Edit: It could be even simpler without using DI when using a static class. |
Does this apply to parameters as well? I have a need to access the current page's route parameter when rendering navigation links from the layout. I really don't think this is unusual. |
I think this is a big oversight from how we structure pages in a traditional MVC application. With Blazor we have a way to pass state down the stack, but no way to pass it back up. The example of passing state back up in MVC is both ViewBag and sections. This functionality made it very complex to implement a breadcrumbs style component outside of using shared services to manually propagate the component initialisation. Even then, this is not really a good solution, there is no real guarantee from a page, with pages just being components, that there wont be multiple instances of it. I see this causing more serious issues on systems that need to ensure their state is maintained for the duration of the page, not just breadcrumbs where if they are wrong, in general everything else behaves. In the JS ecosystem we would be using state management tools like redux to pass state back up the "stack" so that the changes can be propagated back down. This is 100% possible to implement yourself at the moment, even in a generic way, but it's not a clean solution nor is it consistent with any form of library components. I think blazor needs to be opinionated on this, or at least how it functions at a lower level and we can build neater interfaces on top. Having something that serves as the reverse of a CascadingParameter would be a good start, something where I can have an output variable in the layout and multiple input variables throughout my view. Throw in some resolving logic to take the deepest instance of the input variable to update the output variable along with an option to have the output be an IEnumerable of your variables for things like breadcrumbs and I think many cases are covered. The above is ofc my own quick thoughts and not meant to be a proposal, just an idea of the kind of functionality that I think needs to be present in the framework at a centeralised level. |
@Yen Thanks for the feedback! Unfortunately, this is a closed issue in a repo that we're aren't using to track future Blazor work. Could you please provide this feedback through an issue on the https://github.com/aspnet/aspnetcore/issues repo? |
@Yen you can use cascadingparameters for this. Setting/updating cascadingparameter on a child component works(you get a warning, but it is possible) |
Currently, if a page has a layout, there doesn't appear to be any way for the page to get a reference to it. This can be very frustrating if you want to pass parameters from the route data to the layout, for example.
Is there a way to do this that isn't obvious? If not, can it get added to the next release?
The text was updated successfully, but these errors were encountered: