Merged PR 1937: fix(ui-input-controls-dropdown): prevent multiple dropdowns from being open s...

fix(ui-input-controls-dropdown): prevent multiple dropdowns from being open simultaneously

Add DropdownService to manage global dropdown state and ensure only one
dropdown is open at any time. When a new dropdown opens, any previously
opened dropdown is automatically closed, improving user experience and
preventing UI conflicts.

Ref: #5298
This commit is contained in:
Nino Righi
2025-09-03 13:19:10 +00:00
committed by Andreas Schickinger
parent c52f18e979
commit 39984342a6
2 changed files with 46 additions and 0 deletions

View File

@@ -20,6 +20,7 @@ import { ActiveDescendantKeyManager, Highlightable } from '@angular/cdk/a11y';
import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
import { isEqual } from 'lodash';
import { DropdownAppearance } from './dropdown.types';
import { DropdownService } from './dropdown.service';
@Component({
selector: 'ui-dropdown-option',
@@ -117,6 +118,8 @@ export class DropdownOptionComponent<T> implements Highlightable {
export class DropdownButtonComponent<T>
implements ControlValueAccessor, AfterViewInit
{
#dropdownService = inject(DropdownService);
readonly init = signal(false);
private elementRef = inject(ElementRef);
@@ -206,11 +209,13 @@ export class DropdownButtonComponent<T>
} else {
this.keyManger?.setFirstItemActive();
}
this.#dropdownService.open(this); // #5298 Fix
this.isOpen.set(true);
}
close() {
this.isOpen.set(false);
this.#dropdownService.close(this); // #5298 Fix
}
focusout() {

View File

@@ -0,0 +1,41 @@
import { Injectable, signal } from '@angular/core';
import { DropdownButtonComponent } from './dropdown.component';
/**
* Service zur Verwaltung des globalen Dropdown-Zustands.
*
* Stellt sicher, dass immer nur ein Dropdown gleichzeitig geöffnet ist.
* Wenn ein neues Dropdown geöffnet wird, wird ein zuvor geöffnetes automatisch geschlossen.
*/
@Injectable({ providedIn: 'root' })
export class DropdownService {
/**
* Signal, das die aktuell geöffnete Dropdown-Instanz hält.
* Ist `null`, wenn kein Dropdown geöffnet ist.
*/
private _openDropdown = signal<DropdownButtonComponent<any> | null>(null);
/**
* Öffnet ein Dropdown und schließt ein zuvor geöffnetes automatisch.
*
* @param dropdown - Die Dropdown-Komponente, die geöffnet werden soll
*/
open(dropdown: DropdownButtonComponent<any>) {
const current = this._openDropdown();
if (current && current !== dropdown) {
current.close();
}
this._openDropdown.set(dropdown);
}
/**
* Schliesst ein Dropdown, falls es aktuell als geöffnet registriert ist.
*
* @param dropdown - Die Dropdown-Komponente, die geschlossen werden soll
*/
close(dropdown: DropdownButtonComponent<any>) {
if (this._openDropdown() === dropdown) {
this._openDropdown.set(null);
}
}
}