How can one click the button within the expanded dropdown while hovering over the navigation item in Angular and Bootstrap?

Issue Description: Upon hovering over a navigation item, the dropdown container is displayed but it's not clickable.

Desired Behavior: Hovering over a navigation item should display the dropdown container and allow clicking on its contents. Furthermore, when moving away from the navigation item and dropdown container, the container should be hidden.

To access the StackBlitz code example, click on this link

HTML:

 <div class="flex-container">
  <div *ngFor="let item of navigations">
    <ng-container *ngIf="item.type == 'dropdown'">
      <div
        class="dropdown p-0"
        (mouseenter)="showDropdown(item)"
        (mouseleave)="hideDropdown(item)"
      >
        <a
          class="cs-link-white dropdown-toggle"
          href="#"
          role="button"
          data-bs-toggle="dropdown"
          aria-expanded="false"
        >
          {{ item.menuTitle }}
        </a>
      </div>
    </ng-container>
    <ng-container *ngIf="item.type == 'link'">
      <div>
        <a class="cs-link-white" href="#">{{ item.menuTitle }}</a>
      </div>
    </ng-container>
  </div>
</div>
<div
  *ngIf="activeMenu"
  style="height: 200px; width: 100%; background-color: #c8c8c8;"
  class="dropdown-menu"
  [class.show]="isDropdownOpen[activeMenu.menuCode]"
>
  <div>
    Hello from {{ activeMenu.menuCode }}
    <button (click)="triggerAction()">Button</button>
  </div>
</div>

CSS:

.flex-container {
  background-color: #2f333a;
  display: flex;
  align-items: center;
}

.cs-link-white {
  display: flex;
  color: white;
  text-decoration: none;
  font-family: inherit;
  -webkit-box-align: center;
  align-items: center;
  padding: 0 15px;
  min-height: 44px;
  letter-spacing: 0.2px;
  font-size: 14px;
  font-weight: 500;
  font-style: normal;
  line-height: normal;
}

.show {
  display: block;
}

TypeScript Code:

import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';

interface NavigationItem {
  menuTitle: string;
  menuCode: string;
  type: 'dropdown' | 'link';
}

@Component({
  selector: 'app-navigation',
  templateUrl: './navigation.component.html',
  styleUrls: ['./navigation.component.css'],
  standalone: true,
  imports: [CommonModule],
})
export class NavigationComponent {
  activeMenu!: NavigationItem;

  isDropdownOpen: any = {
    dropdown1: false,
    dropdown2: false,
    dropdown3: false,
  };

  navigations: NavigationItem[] = [
    {
      menuTitle: 'Dropdown 1',
      menuCode: 'dropdown1',
      type: 'dropdown',
    },
    {
      menuTitle: 'Dropdown 2',
      menuCode: 'dropdown2',
      type: 'dropdown',
    },
    {
      menuTitle: 'Dropdown 3',
      menuCode: 'dropdown3',
      type: 'dropdown',
    },
    {
      menuTitle: 'Link1',
      menuCode: 'link1',
      type: 'link',
    },
    {
      menuTitle: 'Link2',
      menuCode: 'link2',
      type: 'link',
    },
  };

  constructor() {}

  showDropdown(item: NavigationItem) {
    this.activeMenu = item;
    this.isDropdownOpen[item.menuCode] = true;
  }

  hideDropdown(item: NavigationItem) {
    this.activeMenu = item;
    this.isDropdownOpen[item.menuCode] = false;
  }

  triggerAction() {
    console.log('button clicked');
  }
}

Answer №1

To enable the hover functionality on the dropdown menu, a setTimeout function can be added to toggle the flag when a mouseover event occurs.

import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';

interface NavigationItem {
  menuTitle: string;
  menuCode: string;
  type: 'dropdown' | 'link';
}

@Component({
  selector: 'app-navigation',
  templateUrl: './navigation.component.html',
  styleUrls: ['./navigation.component.css'],
  standalone: true,
  imports: [CommonModule],
})
export class NavigationComponent {
  activeMenu: NavigationItem = {
    menuTitle: 'Dropdown 1',
    menuCode: 'dropdown1',
    type: 'dropdown',
  };

