Angular JS with multiple menu levels

I am looking to iterate through an array of menus and submenus, possibly with nested submenus.

Currently, I am using the Metronic template for my project. You can see a sample of the menu structure in the second-last item on this Metronic Template ("Multi Level Menu").

Here is the structure I am working with:

$scope.dashitems = [{
    title: 'Company',
    icon: 'icon-layers',
    href: '#/dashboard1',
    isActive: path === '/dashboard1'
}, {
    title: 'Buildings',
    icon: 'icon-layers',
    href: '#/Buildings',
    isActive: path === '/Buildings'
}, {
    title: 'Floors',
    icon: 'icon-layers',
    href: '#/Floors',
    isActive: path === '/Floors'
}, {
    title: 'Spaces',
    icon: 'icon-layers',
    href: 'javascript:;',
    isActive: path === '/Spaces',
    subitems: [{
        title: 'OpenSpaces',
        icon: 'icon-layers',
        href: '#/OpenSpaces',
        isActive: path === '/OpenSpaces',
        subitems: [{
            title: 'OpenSpaces2',
            icon: 'icon-layers',
            href: '#/OpenSpaces2',
            isActive: path === '/OpenSpaces2',
        }]
    }, ]
}, {
    title: 'Meeting',
    icon: 'icon-layers',
    href: '#/meeting',
    isActive: path === '/meeting'
}];

This code snippet does not achieve the desired outcome:

function printList(dashitems){
            $scope.menu = '<ul>';
            angular.forEach(dashitems, function(value, key) {
                $scope.menu+="<li>";
                if(value.hasOwnProperty('subitems')){


                  $scope.menu=' <a ng-href="{{ value.href }}" class="nav-link nav-toggle">'+
                              '<i ng-class="value.icon"></i>'+
                              '<span class="title">{{ value.title }}</span>'+
                              '<span class="arrow open"></span>'+
                          '</a>';


                  printList(value.subitems);
                }else{

                   $scope.menu+="<a href='javascript:;' class='nav-link nav-toggle'>"+
                      "<i class='value.icon'></i>"+
                      "<span class='title'>{{value.title}}</span>"+
                  "</a></li>";
                }
            });
            $scope.menu += "<ul>";
            return $scope.menu;
        }

Can someone provide guidance on how to successfully loop over this structure and generate HTML like the "Multi Level Menu"?

Edit:

angular
  .module('app').directive('menuBar', function() {
    return {
      restrict: 'E',
      controller: ['$scope', '$location', function($scope, $location) {
        //function & dashitems
            $scope.printList($scope.dashitems);
      }]
    }   
});

Answer №1

If you want to create a custom directive that generates recursive lists, here is a high-level overview of how you can do it:

<menu ng-model="dashItems"></menu>

The directive should perform the following steps:

  1. Create a function called printList(dashItems)
  2. Open a ul element
  3. Iterate through dashItems and generate a li element for each item
  4. If an item has property 'subItem', call printList(dashItems.subitem) recursively
  5. Finally, close the ul element and return the list

To implement this, simply use:

element.append(printList(dashItems))

Here is a suggested implementation for the printList function:

function printList(dashitems){
            $scope.menu = '<ul>';
            angular.forEach(dashitems, function(value, key) {
                $scope.menu+="<li>";
                if(value.hasOwnProperty('subitems')){

                  // Handle subitems logic
                  
                  printList(value.subitems);
                }else{
                   // Handle regular items logic
                }
                $scope.menu+="</li>";
            });
            $scope.menu += "<ul>";
            return $scope.menu;
        }

This approach should work well in creating recursive lists using a custom directive.

angular
  .module('app').directive('menuBar', function() {
    return {
      restrict: 'E',
      scope: {
          list: '=dashitems'
      },
      controller: ['$scope', '$location', function($scope, $location) {
             // Call printList with dashitems as parameter
            $scope.printList($scope.dashitems);
      }]
    }   
});

Answer №2

Take a look at the code structure... They have utilized Bootstrap to construct a complex menu with multiple levels. To gain a better understanding, visit Bootstrap's official page. Bootstrap utilizes classes for organizing and setting up menus. You also have the option of using AngularJS Bootstrap which is available in the AngularUI project.

To handle your collection effectively, it is recommended to use a directive such as ng-repeat. Alternatively, you can create a custom directive as suggested in another answer. Ultimately, the choice comes down to personal preference. I personally utilize ng-repeat and nest iterations together to form multi-level items.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to create a new object in a Vue component with optimal efficiency?

