Switch the ngClass on the appropriate ancestor element for the dropdown menu

Utilizing Angular CLI version 8.3.0, I aim to construct a sidebar featuring a drop-down menu. My objective is to apply the "open" class to toggle the opening of the drop-down section. However, the current challenge I am encountering is that when I click to open a drop-down menu, all drop-downs are triggered to open simultaneously. What I desire is for only the clicked drop-down to open. Furthermore, I would like the currently opened drop-down to close automatically if I click on another menu item to open a different drop-down.

Below is the component.html markup:

<li class="nav__item"
    (click)="toggleShowDiv('divA')"
    >
  <a target="_self">
    <mat-icon svgIcon="ic-corp-setup"></mat-icon>
    <span class="nav__text">Corp setup</span>
  </a>
  <ul class="nav-sub divA" [@slideInOut]="animationState">
    <li><a href="">Menu 1</a></li>
    <li><a href="">Menu 2</a></li>
    <li><a href="">Menu 3</a></li>
  </ul>
</li>

<li class="nav__item"
    (click)="toggleShowDiv('divB')"
    >
  <a target="_self">
    <mat-icon svgIcon="ic-corp-setup"></mat-icon>
    <span class="nav__text">Corp setup</span>
  </a>
  <ul class="nav-sub divB" [@slideInOut]="animationState">
    <li><a href="">Menu 1</a></li>
    <li><a href="">Menu 2</a></li>
    <li><a href="">Menu 3</a></li>
  </ul>

Within my component.ts file:

animationState = 'in';
  toggleShowDiv(divName: string) {
    if (divName === 'divA') {
      console.log(this.animationState);
      this.animationState = this.animationState === 'out' ? 'in' : 'out';
      console.log(this.animationState);
    }
  }

Here's an excerpt from animations.ts:

import {
  trigger, state, style, transition,
  animate, group, query, stagger, keyframes
} from '@angular/animations';

export const SlideInOutAnimation = [
  trigger('slideInOut', [
    state('in', style({
      'max-height': '500px', 'opacity': '1', 'visibility': 'visible'
    })),
    state('out', style({
      'max-height': '0px', 'opacity': '0', 'visibility': 'hidden'
    })),
    transition('in => out', [group([
      animate('400ms ease-in-out', style({
        'opacity': '0'
      })),
      animate('600ms ease-in-out', style({
        'max-height': '0px'
      })),
      animate('700ms ease-in-out', style({
        'visibility': 'hidden'
      }))
    ])]),
    transition('out => in', [group([
      animate('1ms ease-in-out', style({
        'visibility': 'visible'
      })),
      animate('600ms ease-in-out', style({
        'max-height': '500px'
      })),
      animate('800ms ease-in-out', style({
        'opacity': '1'
      }))
    ])])
  ]),
]

I do not wish to rely on classes such as "divA" or "divB" as I intend to create a dynamic menu system.

While suggestions within this context are encouraged, I remain receptive to alternative solutions. Any assistance provided is greatly valued.

Answer №1

To effectively manage the current selected item, you can implement the following approach.

your-component.component.ts

currentSelectedItem: string;

toggleShowDiv (item) {
 // Allow for opening a different menu directly

 if (item === this.currentSelectedItem) {
  // Toggle functionality to switch between showing and hiding
  this.animationState = this.animationState === 'out' ? 'in' : 'out'; 
 } else {
   this.currentSelectedItem = item;
   // Show the newly selected item directly
    this.animationState = 'in';
 }
}

In your HTML view, you can implement the following structure.

your-component.component.html

<li class="nav__item"
    (click)="toggleShowDiv('divA')"
    >
  <a target="_self">
    <mat-icon svgIcon="ic-corp-setup"></mat-icon>
    <span class="nav__text">Corp setup</span>
  </a>
  <ul class="nav-sub divA" [@slideInOut]="currentSelectedItem === 'divA' ? animationState : 'out'">
    <li><a href="">Menu 1</a></li>
    <li><a href="">Menu 2</a></li>
    <li><a href="">Menu 3</a></li>
  </ul>
</li>

Repeat the same process for other elements as needed.

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

How to resolve useState problem in useEffect when state is not null

Encountering issues with maintaining state in TypeScript React. A Child component passes a 'terminal' object to the Parent via a function called returnTerminal(). This 'terminal' object is then stored as a useState variable named _obje ...

Dealing with implicit `any` when looping through keys of nested objects

Here is a simplified example of the issue I am facing: const testCase = {a:{b:"result"}} for (const i in testCase) { console.log("i", i) for (const j in testCase[i]){ console.log("j", j) } } Encountering ...

