Collapsible list in Angular2 sidenav: ensuring only one sublist remains open

Presenting a functional sidenav demo with Angular 2, TypeScript, and Material Design components. The sidenav features a UL, with the Sites and Users anchors expanding to display their own sub-list.

Check out the Plunker here

Here is the HTML code for the sidenav:

<md-sidenav #start mode="over" class="sideDrawer">
    <ul class="sidenav">
      <li><a>Dashboard</a></li>
      <li>
        <a (click)="sideNavClick()">Sites</a>
          <div>
            <ul *ngIf="clickedSites" class="sublist">
                <li><a (click)='sideNavAlert()'>All Sites</a></li>
                <li><a>Site Groups</a></li>
            </ul>
          </div>
      </li>
      <li>
        <a (click)="sideNavClickUser()">Users</a>
          <div>
            <ul *ngIf="clickedUsers" class="sublist">
                <li><a (click)="sideNavAlert()" >Add User</a></li>
                <li><a>Edit User</a></li>
                <li><a>Remove User</a></li>
            </ul>
          </div>
      </li>
      <li>
          <a>Lights</a>
      </li>
      <li><a>Settings</a></li>
    </ul>
</md-sidenav>

This is a basic version of the solution provided. The actual sidenav will include numerous navigation options, each with children that require toggling visibility. I aim to have only one sublist visible at any given time. Instead of manipulating boolean values for every sublist using *ngIf, I seek a more efficient approach within Angular 2. Although a CSS workaround is plausible, it may involve adding/removing classes individually from each list, similar to flipping boolean values in the alternate solution.

Any thoughts or suggestions?

Answer №1

To efficiently manage expandable menus, one approach is to keep track of the currently open menu in a variable. This way, when a menu item is clicked, it either closes (if already open) or opens while closing the previously open menu.

Here is an example of the component logic:

export class AppComponent {
    activeMenu: string = null;

    onMenuClick(menu: string): void {
        this.activeMenu = this.activeMenu === menu ? null : menu;
    }

    showAlert(): void {
        alert("Sublist item clicked");
    }
}

And here is how it can be implemented in the template file:

<a (click)="onMenuClick('sites')">Sites</a>
<div>
    <ul *ngIf="activeMenu === 'sites'" class="sublist">...</ul>
</div>

...

<a (click)="onMenuClick('users')">Users</a>
<div>
    <ul *ngIf="activeMenu === 'users'" class="sublist">...</ul>
</div>

For better scalability, consider using an array in the component to dynamically generate menus instead of hardcoding each possibility.

Check out the updated Plunker here.

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

The jsPdf library performs well on medium-sized screens like laptops, but when downloaded from larger monitor screens, the PDF files do not appear properly aligned

In the code snippet below, I am using html2canvas to convert HTML to PDF. The PDF download works fine on medium screens, but when viewed on larger screens, some pages appear blank and the content order gets shuffled. How can I resolve this issue so that th ...

What steps can I take to resolve a dependency update causing issues in my code?

My program stopped working after updating one of the dependencies and kept throwing the same error. Usually, when I run 'ng serve' in my project everything works fine, but after updating Chartist, I encountered this error: An unhandled exception ...

Which TypeScript AsyncGenerator type returns a Promise?

