首页 > 解决方案 > 当使用 enter 键打开新的 NgbDropdowns 时,如何关闭先前打开的 NgbDropdowns?

问题描述

我是 NgbDropdown 和相关 ng-bootstrap 代码的新手,当使用回车键打开新的 NgbDropdowns 时,我无法弄清楚如何关闭所有以前的 NgbDropdowns。

我在我的 Angular 项目的一个页面上创建了许多 NgbDropdowns,我发现当我从下拉按钮单击到下拉按钮时,之前打开的下拉菜单会关闭;但是,如果我从一个打开的下拉菜单中选择 TAB 到另一个下拉按钮并使用 enter 键打开第二个下拉菜单,这可能是可访问性所需要的,第一个下拉菜单不会关闭。我留下了两个相互重叠的下拉菜单。

可以在https://ng-bootstrap.github.io/#/components/dropdown/examples的主要 NgbDropdown 示例页面上复制此序列:在不同的按钮上(顶部的第一个示例。)

顺序: 1. Tab 切换到“Toggle Dropdown” 2. 按回车键打开下拉列表 3. Tab 通过下拉选项,再加一次,这样您就切换到了“切换下拉”按钮。4. 按回车键 5. 两个下拉菜单将同时打开。

截屏

因此,当在其他按钮上按下回车键时,显然关闭先前单击下拉菜单的代码不起作用。没有找到太多关于可以在 typescript 中使用各种 Ngb 对象做什么的文档,我不知道在使用 enter 键打开新下拉列表时如何关闭所有以前的下拉列表。我能想到的只有:

1) 遍历 ts 文件中的所有下拉列表,在打开最新的之前关闭它们。如果这是最好的解决方案,我看不出有任何方法可以循环打开一组下拉列表。作为 NgbSolution 的一部分,我是否可以使用这样的对象/数组,还是我必须自己将每个对象/数组添加到数组中?

2)当在按钮上按下回车键时触发点击事件。同样,我不知道如何让一个事件在 NgbDropdown 对象上触发另一个事件。

任何指针将不胜感激。我没有在这里发布我的代码,因为它与上面引用的基本示例相同。

标签: ng-bootstrap

解决方案


对于您的建议 #1(遍历所有下拉菜单并关闭它们),您可以按如下方式实现它:

  1. 在您的 HTML 中,使用模板引用变量#语法)将每个下拉列表声明为 DOM 变量:
    <div ngbDropdown class="d-inline-block" #dd1="ngbDropdown">
    ...
    </div>
  1. 如下添加一个click处理程序button。这允许您将对下拉列表的引用传递给单击处理程序调用的函数:
     <button class="btn btn-outline-primary" id="dropdownBasic1" ngbDropdownToggle (click)="closeOthers(dd1)">Toggle dropdown</button>

下拉列表的完整 HTML 应如下所示:

<div ngbDropdown class="d-inline-block" #dd1="ngbDropdown">
    <button class="btn btn-outline-primary" id="dropdownBasic1" ngbDropdownToggle (click)="closeOthers(dd1)">
        Toggle dropdown
    </button>
    <div ngbDropdownMenu aria-labelledby="dropdownBasic1">
        <button ngbDropdownItem>Action - 1</button>
        <button ngbDropdownItem>Another Action</button>
        <button ngbDropdownItem>Something else is here</button>
    </div>
</div>
  1. 添加以下内容作为 Typescript 组件的类变量。这允许您从 Typescript 文件中引用组件中显示的所有下拉列表:
@ViewChildren(NgbDropdown) dropdowns: QueryList<NgbDropdown>;
  1. click向您的 Typescript 组件添加一个函数:
  closeOthers(clickedDropdown: NgbDropdown) {
    // Close all dropdowns
    this.dropdowns.toArray().forEach(el => {
        el.close();
    });
    // Open the dropdown that was clicked on
    clickedDropdown.open();
  }

现在,每当您单击下拉菜单(或通过 Tab 键和按回车键选择它)时,它都会调用以下closeOthers函数:

  • 关闭所有下拉菜单
  • 打开被点击的下拉菜单

请参阅此 StackBlitz以获取工作演示。

@Dordrecht - 我将为您在下面的评论中提到的功能采取的方法是创建如下服务:

export class ModalNotificationService {

    private _closeModals: Subject<void> = new Subject<void>();
    private _closeModals$: Observable<void> = this._closeModals.asObservable();

    public emitCloseModalEvent() {
        this._closeModals.next();
    }

    get closeModals$(): Observable<void> {
        return this._closeModals$;
    }

}

该服务将被注入任何具有模态的组件中,并且这些组件将订阅可观察closeModals$对象,然后在它们自己的组件中关闭模态。修改closeOthers方法以调用新服务的emitCloseModalEvent方法来通知所有其他组件。


推荐阅读