Tips on concealing the scrollbar only when a particular element is visible

I inserted the following code into my index.html file: <head> <style> body::-webkit-scrollbar { display: none; } </style> </head> This code successfully hides the scrollbar. My goal is to only h ...

Display the output of JSON.stringify in a neatly formatted table

After sending my table data to the database using ajax, I am now trying to retrieve it by clicking on the open button. $.ajax({ type: "POST", url: "http://localhost/./Service/GetPageInfo", dataType: "json", ...

Every file downloaded through the iframe is automatically stored in a designated server folder

Is it possible for my website to have an iframe that enables users to browse the web, and when they click on a download button on any external website, the file can be saved directly to a specific folder on my server instead of their own computer? I'm ...

The absence of HttpOnly Secure Cookies being transmitted

Here we go again, another inquiry regarding httpOnly Cookies. Seems like many others are facing the same predicament as me. Even though I receive the cookie from the server, it doesn't accompany other requests. I have mysite.example.com in angularj ...

Leveraging both closetag.js and closebrackets.js simultaneously in Codemirror on a single line

Currently, I am integrating the Codemirror library with a textarea to enable autoclosing of HTML tags and brackets such as {}, (), []. However, I have come across an issue where they do not work together on the same line. For example, when typing out a ta ...

Can you explain how I can declare a variable to store a scraped element in Puppeteer?

const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ headless: false, defaultViewport: null }) const page = await browser.newPage() await page.goto('https://www.supre ...

Creating repeatable texture patterns in Three.js

Hello, I have developed a basic renderer for my 3D objects that are generated using PHP. While I am able to successfully render all the objects, I am facing some major issues with textures. Currently, the texture I am using is sized at 512x512 pixels. I ...

Navigating the missing "length" property when dealing with partial functions generated using lodash's partialRight

I've been utilizing MomentTimezone for time manipulation within the browser. My development stack includes TypeScript and Lodash. In my application, there is an accountTimezone variable set on the window object which stores the user's preferred ...

Exploring JSON data in Angular 7 by leveraging services

I am working on a node server which is returning the following JSON data: { "ResponseStatus": { "ResponseCode": 0, "ResponseMessage": "Success." }, "Events": [ { "CodEspec": 65957, ...

Interactive Range Slider for Scrolling Through Div Content

I am currently facing an issue where I want to implement a HTML range slider for controlling the horizontal scrolling of a div located below. This functionality is similar to that of a scroll bar, but it will be positioned away from the scrollable content ...

Styles brought in from external sources do not get applied to components

My goal is to create a separate file specifically for storing styles targeted at IE 9-11. In order to achieve this, I have created a file named InternetExplorer.scss and imported it into my main file styles.scss: @import "scss/InternetExplorer.scss"; The ...

Having trouble obtaining outcomes from Cloud Code in Parse

After struggling with this issue for quite some time, I have reached a point where I feel the need to seek help. I am working on a cloud code function that is supposed to retrieve a list of categories along with their respective products. Each category con ...

Toggle the visibility of a section in an external .js file

Is there a way to toggle the display of answers from an external .js file using a button? If I were able to modify the code, I could wrap the answers in a div. However, since it's an external .js file, is this feasible? Here's the fiddle and cod ...

Trouble with passing data from action to reducer in Redux with React Native

As a newcomer to Redux, I'm encountering an issue while trying to make an API call in the Action and pass the data to the reducer. Although I can see the response from the API call, there seems to be a problem with sharing the data correctly with the ...

Determine the size of an SVG while taking into consideration any strokes applied

Is there a way to seamlessly position an SVG in the corner of a div, despite having a dynamically generated stroke? Calculating the distance to the outermost part of the border proves difficult when dealing with irregular shapes like stars. Here's my ...

Trigger/cease cron job with the click of a button within a Node.js Express application

I have been working on a project that involves starting and stopping a cron scheduler when a user interacts with a button on the front end. Essentially, clicking the start button initiates the cron job, while clicking the stop button halts the timer. It&ap ...

Guide to reference points, current one is constantly nonexistent

As I work on hosting multiple dynamic pages, each with its own function to call at a specific time, I encounter an issue where the current ref is always null. This poses a challenge when trying to access the reference for each page. export default class Qu ...

The error encountered states that in the Angular typescript method, the term "x" is not recognized as a

In my codebase, I have an entity named Epic which contains a method called pendingTasks() within a class. import { Solution } from '../solutions.model'; import { PortfolioKanban } from '../kanban/portfolio-kanban.model'; import { Kanban ...