Search code examples
angularngx-bootstrap

How do I call a directive's method when there are multiple instances of directive in same template?


I have a navbar with multiple dropdown menus. I'm using a directive provided by ngx-bootstrap to handle dropdown behavior. I want to add custom functionality by opening the dropdowns on mouseover and closing them on mouseout. I need to call the BsDropdownToggleDirective's onEsc() function on mouseout. When I implement this with @ViewChild, it works only for the first dropdown, but not the second. When I remove the first dropdown, then the second dropdown works. How can I call onEsc() for whichever dropdown is open?

top-menu-links.component.ts

import { Component, ViewChild } from '@angular/core';
import { BsDropdownToggleDirective } from 'ngx-bootstrap/dropdown';

@Component({
    selector: 'top-nav-main',
    templateUrl: './top-menu-links.component.html',
    // styleUrls: [ './top-menu-links.component.scss' ]
})
export class TopMenuLinksComponent {
    @ViewChild(BsDropdownToggleDirective) dropdown:BsDropdownToggleDirective;

    public closeDropdown():void {
        this.dropdown.onEsc();
    }

}

top-menu-links.component.html

<li class="dropdown" bsDropdown triggers="mouseover" >
                <a bsDropdownToggle dropdown-toggle data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" (mouseout)="closeDropdown()">Features<span class="caret"></span></a>
                <ul class="dropdown-menu" *bsDropdownMenu>
                    <li class="nav-item"><a class="nav-link" routerLink="feature-1">Feature 1</a></li>
                    <li class="nav-item"><a class="nav-link" routerLink="feature-2">Feature 2</a></li>
                    <li class="nav-item"><a class="nav-link" routerLink="feature-3">Feature 3</a></li>
                </ul>
            </li>
            <li class="dropdown" bsDropdown triggers="mouseover">
                <a bsDropdownToggle dropdown-toggle data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" (mouseout)="closeDropdown()">Company<span class="caret"></span></a>
                <ul class="dropdown-menu" *bsDropdownMenu>
                    <li class="nav-item"><a class="nav-link" routerLink="app-about-us">About</a></li>
                    <li class="nav-item"><a class="nav-link" routerLink="app-faq">Frequently Asked Questions</a></li>
                    <li class="nav-item"><a class="nav-link" routerLink="app-contact-us">Contact</a></li>
                </ul>
            </li>

Solution

  • As mentioned above, you have to use @ViewChildren decorator. Please give a try with this:

    import { Component, ViewChildren, QueryList } from '@angular/core';
    import { BsDropdownToggleDirective } from 'ngx-bootstrap/dropdown';
    
    @Component({
        selector: 'top-nav-main',
        templateUrl: './top-menu-links.component.html',
        // styleUrls: [ './top-menu-links.component.scss' ]
    })
    export class TopMenuLinksComponent {
        @ViewChildren(BsDropdownToggleDirective) dropdowns: QueryList<BsDropdownToggleDirective>;
    
        public closeDropdown():void {
            this.dropdowns.forEach((dropdown) => {
              dropdown.onEsc()
           })
        }
    
    }