  isDropdownOpen: any = {
    our_products: false,
    home_kitchen: false,
    toys: false,
    dropdown2: false,
    dropdown3: false,
  };

  navigations: NavigationItem[] = [
    {
      menuTitle: 'Dropdown 1',
      menuCode: 'dropdown1',
      type: 'dropdown',
    },
    {
      menuTitle: 'Dropdown 2',
      menuCode: 'dropdown2',
      type: 'dropdown',
    },
    {
      menuTitle: 'Dropdown 3',
      menuCode: 'dropdown3',
      type: 'dropdown',
    },
    {
      menuTitle: 'Dropdown 4',
      menuCode: 'dropdown4',
      type: 'dropdown',
    },
    {
      menuTitle: 'Dropdown 5',
      menuCode: 'dropdown5',
      type: 'dropdown',
    },
    {
      menuTitle: 'Dropdown 6',
      menuCode: 'dropdown6',
      type: 'dropdown',
    },
    {
      menuTitle: 'Link1',
      menuCode: 'link1',
      type: 'link',
    },
    {
      menuTitle: 'Link2',
      menuCode: 'link2',
      type: 'link',
    },
  ];

  isDropdownOpenv1 = false;

  constructor() {}

  showDropdown(item: NavigationItem) {
    this.activeMenu = item;
    this.isDropdownOpen[item.menuCode] = true;
  }

  hideDropdown(event: any, item: NavigationItem) {
    console.log(event);
    const relatedTarget = event?.relatedTarget;
    if (relatedTarget?.classList.contains('dropdown-menu')) {
      return;
    }
    this.activeMenu = item;
    setTimeout(() => {
      this.isDropdownOpen[item.menuCode] = false;
    });
  }

  isMobileView(): boolean {
    return window.innerWidth < 992;
  }

  showDropdownv1() {
    this.isDropdownOpenv1 = true;
  }

  hideDropdownv1() {
    this.isDropdownOpenv1 = false;
  }

  triggerAction() {
    this.isDropdownOpen[this.activeMenu.menuCode] = false;
    console.log('button clicked');
  }
}

stackblitz

Answer №2

To enhance your dropdown functionality, simply incorporate mouse enter and mouse leave events into the code for your dropdown menu element. This will allow you to easily show and hide the dropdown as needed.

Example Code

<div
  *ngIf="showDropdown"
  (mouseenter)="handleMouseEnter()"
  (mouseleave)="handleMouseLeave()"
  style="height: 200px; width: 100%; background-color: #c8c8c8;"
  class="dropdown-menu"
  [class.show]="isDropdownVisible"
>
  <div>
    Hello from Dropdown Menu
    <button (click)="performAction()">Button</button>
  </div>
</div>

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

New Entry failing to appear in table after new record is inserted in CRUD Angular application

Working with Angular 13, I developed a basic CRUD application for managing employee data. Upon submitting new information, the createEmployee() service is executed and the data is displayed in the console. However, sometimes the newly created entry does no ...

Design a TypeScript interface inspired by a set static array

