-
Notifications
You must be signed in to change notification settings - Fork 10.1k
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
Sections support in Blazor #28182
Comments
Thanks for contacting us. |
One of the reasons we haven't got this as a baked-in feature yet is that it's possible to implement something like this in your own application code. If there's enough consensus that some single pattern takes care of almost all requirements, we might well consider putting it into the framework. But until then, it would help if people were able to try out ways of doing this and report back on what's working well or not well for them. To get started, here's one way to do it:
<div class="top-row px-4">
<SectionOutlet Name="topbar" />
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<SectionContent Name="topbar">
<button class="btn btn-primary" @onclick="IncrementCount">Increment counter</button>
</SectionContent> Now when the user navigates to "Counter", they will have a button in the navigation bar that updates the count. And when they navigate to any other page, that button will disappear. Of course, each page could provide its own different content for Technically you can even use this approach to supply content to the |
Thank you @SteveSandersonMS ! This is a viable solution.
Indeed it is. But the implementation is so simple and small that you can consider including it in Blazor (or another official Nuget package that people can use). Thanks again for the code and general idea. I will use it in my projects. |
To anybody trying @SteveSandersonMS's solution don't make the same mistake as me. Do not forget to include |
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process. |
Is this still being considered for .NET 7 ? |
It's in |
Any news about this? |
@sajjadarashhh not for .NET 7 for sure. |
I'll expose my use case, just in case it serves as an example: |
Thanks for contacting us. We're moving this issue to the |
Just wanted to add my few cents. I'm making a CMS-like engine, where different pages can render to different parts of a page. Namely, on the top, there are breadcrumbs, and on the right, there is a table of contents. The body of the page is the content itself. The layout can define the sections. I'm not a big fan of magic strings, I'd rather pass discrete references to objects, so I've made the following, using the example of putting a table of contents on the page in a different place. It's similar (closest) in concept to MVC's .cshtml sections.
public sealed class Section<TOutlet> : IComponent where TOutlet : SectionOutlet, IDisposable
{
[Parameter, EditorRequired]
public RenderFragment ChildContent { get; set; } = null!;
[Parameter, EditorRequired]
public TOutlet Outlet { get; set; } = null!;
void IComponent.Attach(RenderHandle renderHandle)
{
// The section isn't rendered where it is defined, so the RenderHandle is discarded here by design.
}
public Task SetParametersAsync(ParameterView parameters)
{
ChildContent = parameters.GetValueOrDefault<RenderFragment>(nameof(ChildContent))!;
Outlet = parameters.GetValueOrDefault<TOutlet>(nameof(Outlet))!;
Outlet?.Render(ChildContent); // The ?. is only needed if the Outlet hasn't been defined yet.
return Task.CompletedTask;
}
public void Dispose()
{
Outlet?.Render(_=>{}); // Keep in mind this might also clear the content of the outlet if another section is attached to it.
}
}
public class SectionOutlet : IComponent
{
public RenderHandle Handle { get; private set; }
public void Attach(RenderHandle renderHandle) => Handle = renderHandle;
public virtual Task SetParametersAsync(ParameterView parameters) => Task.CompletedTask;
public void Render(RenderFragment renderFragment) => Handle.Render(renderFragment);
} Usage is as expected: you need to create an outlet somewhere (higher up the hierarchy), hold its reference, then define a section in the body of your page referring to the reference held, something like:
<CascadingValue Value="this" IsFixed="true">
<!-- Router, layout, etc. -->
<div class="table-of-contents">
<SectionOutlet @ref="TableOfContents">
</div>
</CascadingValue>
@code {
public SectionOutlet? TableOfContents { get; set; }
}
@page /mypage
<Section Outlet="App.TableOfContents">
<h1>Lorem ipsum dolor</h1>
<h2>Lorem ipsum dolor</h3>
<h3>Lorem ipsum dolor</h3>
</Section>
@code {
[CascadingParameter]
public App App { get; set; }
} This seems to work for my scenario very well. I wonder if I'm missing something or if this will cause issues in the future, but I would like to see this implemented in the framework as well. One obvious drawback of this direct implementation is if there are multiple Section instances using the same Outlet, they'll keep overwriting each others' contents. I'm not sure how this could be done otherwise (except for throwing in such cases when multiple section try to write to the same outlet). The other one using the breadcrumbs I'm currently in the middle of developing, as it shouldn't use arbitrary content, but rather should use a model provided by the page itself; so it's possibly better to implement it in some other way, or it requires maybe one or two more levels of abstraction. It can easily be used by something similar though: <Section Outlet="App.Breadcrumbs">
<Breadcrumbs Crumbs="..."/>
</Section> |
It also would be nice to check if the section is available or has content similar to IsSectionDefined |
@yugabe
|
@Flachdachs Both of your problems I also encountered myself and solved them, but in the meantime the solution got more verbose and complicated (I actually created a third component called |
Basically the same as #10131 which has been closed in in favour of #10452 which was in turn closed in favour of #10450 (influencing the
<head>
).Having the ability to embed content from the page in the layout in more than one placeholder is a common need. A typical use case is to display the page name in the "header" of the application which is usually defined in the layout. Another use case is to display personalised content for the currently logged user.
A lot of other technologies support this feature and I think it would be a great addition to Blazor. A few examples:
Thank you for your consideration!
The text was updated successfully, but these errors were encountered: