Search code examples
javascriptjqueryhtmlangularjsmmenu

Replacing a tag with spans


I am making a menu using AngularJS and mmenu and I have some submenus that are not correctly functioning as submenus. Essentially mmenu treats a span as a menu, when you click it, it expands (or tries to) and it treats a tags as a link, when you click it the menu closes and it attempts to send you to a link. The problem is that when I build my menu with ng-repeat some of my items are links(a) and some should have further submenus making them spans. I can think of a few ways to fix this but I cannot seem to make them work, here are the solutions I have tried:

  1. use ng-click function to run an if statement to see if the menu that was clicked has a nested ul, if it does than add class mm.opened to expand the submenu instead of following the link

  2. use a function to run through the entire menu after it is built and find any <a> tag that has a nested ul and replace the a tag with span ("span" + this.innerHTML + "/span")

  3. Seek help (current step)

I am open to any solution really, my angular could be wrong which may be causing all of my problems so feel free to correct me on it.

I cannot attach a working example since my menu is built from a json file and I cannot import json to the code editor (that I know of)

This is my menu:

<ul>
  <li><a ng-href="#/home" class="menuBtn">Home</a></li>
  <li ng-repeat="menu in menuInfo" ng-class="countDisable(menu.schematics.length, menu)"> <a class="menuBtn">ATA {{menu.ata}} - {{menu.name}}</a>
    <ul>
      <li ng-click="subCheck()" ng-repeat="submenu in menu.schematics"><a ng-href="#{{submenu.view}}" class="menuBtn">{{submenu.name}}</a>
        <ul>
          <li ng-repeat="animated in submenu.subs"><a ng-href="#{{animated.view}}" ng-click="contentCtrl(animated)" class="menuBtn">{{animated.name}}</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

it looks like this:

Menu opened

when I click on ATA 29 it expands to this:

Menu opened with ATA 29 expanded

you'll see that ATA 29 has 4 items in it, 3 of which should be regular links, the first one ALSO has four nested items, so when I click it I want it to expand just like ATA 29 did, but instead it thinks its a link so it does this:

Menu opened with left hydraulic system selected

I realize it's difficult to help without working code but any help will be appreciated.

var app = angular.module('myApp', ['ngRoute'])

.config(['$routeProvider',
  function($routeProvider) {
    //determines redirects go via shortcuts, clicking on the management icon on the main page sends the routeProvider /MG which it then uses to pull the relevant HTML file
    $routeProvider
      .when('/', {
        controller: 'projectController',
        templateUrl: './assets/html/home.html'
      })
      .when('/schematicView', {
        controller: 'projectController',
        templateUrl: './assets/html/schematicView.html'
      })
      .when('/staticView', {
        controller: 'projectController',
        templateUrl: './assets/html/staticView.html'
      })
      .otherwise({
        controller: 'projectController',
        templateUrl: './assets/html/home.html'
      })
  }
]);

app.controller('projectController', function projectController($scope, $http, $rootScope, $timeout) {
  // $(document).ready(function($) {
  //     setTimeout(function() {
  //         $("#menu").mmenu({
  //             "slidingSubmenus": false,
  //             "counters": true,
  //             extensions: ["multiline"],
  //             offCanvas: {
  //                 position: "left",
  //                 zposition: "front"
  //             }
  //         });
  //     }, 100);
  //     // $("#menu").click(function() {
  //     //     $('.mm-opened').removeClass('mm-opened');
  //     // });
  // });

  $scope.menuInfo = [{
    name: "This is a span it should expand"
  }];
   $scope.secMenuInfo = [{
    name: "This is an a, it should close the menu",
    name2: "This is an a, but it needs to work like a span",
     name3: "This is an a, it should close the menu"
  }];



  // $scope.activeID = 'HM';
  // $scope.activePath = "Assets/images/allActive.png";

  // function getImgPath(item) {
  //     $scope.activePath = "Assets/images/" + item.path + "";
  //     console.log($scope.activePath);
  // }

  // $("#menu em").trigger("count");

  $scope.setImgPath = function(btnPath) {
    console.log(btnPath)
    $scope.activePath = "Assets/images/" + btnPath + "";
    console.log($scope.activePath);
  };
  $scope.contentCtrl = function(id) {
    $scope.active = id;
    console.log($scope.active);
    // $scope.activeItem = item;
    // getImgPath($scope.activeItem);


  };
  // $scope.subCheck = function() {
  //     if ($(this).children().find('mm-counter')) {
  //         alert("has ul");
  //         return false;
  //     } else {
  //         alert("no ul");
  //         return false;
  //     }

  // };



});

