Skip to content

Commit

Permalink
fix(dropdown): support autoClose when several dropdowns exist
Browse files Browse the repository at this point in the history
Fixes #687

Closes #785
  • Loading branch information
pkozlowski-opensource committed Sep 22, 2016
1 parent f6b1dca commit e2e7c1b
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 17 deletions.
43 changes: 37 additions & 6 deletions src/dropdown/dropdown.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('ngb-dropdown', () => {

it('should initialize inputs with provided config', () => {
const defaultConfig = new NgbDropdownConfig();
const dropdown = new NgbDropdown(new NgbDropdownConfig);
const dropdown = new NgbDropdown(defaultConfig);
expect(dropdown.up).toBe(defaultConfig.up);
expect(dropdown.autoClose).toBe(defaultConfig.autoClose);
});
Expand Down Expand Up @@ -284,7 +284,7 @@ describe('ngb-dropdown-toggle', () => {
expect(dropdownEl).toHaveCssClass('open');
});

it('should not close on item click', () => {
it('should close on item click', () => {
const html = `
<div ngbDropdown [open]="true">
<button ngbDropdownToggle>Toggle dropdown</button>
Expand All @@ -296,7 +296,6 @@ describe('ngb-dropdown-toggle', () => {
const fixture = createTestComponent(html);
const compiled = fixture.nativeElement;
let dropdownEl = getDropdownEl(compiled);
let buttonEl = compiled.querySelector('button');
let linkEl = compiled.querySelector('a');

fixture.detectChanges();
Expand All @@ -305,12 +304,44 @@ describe('ngb-dropdown-toggle', () => {
linkEl.click();
fixture.detectChanges();
expect(dropdownEl).not.toHaveCssClass('open');
});


it('should close on other dropdown click', () => {
const html = `
<div ngbDropdown>
<button ngbDropdownToggle>Toggle dropdown 1</button>
<div class="dropdown-menu">
<a class="dropdown-item">Action 1</a>
</div>
</div>
<div ngbDropdown>
<button ngbDropdownToggle>Toggle dropdown 2</button>
<div class="dropdown-menu">
<a class="dropdown-item">Action 2</a>
</div>
</div>`;

const fixture = createTestComponent(html);
const compiled = fixture.nativeElement;

const buttonEls = compiled.querySelectorAll('button');
const dropdownEls = compiled.querySelectorAll('div[ngbDropdown]');

buttonEl.click();
fixture.detectChanges();
expect(dropdownEl).toHaveCssClass('open');
});
expect(dropdownEls[0]).not.toHaveCssClass('open');
expect(dropdownEls[1]).not.toHaveCssClass('open');

buttonEls[0].click();
fixture.detectChanges();
expect(dropdownEls[0]).toHaveCssClass('open');
expect(dropdownEls[1]).not.toHaveCssClass('open');

buttonEls[1].click();
fixture.detectChanges();
expect(dropdownEls[0]).not.toHaveCssClass('open');
expect(dropdownEls[1]).toHaveCssClass('open');
});

describe('Custom config', () => {
let config: NgbDropdownConfig;
Expand Down
43 changes: 32 additions & 11 deletions src/dropdown/dropdown.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Directive, Input, Output, HostListener, EventEmitter} from '@angular/core';
import {Directive, Input, Output, EventEmitter, ElementRef} from '@angular/core';
import {NgbDropdownConfig} from './dropdown-config';

/**
Expand All @@ -11,11 +11,13 @@ import {NgbDropdownConfig} from './dropdown-config';
'[class.dropdown]': '!up',
'[class.dropup]': 'up',
'[class.open]': 'isOpen()',
'(keyup.esc)': 'closeFromOutside()',
'(document:click)': 'closeFromOutside()'
'(keyup.esc)': 'closeFromOutsideEsc()',
'(document:click)': 'closeFromOutsideClick($event)'
}
})
export class NgbDropdown {
private _toggleElement: any;

/**
* Indicates that the dropdown should open upwards
*/
Expand Down Expand Up @@ -82,28 +84,47 @@ export class NgbDropdown {
/**
* @internal
*/
closeFromOutside() {
closeFromOutsideClick($event) {
if (this.autoClose && !this._isEventFromToggle($event)) {
this.close();
}
}

/**
* @internal
*/
closeFromOutsideEsc() {
if (this.autoClose) {
this.close();
}
}

/**
* @internal
*/
set toggleElement(toggleElement: any) { this._toggleElement = toggleElement; }

private _isEventFromToggle($event) { return $event.target === this._toggleElement; }
}

/**
* Allows the dropdown to be toggled via click. This directive is optional.
*/
@Directive({
selector: '[ngbDropdownToggle]',
host: {'class': 'dropdown-toggle', 'aria-haspopup': 'true', '[attr.aria-expanded]': '_dropdown.isOpen()'}
host: {
'class': 'dropdown-toggle',
'aria-haspopup': 'true',
'[attr.aria-expanded]': 'dropdown.isOpen()',
'(click)': 'toggleOpen()'
}
})
export class NgbDropdownToggle {
constructor(private _dropdown: NgbDropdown) {}

@HostListener('click', ['$event'])
toggleOpen($event) {
$event.stopPropagation();
this._dropdown.toggle();
constructor(public dropdown: NgbDropdown, elementRef: ElementRef) {
dropdown.toggleElement = elementRef.nativeElement;
}

toggleOpen() { this.dropdown.toggle(); }
}

export const NGB_DROPDOWN_DIRECTIVES = [NgbDropdownToggle, NgbDropdown];

0 comments on commit e2e7c1b

Please sign in to comment.