【问题标题】:How would one close previously opened NgbDropdowns when new NgbDropdowns are opend using the enter key?当使用 enter 键打开新的 NgbDropdown 时,如何关闭先前打开的 NgbDropdown?
【发布时间】:2019-12-20 16:33:34
【问题描述】:

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

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

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

顺序: 1.标签到“切换下拉” 2.按回车键打开下拉菜单 3. 浏览下拉选项,再点击一次,这样你就已经 标签到“切换下拉”按钮。 4.按回车键 5. 两个下拉菜单将同时打开。

Screen Shot

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

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

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

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

【问题讨论】:

    标签: ng-bootstrap


    【解决方案1】:

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

    1. 在您的 HTML 中,使用 Template Reference Variables# 语法)将每个下拉列表声明为 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. 向您的 Typescript 组件添加 click 函数:
      closeOthers(clickedDropdown: NgbDropdown) {
        // Close all dropdowns
        this.dropdowns.toArray().forEach(el => {
            el.close();
        });
        // Open the dropdown that was clicked on
        clickedDropdown.open();
      }
    

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

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

    请参阅this 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方法通知所有其他组件。

    【讨论】:

    • 优秀的答案,伊恩 A。谢谢!我们有一种情况,我们还需要关闭其他组件中生成的下拉菜单,您的回答没有涵盖,但这是我之前没有提及的错。你的答案是,我有信心,这是一个重要的、必要的难题。
    • @Dordrecht 没问题。我已经使用您在评论中提到的一般方法编辑了我的答案(请注意,这不是您在评论中提出的问题的完整答案,而且我没有机会测试完全没有)。如果有机会,我会尝试将 StackBlitz 放在一起,展示它是如何工作的。
    • @Dordrecht 刚刚打开了a StackBlitz,它关闭了其他组件中的下拉菜单。希望这就是你所追求的
    • 谢谢你,伊恩 A!回复晚了非常抱歉。一位同事通过将上次打开的下拉菜单存储在服务中,然后在打开下一个下拉菜单时关闭该下拉菜单,解决了这一挑战。感谢您的解决方案,它看起来是一个可行的替代方案,并且还提供了一个很好的示例来说明如何遍历下拉列表。我知道这会派上用场的。
    猜你喜欢
    • 1970-01-01
    • 2012-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-25
    • 1970-01-01
    相关资源
    最近更新 更多