dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.43k stars 10.02k forks source link

Add the property NavLink.IsActive and the event handler NavLink.ActivationChanged #40762

Open nkosi23 opened 2 years ago

nkosi23 commented 2 years ago

Background and Motivation

Knowing the state of a NavLink is often needed in situations where the html layout is complex and setting a css class on the <a> tag is not enough. This is for example the case if the user also needs to add a class to the parent element of a link as in the following situation:

<li>
    <NavLink href="@Url">
        @Text
    </NavLink>
</li>

Real world situations may be even more complex than that. There is currently a need to use an ugly workaround consisting in reimplementing part of the logic of NavLink, such as:

<li class="nav-item @GetActive("", NavLinkMatch.All)">
    <NavLink class="nav-link" href="" Match="NavLinkMatch.All">Home</NavLink>
</li>
@code {

    [Inject]
    NavigationManager NavigationManager { get; set; }

    protected override void OnInitialized() => NavigationManager.LocationChanged += (s, e) => StateHasChanged();

    bool IsActive(string href, NavLinkMatch navLinkMatch = NavLinkMatch.Prefix)
    {
        var relativePath = NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLower();
        return navLinkMatch == NavLinkMatch.All ? relativePath == href.ToLower() : relativePath.StartsWith(href.ToLower());
    }

    string GetActive(string href, NavLinkMatch navLinkMatch = NavLinkMatch.Prefix) => IsActive(href, navLinkMatch) ? "active" : "";
}

Proposed API

namespace Microsoft.AspNetCore.Components.Routing
{
    public class NavLink : Microsoft.AspNetCore.Components.ComponentBase, IDisposable
    {
         ...
+       public bool IsActive { get; }
+       public EventHandler<bool> ActivationChanged { get; set; }
         ...
    }
}

Usage Examples

<li class="@SomeCssClassIfAppropriate">
    <NavLink href="@Url" ActivationChanged="UpdateState">
        @Text
    </NavLink>
</li>

And in csharp:

@code {

   bool IsNavLinkActive { get; set; }
   string SomeCssClassIfAppropriate => IsNavLinkActive ? "the-class" : "";
    void UpdateState(bool isActive)
    {
           IsNavLinkActive = isActive;
           StateHasChanged();
    }
}

Alternative Designs

I cannot think of an alternative way to do that, but I am not extremely familiar with Blazor and the capabilities of the razor engine (for example I do not know if it is possible - or desirable - to have a one way binding allowing a containing component to monitor a property of one of its children components such as IsActive. If this is not possible or desirable, NavLink.IsActive may not be necessary - but I feel it may still be useful to develop custom components inheriting from NavLink in csharp).

Risks

I cannot see any risk with this.

ghost commented 2 years ago

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.

ghost commented 11 months ago

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.