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

Prevent ESLint from linting files with non-standard extensions

My .estintrc.yaml: parser: "@typescript-eslint/parser" parserOptions: sourceType: module project: tsconfig.json tsconfigRootDir: ./ env: es6: true browser: true node: true mocha: true plugins: - "@typescript-eslint" D ...

Disabling the experimental app directory feature in NextJs

I've been working on a real-life project and decided to test out the new App directory feature that comes with Next.js version 13. However, I encountered some issues such as images and fonts not loading properly. Now, I'm looking to opt out of th ...

How to pass a JSON object to a component's constructor in Angular 2

In a unique situation, my primary component config.editor.component performs extensive processing and generates various JSON objects. I am content with this approach. The template for this component then proceeds to render another component - api.entry.com ...

Can someone provide guidance on utilizing the map function to iterate through intricate components in TypeScript?

I am facing a challenge while trying to iterate through a complex object containing 'inner objects'. When using the map function, I can only access one level below. How can I utilize map and TypeScript to loop through multiple levels below? Whene ...

Having trouble with Next.js 13 GitHub OAuth integration - it keeps redirecting me to Discord instead of signing me in

There's a perplexing issue troubling my application... The implementation of OAuth 2 with GitHub, Discord, and Google is causing some trouble. While Google and Discord authentication works smoothly, attempting to sign in via GitHub redirects me to Di ...

Angular removing every query string parameters

Linked to but distinct from: How to maintain query string parameters in URL when accessing a route of an Angular 2 app? I am facing an issue with my basic Angular application where adding a query parameter results in its removal, both from the browser&apo ...

Implementing webrtc functionality in Angular 2: A beginner's guide

I attempted to integrate webrtc into my Angular 2 TypeScript project and encountered the following error: navigation.getUserMedia is not a function. Below is the code I used: ngOnInit(): void { navigator.getUserMedia(this.constraints, stream =& ...

Tips for guaranteeing the shortest possible period of operation

I am in the process of constructing a dynamic Angular Material mat-tree using data that is generated dynamically (similar to the example provided here). Once a user expands a node, a progress bar appears while the list of child nodes is fetched from the ...

What is the process for including a resource parameter in the acquireTokenSilent method of an MSAL instance within an Angular application?

const requestToken = { permissions: ['view_only'], }; newToken = await this.authInstance.acquireTokenSilent(requestToken); I'm trying to include the client ID of my Web API as a resource parameter when requesting the access token. Strugg ...

Center align the mat-expansion-panel material component in a vertical orientation

When working with the mat-expansion-panel component alongside a mat-accordion, I've encountered an issue where the items are not aligning vertically at the center/middle. I'm unsure of the proper method to achieve vertical alignment for the conte ...

Establishing the initial state in React

Can someone help me with setting the default state in React? I'm working on a project that allows files to be dropped onto a div using TypeScript and React. I want to store these files in the state but I'm struggling with initializing the default ...

What causes the Angular router URL to vary from the document location on reload while employing CanActivate?

My Angular 2 router setup seems to be causing some issues. When I refresh the page, I've noticed that the router object's URL value is different from the location.hash property of the document. For example, when I check router.url, I get "/", bu ...

I am attempting to code a program but it keeps displaying errors

What is hierarchical inheritance in AngularJS? I have been attempting to implement it, but I keep encountering errors. import {SecondcomponentComponent} from './secondcomponent/secondcomponent.Component'; import {thirdcomponentcomponent} from & ...

Step-by-step guide to conducting a security audit for an Angular project using OWASP dependency check

Struggling to find the correct steps to run OWASP dependency check for my Angular project. I would greatly appreciate if someone could provide a detailed, step-by-step guide. ...

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++)); ...

compileOnSave has ceased to function

After successfully building my ng4 project with "@angular/material": "^2.0.0-beta.6" and having the compileOnSave feature work fine, I decided to add the following dependencies: "@ngx-translate/core": "^8.0.0", "@ngx-translate/http-loader": "^2.0.0", "an ...

The Ion-icon fails to appear when it is passed as a prop to a different component

On my Dashboard Page, I have a component called <DashHome /> that I'm rendering. I passed in an array of objects containing icons as props, but for some reason, the icons are not getting rendered on the page. However, when I used console.log() t ...

Facing the issue of "Protractor not syncing with the page" while trying to navigate an Angular website

I'm currently attempting to follow the tutorial for Protractor on the official Protractor website, but I've hit a roadblock at step 0. My setup involves using protractor and webdriver-manager version 6.0.0. I am running Linux (Ubuntu 18.06) as m ...

Issues with Angular routing after upgrading to Angular 4

After making updates in this way, they can be found here To update on Linux/Mac: run the command npm install @angular/{common,compiler,compiler-cli,core,forms,http,platform-browser,platform-browser-dynamic,platform-server,router,animations}@latest type ...

Is it possible to customize a row with checkboxes in ng2-smart-table when creating a new row?

When adding a new row, I would like a checkbox in the Status column and an input text field in the Image column. You can see an example image here. ...