2

This is my menu

<ul class="sidebar-menu" id="navigation-menu">
    <li class="active"><a class="nav-link" href="/"><i class="fas fa-home"></i><span>Home Page</span></a></li>
    <li class="nav-item dropdown">
        <a href="#" class="nav-link has-dropdown"><i class="fas fa-cog"></i><span>Configuration</span></a>
        <ul class="dropdown-menu">
            <li><a class="nav-link" href="/Configuration/AccountCodes">Account Codes</a></li>
            <li><a class="nav-link" href="/Configuration/Branches">Branches</a></li>
        </ul>
     </li>
     <li class="nav-item dropdown">
         <a href="#" class="nav-link has-dropdown"><i class="fas fa-person-booth"></i><span>Directory</span></a>
         <ul class="dropdown-menu">
             <li><a class="nav-link" href="/Directory/Users?Role=Administrator">Administrators</a></li>
             <li><a class="nav-link" href="/Directory/Users?Role=Manager">Managers</a></li>
             <li><a class="nav-link" href="/Directory/Users?Role=Agent">Agents</a></li>
         </ul>
     </li>
</ul>

This is my Jquery, when I select AccountCodes which is under the Configuration dropdown, it should only set the parent list item active. However, the Directory parent is set to active as well. I'm not sure how to select it directly.

Also, due to the structure of my URL, I am unable to continue to use endWith. Is there an alternate method of setting an active class based on the url? Currently, if I select AccountCodes or Branches, it correctly sets the Configuration dropdown item as active. However, If I select agent, nothing is selected at all due to its url ending with a ?Agent instead of Users

<script>
    $(document).ready(function () {
        var current = location.pathname;
        console.log(current);
        $("#navigation-menu a").each(function () {
            var $this = $(this);
            console.log($this.attr('href'));
            if ($this.attr('href').endsWith(current)) {
                console.log($this.parent());
                $this.parent().addClass('active');
                console.log("matched");
            }
        });
        if ($(".dropdown-menu li").hasClass("active")) {
            console.log("Yes");
            var $this = $(this);
            $(".dropdown-menu li").prev().parent().parent().addClass('active');
            console.log($(".dropdown-menu li").closest(".nav-item dropdown"));
        }
    });
</script>
10
  • When you debug, what is the value of current? What is the value of $this.attr('href')? What is the result of $this.attr('href').indexOf(current)? Commented Mar 2, 2019 at 13:12
  • When I am on the AB page the URL is localhost.com:5888/Configuration/AC and console shows Configuration/AC. Thats the value of current. Commented Mar 2, 2019 at 13:15
  • Are you familiar with how to use your browser's debugging tools? Because now is the time to use them. You can place a breakpoint in your code to pause execution on that line and then use the console to observe values and the results of operations while paused. When you do that... What is the value of current? What is the value of $this.attr('href')? What is the result of $this.attr('href').indexOf(current)? Commented Mar 2, 2019 at 13:18
  • I got these results current = /Configuration/AccountCodes thisvalue = w.fn.init [a.nav-link] indexOfResult = -1 Commented Mar 2, 2019 at 13:22
  • 1
    Yeah. I'll change it to html though so its easier to read. Commented Mar 6, 2019 at 1:20

1 Answer 1

0
+200

There would be two ways to mark only the parent link as active.

1. With jQuery

The advantage of this is that it will be compatible with any back end platform.

<script>
    $(document).ready(function () {
        var current = location.pathname;
        console.log(current);
        $("#navigation-menu a").each(function () {
            var $this = $(this);
            var link = $this.attr('href');
            console.log(link);

            // Remove the query string parameters by finding their starting position
            var indexOfQueryString = link.lastIndexOf("?");
            link = link.substring(0, indexOfQueryString);

            if (link.endsWith(current)) {
                console.log("matched");
                if ($this.parent().parent().hasClass('.dropdown-menu')) {
                    var parentLink = $this.closest('.dropdown');
                    console.log("Setting parent link as active:", parentLink);
                    // Find the closest parent link and add active class
                    parentLink.addClass('active');
                } else {
                    console.log("Setting link as active: ", $this.parent());
                    $this.parent().addClass('active');
                }
            }
        });
    });
</script>

In this case, as you have mentioned you encountered problems with ?Agent being present in link – this is what we refer to as query string parameters, which we can safely remove by searching for the unencoded question mark. This is already considered in the solution.

2. With ASP.NET MVC

Doing this in the back end would be more robust and should JavaScript be disabled by the user, this functionality will still work in your website. The disadvantage though, as you might have guessed, is that it is platform-dependent.

There are many ways of going about this. For your specific use-case, as your dropdown links are related to the parent by area, I have adapted another SO answer to cover your specific use-case:

public static string IsSelected(this HtmlHelper html, string area = "", string cssClass = "active")
{
    ViewContext viewContext = html.ViewContext;
    RouteValueDictionary routeValues = viewContext.RouteData.Values;
    string currentArea = routeValues["area"] as string;

    return area.Equals(currentArea) ? cssClass : String.Empty;
}

Then use it this way:

<ul class="sidebar-menu" id="navigation-menu">
    <li><a asp-area="" asp-controller="Home" asp-action="Index" class="nav-link"><i class="fas fa-home"></i><span>Home
                Page</span></a></li>
    <li class="nav-item dropdown @Html.IsSelected(area: "Configuration")">
        <a href="#" class="nav-link has-dropdown"><i class="fas fa-cog"></i><span>Configuration</span></a>
        <ul class="dropdown-menu">
            <li><a asp-area="Configuration" asp-controller="AccountCodes" asp-action="Index" class="nav-link">Account
                    Codes</a></li>
            <li><a asp-area="Configuration" asp-controller="Branches" asp-action="Index" class="nav-link">Branches</a>
            </li>
        </ul>
    </li>
    <li class="nav-item dropdown  @Html.IsSelected(area: "Directory")">
        <a href="#" class="nav-link has-dropdown"><i class="fas fa-person-booth"></i><span>Directory</span></a>
        <ul class="dropdown-menu">
            <li><a asp-area="Directory" asp-controller="Users" asp-action="Index" asp-route-Role="Administrator"
                    class="nav-link">Administrators</a></li>
            <li><a asp-area="Directory" asp-controller="Users" asp-action="Index" asp-route-Role="Manager"
                    class="nav-link">Managers</a></li>
            <li><a asp-area="Directory" asp-controller="Users" asp-action="Index" asp-route-Role="Agent"
                    class="nav-link">Agents</a></li>
        </ul>
    </li>
</ul>

Would this benefit you, please make sure to upvote the other linked answer as well.

Sign up to request clarification or add additional context in comments.

3 Comments

I like your second suggestion more. However, it looks like it sets the list item directly. Does it work with the parent list item as well?
Yes it should, @JianYA. As your dropdown links are grouped by area, I have added code that will use that instead. Let us know how this goes.
@JianYA you may also consider inserting the previous version of HTML as well in your post so others will be able to follow this answer from there.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.