app.directive("mmenu", function($timeout) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {

        $timeout(function() {
          $(element).mmenu({
            "slidingSubmenus": false,
            "counters": true,
            extensions: ["multiline"],
            offCanvas: {
              position: "left",
              zposition: "front"
            } //ends offCanvas
          });

          $("em").each(function() {
            var t = $(this).text().trim();
            if (t == "0") {
              $(this).next().remove();

              $(this).remove();

            }
          });
        }, 10);
      } //ends link
  }

});
/* Helvetica Font */

@font-face {
  font-family: HelveticaNeue;
  src: local('0'), url('../fonts/HelveticaNeueLTStd-Lt.woff') format('woff'), url('../fonts/HelveticaNeueLTStd-Lt.otf') format('otf');
}
body,
html {
  font-family: Helvetica, Arial, sans-serif;
  overflow: none;
  color: #FFF;
}
body {
  background: #FFFFFF;
}
#header {
  background: #212121;
  box-shadow: 0 1.5px 4px rgba(0, 0, 0, 0.24), 0 1.5px 6px rgba(0, 0, 0, 0.12);
}
#footer {
  background: #212121;
  box-shadow: 0 -1.5px 4px rgba(0, 0, 0, 0.24), 0 -1.5px 6px rgba(0, 0, 0, 0.12);
}
.fa {
  color: #8ea5d0;
}
.fa:hover {
  color: #627EB0;
}
.fa:active {
  color: #415E95;
}
a:focus {
  outline: 0 none;
  color: #627EB0;
  text-decoration: none;
}
.info_btn {
  color: #FFF !important;
  background-color: #8ea5d0;
  box-shadow: 0 3px 12px rgba(0, 0, 0, 0.23), 0 3px 12px rgba(0, 0, 0, 0.16);
}
.info_btn:hover {
  background-color: #627EB0;
}
.info_btn:active {
  background-color: #415E95;
  color: #FFF;
  text-decoration: none;
}
.info_btn:hover,
.info_btn:visited,
.info_btn:link,
.info_btn:active {
  text-decoration: none;
  color: #FFF;
}
#menu {
  background: #444444;
  box-shadow: 5px 0px 4px rgba(0, 0, 0, 0.3);
  z-index: 10;
}
#menu .li {
  background: #555555;
}
#menu > ul > li {
  list-style: none;
}
#menu > ul {
  padding: 0px;
}
.menuBtn {
  background-color: transparent;
  display: inline-flex;
  cursor: pointer;
  color: #ffffff;
  border: #212121;
  border-bottom-style: solid;
  border-width: 1px;
  width: 100%;
  font-size: 17px;
  padding: 10px 10px;
  -webkit-transition: color .25s linear, background-color .25s ease-in-out, border-color .25s ease-in-out;
  -moz-transition: color .25s linear, background-color .25s ease-in-out, border-color .25s ease-in-out;
  -o-transition: color .25s linear, background-color .25s ease-in-out, border-color .25s ease-in-out;
  transition: color .25s linear, background-color .25s ease-in-out, border-color .25s ease-in-out;
  outline: none;
}
.menuBtn:hover {
  background-color: #333333;
  outline: none;
}
.menuBtn:active {
  position: relative;
  background-color: #222222;
  outline: none;
}
#homeContent {
  color: #000000;
}
/* Global and Overrides */

#header {
  height: 96px;
  border: 0;
  top: 0px;
  width: 100%;
}
#content {
  width: 100%;
  position: fixed;
  top: 96px;
  bottom: 72px;
}
#footer {
  height: 72px;
  border: 0;
  bottom: 0px;
  position: fixed;
  width: 100%;
}
.fa {
  font-size: 36px;
  cursor: pointer;
  display: inline-block;
  padding-top: 30px;
  padding-left: 30px;
}
.title {
  position: absolute;
  right: 75px;
  top: 20px;
  max-width: 400px;
}
.info_btn {
  position: absolute;
  font-size: 40px;
  font-weight: 400;
  right: 30px;
  top: 48px;
  border-radius: 50px;
  padding: 0 21.8px;
  font-size: 20px;
  line-height: 48px;
  position: absolute;
  top: 72px;
  right: 1.6%;
  z-index: 100;
}
/*  causes the color to change when you hover over a button of class myButton */