I am currently in the process of assigning a return type to the function displayed below: async function *sleepyNumbers() { // trying to determine TypeScript type let n = 0; while (true) { yield new Promise(resolve => resolve(n++)); ...

Understanding Scope in TypeScript

Recently, I developed a sample application in Node.js which utilizes pg-promise to execute queries on a Postgres database. I encapsulated this functionality within a class named PostgresDataAccess. However, I encountered an issue while trying to access t ...

Is there a way to determine the distance in miles and feet between various sets of latitude and longitude coordinates?

I am working with an array of latitude and longitude coordinates and I am looking to use JavaScript or Typescript to calculate the distance in miles and feet between these points. const latsLngs = [ { lat: 40.78340415946297, lng: -73.971427388 ...

The error message "Directive does not contain a property called 'element'.ts" is displayed

I'm encountering an issue where the property 'element' is not recognized on 'directive'. I am currently working on implementing functionalities for directives. import { Directive, ElementRef, HostListener } from '@angular/cor ...

The process of invoking the parent class's Symbol.iterator function from the child class's Symbol.iterator can be achieved by following a specific

I have two TypeScript classes defined below. class BaseIter { constructor(public a: number, public b: number, public c: number, public d: number){} *[Symbol.iterator](): Iterator<number> { yield this.a yield this.b yield this.c y ...

Identify when a browser tab is closed and determine which specific tab out of all the open tabs was closed

Is there a way to identify when a browser or tab is closed in Angular/JavaScript? I would like to know if there are specific events that can be used for detecting these actions. Any advice, information, or code examples on this topic would be greatly app ...

Utilizing a dictionary for comparing with an API response in order to generate an array of unique objects by eliminating duplicates

I currently have a React component that utilizes a dictionary to compare against an API response for address state. The goal is to map only the states that are returned back as options in a dropdown. Below is the mapping function used to create an array o ...

The Angular directive ng-if does not function properly when trying to evaluate if array[0] is equal to the string value 'Value'

In my code, I want to ensure that the icon is only visible if the value at array index 0 is equal to 'Value': HTML <ion-icon *ngIf="allFamily[0] === 'Value'" class="checkas" name="checkmark"></ion-icon> TS allFamily = [ ...

Each Tab in Ionic2 can have its own unique side menu that opens when selected

In my ionic2 app, I wanted to implement a unique side menu for each of my tabs. Here is what I attempted: I used the command ionic start appname tabs --v2 to create the initial structure. Next, I decided to turn both home.html and contact.html (generated ...

Trying out the results of angular services

Seeking assistance in understanding the current situation: I believe a simple tour of heroes app would be helpful in clarifying, I am looking to set up some tests using Jest to verify if the behavior of a service remains consistent over time. This is ho ...

Leverage the power of the MEAN stack with Angular 2 to seamlessly retrieve data from multiple APIs

Using angular2, nodejs, expressjs, and mongodb for development. I need all APIs to fetch data and display it on an HTML page. Below is the code snippet from my .ts file. view image description here All APIs have been tested and are s ...

Learn the art of efficiently saving scanned documents using the Dynamic Web Twain

I'm having trouble saving documents after scanning in my web app that utilises angular 4. I came across this function in the Twain documentation: function DynamicWebTwain_OnPostTransfer() { var strFileName; var Digital = new Date(); v ...

Material UI offers a feature that allows for the grouping and auto-completion sorting

I am currently utilizing Material UI Autocomplete along with React to create a grouped autocomplete dropdown feature. Here is the dataset: let top100Films = [ { title: "The Shawshank Redemption", genre: "thriller" }, { title: " ...

Typescript is throwing a fit over namespaces

My development environment consists of node v6.8.0, TypeScript v2.0.3, gulp v3.9.1, and gulp-typescript v3.0.2. However, I encounter an error when building with gulp. Below is the code snippet that is causing the issue: /// <reference path="../_all.d. ...

Using React hooks and Typescript: I was expecting to see an assignment or function call, but instead, an expression was

After working as a React developer for quite some time, my workplace recently introduced Typescript, which I am still getting familiar with. I implemented a custom hook for managing cookies, but the function it returns is generating an error. Here's ...

Set the default requests header in Ionic 3 using data stored in Ionic Storage

This particular issue is related to retrieving a value from local storage. I am trying to set the default header (Authorization token) for all requests, but I can't seem to find a solution that works efficiently. Most of the resources available only e ...

Sending data to Dialog Component

While working on implementing the dialog component of material2, I encountered a particular issue: I am aiming to create a versatile dialog for all confirmation messages, allowing developers to input text based on business requirements. However, according ...

Utilizing Angular 2's ngModel feature for dynamic objects and properties

Within my TypeScript file, I am dynamically generating properties on the object named selectedValsObj in the following manner: private selectValsObj: any = {}; setSelectedValsObj(sectionsArr) { sectionsArr.forEach(section => { section.questions. ...