'Why Highlight Menu Item Doesn't Work in ASP.NET MVC?

Why Highlight Menu Item Doesn't Work in ASP.NET MVC?

I am testing the method for highlighting the selected menu item in a MVC program.

The test environment include: 1)ASP.NET core with MVC (using .NET 5) 2) Bootstrap V4.6

First, I created a small html file just for testing the "hightlight" mehtod with bootstrap with JQuery. (see html file content below). This html page works fine. It changes the text color to red for the active menu item.

Second, I created an ASP.NET core MVC project. In the _layout.cshtml file, I also use the bootstrap 4 and same JQuery script intended to highlight the active menu item. The top menu has same bootstrap classes for various navbar components. But, it does not work at all. (see content of _layout.cshtml at the very end of this post.) Why the "hightlight" doesn't work in MVC and how can I fix it.


HTML PAGE for testing

<!DOCTYPE html>
<html lang="en">
    <head>
        <!-- Required meta tags -->
        <meta charset="utf-8" />
        <meta name="viewport"
            content="width=device-width,
                    initial-scale=1,
                    shrink-to-fit=no" />

        <!-- Bootstrap CSS -->
        
        <!-- <link rel="stylesheet"
            href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
            integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
            crossorigin="anonymous" />-->
            
        <!-- Bootstrap CSS file -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
        <!-- Bootstrap Font Icon CSS -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
        <!-- Font Awesome library -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
        
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"> </script>
        <script src="https://npmcdn.com/[email protected]/dist/js/tether.min.js">    </script>
        
        <style>
            .font-bold {
                font-weight: bolder;
            }
        </style>

        <title>Active Link font color using jquery</title>
    </head>

    <body>
        <!-- <nav class="navbar navbar-expand-md navbar-light bg-light"> -->
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
            <a class="navbar-brand" >Testing</a>
            
            <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                <ul class="navbar-nav">
                    <li class="nav-item active">
                        <a class="nav-link font-bold" href="#">
                            Home
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link font-bold" href="#">
                            Product
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link font-bold" href="#">
                            Order
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link font-bold" href="#">
                            Shipping
                        </a>
                    </li>               
                    <li class="nav-item">
                        <a class="nav-link disabled" href="#">Disabled</a>
                    </li>
                </ul>
            </div>
            </div>
        </nav>
    
        <script type="text/javascript">
            $(document).ready(function () {
                $("ul.navbar-nav > li > a").click(
                function (e) {
                    $("ul.navbar-nav > li").removeClass(
                    "active");
                    $("ul.navbar-nav > li > a").css(
                    "color", "");

                    $(this).addClass("active");
                    $(this).css("color", "red");
                });
            });
        </script>
    </body>
</html>


_layout.cshtml in MVC

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - MVCWebUI</title>
    @*<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
        <link rel="stylesheet" href="~/css/site.css" />*@

    <!-- Bootstrap CSS file -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
    <!-- Bootstrap Font Icon CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
    <!-- Font Awesome library -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">

    <script src="~/lib/jquery/dist/jquery.min.js"></script>

    <script type="text/javascript">
        $(document).ready(function () {
            $("ul.navbar-nav > li > a").click(
                function (e) {
                    $("ul.navbar-nav > li").removeClass(
                        "active");
                    $("ul.navbar-nav > li > a").css(
                        "color", "");

                    $(this).addClass("active");
                    $(this).css("color", "red");
                });
        });
    </script>
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">MVCWebUI</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item" >
                            <a class="nav-link " asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link"  asp-area="" asp-controller="Home" asp-action="Privacy">Product</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link"  asp-area="" asp-controller="Home" asp-action="Privacy">Order</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>

    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2022 - MVCWebUI - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
        </div>
    </footer>

    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>


Solution 1:[1]

$(this) in this context is referring to the clicked element which is the anchor element.

As such you are adding the active class to the anchor element and I think it needs to be on the list item element. I think you also need to prevent the default link click events,something like:

<script type="text/javascript">
    $(document).ready(function () {
        $("ul.navbar-nav > li > a").on("click", function (e) {
          
          e.preventDefault();
          
          var link  = $(this);
          
          $("ul.navbar-nav > li").removeClass("active");

          link.parent().addClass("active");

         // Redirect to URL
         window.location.href = link.attr("href");

        });
    });
</script>

Put an example here for you: https://codepen.io/treefishuk/pen/zYPKapP

Please note that on redirecting to the new page the active state will be lost becuase HTTP is a stateless protocol. To set the active state after the redirect you have a few options, here are three of them:

Option 1 : Use Javascript to match current URL against links

On the page load you can get the current url from window.location then loop through the links in the nav and add the active class if they match.

Example : https://webdesignerhut.com/active-class-navigation-menu/

Option 2 : Use Javascript and some sort of persistance mechanism

You could save the id of the clicked link in a cookie or local storage and on page load add the active state to the matching element. The example below is for sidebar state but the principle is the same.

Example : Bootstrap 4 Collapse active state in localstorage

Option 3 : Set it server side using a custom tag helper

This is the most elegant approach in my opinion.

Examples :

Solution 2:[2]

You can use Bootstrap's nav-pills to change the color of active menu item.

<ul class=navbar-nav nav nav-pills" role="tablist" id="manu-bar">
  <li class="nav-item">
    <a class="nav-link @(ViewData["Title"] == "Page1" ? "active" : "")" id="menu1" asp-area="" ....>Page1</a>
  </li>
    <a class="nav-link @(ViewData["Title"] == "Page2" ? "active" : "")" id="menu1" asp-area="" ....>Page2</a>    
  </li>
</ul>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Shangwu