Currently, I am working on initializing a map that would be utilized in my calculatePrice function. calculatePrice(key) { let prices = new Map({ 0: 17, 1: 19, 2: 24, 3: 27, 4: 30, 5: 46, 6: 50 ...

Why is it that I am unable to properly encode this URL in node.js?

$node querystring = require('querystring') var dict = { 'q': 'what\'s up' }; var url = 'http://google.com/?q=' + querystring.stringify(dict); url = encodeURIComponent(url); console.log(url); Here is the re ...

jQuery causing trouble with AJAX in Rails

Currently, I am fetching a list of users from the controller side and generating the HTML code to append it. This is how I wrote the code: $.ajax({ type : "get", contentType : "application/json; charset=utf-8", url : "/users/sear ...

Clicking on Only One Card in Material UI React

I've encountered an issue with my code: const useStyles = makeStyles({ card: { maxWidth: 345, }, media: { height: 140, }, }); export default function AlbumCard(props) { const classes = useStyles(); let ...

Changing the extension from html to php causes unexpected behavior in Javascript

I am facing an issue with two identical files that only differ in their file extension, causing JavaScript to behave differently in each file. The JavaScript code in question is responsible for controlling the height of the page, but it behaves abnormally ...

Checking URL validity with regular expressions in Vue JS

Currently, I am attempting to validate URL strings utilizing a regular expression. The following regex is what I am using for this purpose: var regex = /^(http|https):\/\/+[\www\d]+\.[\w]+(\/[\w\d]+)?/ With thi ...

The Dockerized AngularJS app is not displaying correctly in the web browser

I recently decided to dockerize an AngularJS app for practice purposes. Take a look at my repository here: https://github.com/Nigel33/angularJS_docker_test. It's based on the official Angular-phonecat repo, but I added a Dockerfile and docker-compose. ...

The value of the innermost dropdown in the AngularJS Cascading dropdown is not being retrieved when it is selected

CSS <div ng-controller="DynamicCtrl"> <h1>Dynamic - Focused</h1> <p>This method works well when data is constantly changing</p> <div> Category: <select id="category" ng-model="items" ng-options="category ...

Is it possible to generate a specified number of divs or HTML tags with varying information using ReactJS?

Currently, I am in the process of constructing this website and I have noticed that I have 4 divs that are essentially doing the same thing. However, I find myself copying and pasting these divs 4 times, only making minor changes to 4 bits of information. ...

Retrieve a particular path element by its assigned ID

I am currently using Topojson along with world-110m.json to create a visual map of the world. My goal is to be able to change the fill property of two specific countries upon a click event. The first country will be selected by the user through a click, a ...

Changing the appearance of a website by applying various stylesheets based on the size of the browser window in

After implementing the code below to switch between stylesheets based on browser height, I encountered a small issue. The code works perfectly when the page first loads or when the window is resized and then refreshed. However, I'm curious if there&ap ...

Trouble with sending data from jQuery Ajax to Node.js server

I am in the process of developing a video streaming platform that needs to constantly update the backend on the status of the videos being played. However, I am encountering an issue where the data sent through an ajax request appears as an empty object {} ...

Sending a json array from PHP

I spent several hours searching for solutions to my problem but couldn't find an answer. I'm trying to perform a search on the same page using jQuery, AJAX, and PHP. Unfortunately, the array from PHP is still returning undefined. Here is the P ...

Dealing with problems in col-md display on tablet devices

When viewing on Full Screen and mobile, the ranges panel (class="col-md-3") displays correctly. However, on tablet screens, the left column is obscured by the youtube image panel (class="col-12 col-md-9"). I have attempted various adjustments to the div s ...

Upgrade your AJAX logic from synchronous to asynchronous for improved performance

I had an old JavaScript library that was making API calls synchronously. To address this, I decided to write a JavaScript function using jQuery that could make the calls asynchronously. In the code below, the getData function is meant to be a versatile fu ...

Cycle through the list and populate the table with the data

My attempt to clarify this explanation is my best, as articulating exactly what I am trying to achieve is quite challenging: Initially, I have a list of names: { "Items": [ { "Id": 0, "Name": "Robinson" }, ...

Trouble with retrieving data from localStorage

On my webpage, I have set up multiple input fields where users can enter data. When they click a button, the data from these inputs is stored inside <span>...</span> elements (the intention being that the text remains visible in these <span& ...

JavaScript vs. GSP: Exploring How to Trigger a Grails Action

There is an action in a controller that I need to modify. def deleteFiling={ obj.removeFiling() redirect(action:"list") } This action is triggered from a GSP: <g:link action="deleteFiling" id="${filingInstance.id}"> <img src="${resource(di ...

Encounter an issue during npm installation of electron: "Error verifying the initial certificate."

I recently developed a new app directory and ran the command npm init. However, I encountered an issue while trying to install Electron with the following line of code: npm install electron --save-dev. The error message I received is as follows: > [em ...

Is there a way to retrieve the width of the parent element in ReactJS from a child component?

The issue has been fixed: I forgot to include .current in my ref... I am trying to determine the width of the element that will hold my component. I came across a solution on SO, but unfortunately it did not work for me as it returned undefined: import R ...