.revNum {
  font-size: 16px;
  position: absolute;
  bottom: 25px;
  left: 12px;
}
.footer_info {
  bottom: 25px;
  position: absolute;
  margin: 0px auto;
  width: 100%;
  font-size: 18px;
  display: block;
  text-align: center;
}
.logo {
  height: 48px;
  position: absolute;
  bottom: 12px;
  right: 75px;
}
<!DOCTYPE html>
<html>

<head>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/5.6.1/css/jquery.mmenu.all.css" rel="stylesheet" />
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/5.6.1/js/jquery.mmenu.all.min.js"></script>
  <script src="https://code.angularjs.org/1.5.0-rc.2/angular-route.js"></script>
</head>

<body ng-app="myApp" ng-controller="projectController">
  <title>{{projectInfo.title}}</title>
  <div id="wrapper">
    <div id="header">

      <a class="fa fa-home" ng-href="#/home"></a>
      <img class="title" src="assets/images/title.svg"></img>
      <a href class="info_btn"><span>i</span></a>
      <nav id="menu" mmenu>
        <ul>
          <li><a ng-href="#/home" class="menuBtn">Home</a>
          </li>
          <li ng-repeat="menu in menuInfo" ng-class="countDisable(menu.schematics.length, menu)"> <span class="menuBtn">ATA {{menu.ata}} - {{menu.name}}</span>
            <ul>
              <li ng-repeat="submenu in secMenuInfo"><a ng-href="#{{submenu.view}}" class="menuBtn">{{submenu.name}}</a>
                <li ng-repeat="submenu in secMenuInfo"><a ng-href="#{{submenu.view}}" class="menuBtn">{{submenu.name2}}</a>
                <ul>
                  <li ng-repeat="animated in secMenuInfo"><a ng-href="#{{animated.view}}" ng-click="contentCtrl(animated)" class="menuBtn">{{submenu.name3}}</a>
                  </li>
                </ul>
              </li>
            </ul>
          </li>
        </ul>
      </nav>
    </div>
    <div id="content">
      <a href="#menu" target="_self"><h1>HOME</h1></a>
    </div>
    <div id="footer">
      <div class="revNum">Revision: {{projectInfo.version}}</div>
      <div class="footer_info">{{projectInfo.footer}}</div>
      <img class="logo" ng-src="./assets/images/{{projectInfo.logo}}">
    </div>
  </div>
</body>

</html>