I am working with an array of predefined strings and I need to create an interface based on them. To illustrate, here is an example of pseudo-interfaces: const options = ["option1", "option2", "option3"]; interface Selection { choice: keyof options; ...

Include a fresh attribute in the Interface

How can I include a boolean property isPhotoSelected: boolean = false; in an API interface that I cannot modify? The current interface looks like this: export interface LibraryItem { id: string; photoURL: string; thumbnailURL: string; fi ...

Create a single datetime object in Ionic (Angular) by merging the date and time into a combined string format

I have a string in an ionic project that contains both a date and time, and I need to merge them into a single datetime object for sending it to the server const date = "Fri Jan 07 2022 13:15:40 GMT+0530 (India Standard Time)"; const time = " ...

Error TS2322: Type 'boolean' cannot be assigned to type 'undefined'. What is the best approach for dynamically assigning optional properties?

I am currently working on defining an interface named ParsedArguments to assign properties to an object, and here is what it looks like: import {Rules} from "../Rules/types/Rules"; export interface ParsedArguments { //other props //... ...

Erase Typescript Service

To remove a PostOffice from the array based on its ID, you can use a checkbox to select the desired element and then utilize its ID for the delete function. Here is an example: let postOffices = [ {postOfficeID: 15, postCode: '3006&ap ...

Utilize useEffect to track a single property that relies on the values of several other properties

Below is a snippet of code: const MyComponent: React.FC<MyComponentProps> = ({ trackMyChanges, iChangeEverySecond }) => { // React Hook useEffect has missing dependencies: 'iChangeEverySecond' useEffect(() => { ...

Introducing ngrx data - the ultimate collection service and data service that offers a custom endpoint

For my entity in ngrx/data, I required a custom PUT request and wanted to ensure its accuracy. Let's say I have a movie library where I can add tags to movies using a PUT request. This is my data service: export class MovieDataService extends Default ...

The PrimeNG dialog component stubbornly refuses to close even when clicking outside the modal

My modal dialog component from PrimeNG is structured like this <p-dialog header="{{title}}" [(visible)]="display" [modal]="true" [dismissableMask]="true" [closeOnEscape]="true" [responsive]="true" [closable]="false" > {{content}} </p-dialog&g ...

Create collaborative documents with serverless TypeScript extension

Utilizing Amazon Lambda AWS along with Serverless and the Serverless Plugin TypeScript to develop my TypeScript files has been quite a challenge. I have implemented shared code in my project, organized within folders such as: /shared: shared1.ts, shared2. ...

Eliminating an item from an array with the help of React hooks (useState)

I am facing an issue with removing an object from an array without using the "this" keyword. My attempt with updateList(list.slice(list.indexOf(e.target.name, 1))) is only keeping the last item in the array after removal, which is not the desired outcome. ...

Issues with implementing AddEventListener in InAppBrowser on IONIC 2

I am currently working on implementing AddeventListener to listen for 'Exit' and 'LoadStart' events in InAppBrowser within IONIC2. Here is my HTML: <button (click)="browsersystem('https://www.google.com')" > Visit URL& ...

Repeatedly view the identical file on HTML

I'm currently working with the following HTML code: <input type="file" style="display: none" #file(change)="processImage($event)" /> <button type="button" class="btn" (click)="file.click()" Browse </button> When I select image1 fr ...

What is the method for extracting the types of parameters from a function type while excluding a single parameter?

Suppose I have the following interface that defines a function: export declare interface NavigationGuard { (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext): NavigationGuardReturn | Promise<NavigationGuardReturn ...

Tips for utilizing callback function in Angular 4

I previously used the Google API to obtain a current address and now I want to incorporate a callback function in this process using Angular 4. How can I go about implementing it? let geocoder = new google.maps.Geocoder(); geocoder.geocode({ &ap ...

Navigating through a node tree and making changes to its configuration and content

Here's the input I have. Some nodes have downlines with multiple other nodes nested inside. data = [ { "user_id": "1", "username": "johndoe001", "amount": "0.00", "down ...

The mat-autocomplete feature is sending multiple requests to the server instead of just one

After inputting a few characters, my code is designed to make a GET request and auto-complete the returned JSON object. However, I noticed that even after stopping typing for a few seconds, the backend is being hit multiple times rather than just once (I h ...

Hold off until the operation finishes executing and then deliver Angular 6

Is there a way to delay the subscribe function until my logic is complete and the transform method has updated the keys object? transform(value: any, args:string) : any { let keys = []; this.http.get('src/app/enum-data/enum.json').subsc ...

Basic library using babel, TypeScript, and webpack - Error: (...) is not a recognized function; within Object.<anonymous>

Recently, I encountered a strange issue while trying to bundle a simple function using babel, typescript, and webpack. You can find the example that is not working at this link. To test it, simply download the code, run npm/yarn install, npm/yarn run buil ...

Is there a different term I can use instead of 'any' when specifying an object type in Typescript?

class ResistorColor { private colors: string[] public colorValues: {grey: number, white: number} = { grey: 8, white: 9 } } We can replace 'any' with a specific type to ensure proper typing in Typescript. How do we assign correct ...