Solution

    • The sibling li wasn't closed and had become a nested menu without the proper setup to be a submenu.

    • The li wasn't generating a span like I expected it should have. So I simply copied the pattern I saw in the top menu and it worked.

    Change this:

     <li ng-repeat="submenu in secMenuInfo">
       <a ng-href="#{{submenu.view}}" class="menuBtn">{{submenu.name}}</a>
       <li ng-repeat="submenu in secMenuInfo">
         <a ng-href="#{{submenu.view}}" class="menuBtn">{{submenu.name2}}</a>
    

    To this:

     <li ng-repeat="submenu in secMenuInfo">
        <a ng-href="#{{submenu.view}}" class="menuBtn">{{submenu.name}}</a>
     </li>
     <li ng-repeat="submenu in secMenuInfo">
        <span class="menuBtn">{{submenu.name2}}</span>
    

    <!DOCTYPE html>
    <html>
    <meta charset="utf-8">
    
    <head>
      <link href="https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/5.6.1/css/jquery.mmenu.all.css" rel="stylesheet" />
    
      <style>
        /* Helvetica Font */
        @font-face {
          font-family: HelveticaNeue;
          src: local('0'), url('../fonts/HelveticaNeueLTStd-Lt.woff') format('woff'), url('../fonts/HelveticaNeueLTStd-Lt.otf') format('otf');
        }
        body,
        html {
          font-family: Helvetica, Arial, sans-serif;
          overflow: none;
          color: #FFF;
        }
        body {
          background: #FFFFFF;
        }
        #header {
          background: #212121;
          box-shadow: 0 1.5px 4px rgba(0, 0, 0, 0.24), 0 1.5px 6px rgba(0, 0, 0, 0.12);
        }
        #footer {
          background: #212121;
          box-shadow: 0 -1.5px 4px rgba(0, 0, 0, 0.24), 0 -1.5px 6px rgba(0, 0, 0, 0.12);
        }
        .fa {
          color: #8ea5d0;
        }
        .fa:hover {
          color: #627EB0;
        }
        .fa:active {
          color: #415E95;
        }
        a:focus {
          outline: 0 none;
          color: #627EB0;
          text-decoration: none;
        }
        .info_btn {
          color: #FFF !important;
          background-color: #8ea5d0;
          box-shadow: 0 3px 12px rgba(0, 0, 0, 0.23), 0 3px 12px rgba(0, 0, 0, 0.16);
        }
        .info_btn:hover {
          background-color: #627EB0;
        }
        .info_btn:active {
          background-color: #415E95;
          color: #FFF;
          text-decoration: none;
        }
        .info_btn:hover,
        .info_btn:visited,
        .info_btn:link,
        .info_btn:active {
          text-decoration: none;
          color: #FFF;
        }
        #menu {
          background: #444444;
          box-shadow: 5px 0px 4px rgba(0, 0, 0, 0.3);
          z-index: 10;
        }
        #menu .li {
          background: #555555;
        }
        #menu > ul > li {
          list-style: none;
        }
        #menu > ul {
          padding: 0px;
        }
        .menuBtn {
          background-color: transparent;
          display: inline-flex;
          cursor: pointer;
          color: #ffffff;
          border: #212121;
          border-bottom-style: solid;
          border-width: 1px;
          width: 100%;
          font-size: 17px;
          padding: 10px 10px;
          -webkit-transition: color .25s linear, background-color .25s ease-in-out, border-color .25s ease-in-out;
          -moz-transition: color .25s linear, background-color .25s ease-in-out, border-color .25s ease-in-out;
          -o-transition: color .25s linear, background-color .25s ease-in-out, border-color .25s ease-in-out;
          transition: color .25s linear, background-color .25s ease-in-out, border-color .25s ease-in-out;
          outline: none;
        }
        .menuBtn:hover {
          background-color: #333333;
          outline: none;
        }
        .menuBtn:active {
          position: relative;
          background-color: #222222;
          outline: none;
        }
        #homeContent {
          color: #000000;
        }
        /* Global and Overrides */
        #header {
          height: 96px;
          border: 0;
          top: 0px;
          width: 100%;
        }
        #content {
          width: 100%;
          position: fixed;
          top: 96px;
          bottom: 72px;
        }
        #footer {
          height: 72px;
          border: 0;
          bottom: 0px;
          position: fixed;
          width: 100%;
        }
        .fa {
          font-size: 36px;
          cursor: pointer;
          display: inline-block;
          padding-top: 30px;
          padding-left: 30px;
        }
        .title {
          position: absolute;
          right: 75px;
          top: 20px;
          max-width: 400px;
        }
        .info_btn {
          position: absolute;
          font-size: 40px;
          font-weight: 400;
          right: 30px;
          top: 48px;
          border-radius: 50px;
          padding: 0 21.8px;
          font-size: 20px;
          line-height: 48px;
          position: absolute;
          top: 72px;
          right: 1.6%;
          z-index: 100;
        }
        /*  causes the color to change when you hover over a button of class myButton */
        .revNum {
          font-size: 16px;
          position: absolute;
          bottom: 25px;
          left: 12px;
        }
        .footer_info {
          bottom: 25px;
          position: absolute;
          margin: 0px auto;
          width: 100%;
          font-size: 18px;
          display: block;
          text-align: center;
        }
        .logo {
          height: 48px;
          position: absolute;
          bottom: 12px;
          right: 75px;
        }
      </style>
    </head>
    
    <body ng-app="myApp" ng-controller="projectController">
      <title>{{projectInfo.title}}</title>
      <div id="wrapper">
        <div id="header">
    
          <a class="fa fa-home" ng-href="#/home"></a>
          <img class="title" src="assets/images/title.svg"></img>
          <a href class="info_btn"><span>i</span></a>
          <nav id="menu" mmenu>
            <ul>
              <li><a ng-href="#/home" class="menuBtn">Home</a>
              </li>
              <li ng-repeat="menu in menuInfo" ng-class="countDisable(menu.schematics.length, menu)"> <span class="menuBtn">ATA {{menu.ata}} - {{menu.name}}</span>
                <ul>
                  <li ng-repeat="submenu in secMenuInfo"><a ng-href="#{{submenu.view}}" class="menuBtn">{{submenu.name}}</a>
                  </li>
                  <li ng-repeat="submenu in secMenuInfo"><span class="menuBtn">{{submenu.name2}}</span>
                    <ul>
                      <li ng-repeat="animated in secMenuInfo"><a ng-href="#{{animated.view}}" ng-click="contentCtrl(animated)" class="menuBtn">{{submenu.name3}}</a>
                      </li>
                    </ul>
                  </li>
                </ul>
              </li>
            </ul>
          </nav>
        </div>
        <div id="content">
          <a href="#menu" target="_self"><h1>HOME</h1></a>
        </div>
        <div id="footer">
          <div class="revNum">Revision: {{projectInfo.version}}</div>
          <div class="footer_info">{{projectInfo.footer}}</div>
          <img class="logo" ng-src="./assets/images/{{projectInfo.logo}}">
        </div>
      </div>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jQuery.mmenu/5.6.1/js/jquery.mmenu.all.min.js"></script>
      <script src="https://code.angularjs.org/1.5.0-rc.2/angular-route.js"></script>
      <script>
        var app = angular.module('myApp', ['ngRoute'])
    
        .config(['$routeProvider',
          function($routeProvider) {
            //determines redirects go via shortcuts, clicking on the management icon on the main page sends the routeProvider /MG which it then uses to pull the relevant HTML file
            $routeProvider
              .when('/', {
                controller: 'projectController',
                templateUrl: './assets/html/home.html'
              })
              .when('/schematicView', {
                controller: 'projectController',
                templateUrl: './assets/html/schematicView.html'
              })
              .when('/staticView', {
                controller: 'projectController',
                templateUrl: './assets/html/staticView.html'
              })
              .otherwise({
                controller: 'projectController',
                templateUrl: './assets/html/home.html'
              })
          }
        ]);
    
        app.controller('projectController', function projectController($scope, $http, $rootScope, $timeout) {
          // $(document).ready(function($) {
          //     setTimeout(function() {
          //         $("#menu").mmenu({
          //             "slidingSubmenus": false,
          //             "counters": true,
          //             extensions: ["multiline"],
          //             offCanvas: {
          //                 position: "left",
          //                 zposition: "front"
          //             }
          //         });
          //     }, 100);
          //     // $("#menu").click(function() {
          //     //     $('.mm-opened').removeClass('mm-opened');
          //     // });
          // });
    
          $scope.menuInfo = [{
            name: "This is a span it should expand"
          }];
          $scope.secMenuInfo = [{
            name: "This is an a, it should close the menu",
            name2: "This is an a, but it needs to work like a span",
            name3: "This is an a, it should close the menu"
          }];
    
    
    
          // $scope.activeID = 'HM';
          // $scope.activePath = "Assets/images/allActive.png";
    
          // function getImgPath(item) {
          //     $scope.activePath = "Assets/images/" + item.path + "";
          //     console.log($scope.activePath);
          // }
    
          // $("#menu em").trigger("count");
    
          $scope.setImgPath = function(btnPath) {
            console.log(btnPath)
            $scope.activePath = "Assets/images/" + btnPath + "";
            console.log($scope.activePath);
          };
          $scope.contentCtrl = function(id) {
            $scope.active = id;
            console.log($scope.active);
            // $scope.activeItem = item;
            // getImgPath($scope.activeItem);
    
    
          };
          // $scope.subCheck = function() {
          //     if ($(this).children().find('mm-counter')) {
          //         alert("has ul");
          //         return false;
          //     } else {
          //         alert("no ul");
          //         return false;
          //     }
    
          // };
    
    
    
        });
    
        app.directive("mmenu", function($timeout) {
          return {
            restrict: 'A',
            link: function(scope, element, attrs) {
    
                $timeout(function() {
                  $(element).mmenu({
                    "slidingSubmenus": false,
                    "counters": true,
                    extensions: ["multiline"],
                    offCanvas: {
                      position: "left",
                      zposition: "front"
                    } //ends offCanvas
                  });
    
                  $("em").each(function() {
                    var t = $(this).text().trim();
                    if (t == "0") {
                      $(this).next().remove();
    
                      $(this).remove();
    
                    }
                  });
                }, 10);
              } //ends link
          }
    
        });
      </script>
    </body>
    
    </html>