-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(dropdown): close on escape from anywhere #2051
Conversation
Not sure listening for ESC on |
8bc49e6
to
e8f8ea1
Compare
I don't know any other way to catch events from any element without listening to the The requirement is to close the dropdown on any Escape press. What you are saying is that in addition to listening to the event and closing the dropdown, we should also prevent catching this event for let's say a modal to avoid closing it at the same time? If so, that's a valid requirement, and we have to think about a generic solution working well for all widgets with an individual instance, but also for nested instances (dropdown inside modal, etc.). |
2beb316
to
6ac78f2
Compare
b017512
to
6ac78f2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey,
I was recently thinking about same thing for the datepicker.
- What would you think about the alternative approach with observables. It's shorter and doesn't use private variables
-
I'm not sure there is much added value in setting handler outside of angular
-
Please remove
keys.ts
from this PR. For now I would add theenum Keys
as everywhere else and refactor separately afterwards
WDYT?
src/dropdown/dropdown.ts
Outdated
this._escapeListener = (event) => { | ||
if (isEscape(event)) { | ||
this.closeFromOutsideEsc(); | ||
this.changeDetector.detectChanges(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, why would you need to run the CD after closing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Honestly I can't remember why, probably it wasn't working properly otherwise, to be tested again.
src/dropdown/dropdown.ts
Outdated
@@ -120,7 +121,7 @@ export class NgbDropdown implements OnInit { | |||
*/ | |||
@Output() openChange = new EventEmitter(); | |||
|
|||
constructor(config: NgbDropdownConfig, ngZone: NgZone) { | |||
constructor(config: NgbDropdownConfig, private ngZone: NgZone, private changeDetector: ChangeDetectorRef) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be _ngZone
and _changeDetector
https://github.com/ng-bootstrap/ng-bootstrap/wiki/Contributions%3A-Code-conventions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Damn, I thought I had the guidelines in mind, I'll read it again, more carefully. And I agree with that part.
I can remove the Regarding the event handler registered outside Angular: if we don't don't it, isn't the change detection triggered after every Now, about the Observable implementation, I'm just in love with it. Truly. That's totally how I want to write this kind of code. |
a34c0a6
to
ec1bc31
Compare
src/dropdown/dropdown.ts
Outdated
export class NgbDropdown implements OnInit { | ||
export class NgbDropdown implements OnInit, | ||
OnDestroy { | ||
private _closed$ = new Subject(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, why create a new one, if you already have openChange
?
takeUntil(this.openChange.pipe(filter(opened => opened === false)))
?
ec1bc31
to
61fb761
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, just left a couple more comments!
src/dropdown/dropdown.ts
Outdated
import {NgbDropdownConfig} from './dropdown-config'; | ||
import {positionElements, PlacementArray, Placement} from '../util/positioning'; | ||
|
||
enum Key { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind rebasing to use common Keys, please?
src/dropdown/dropdown.ts
Outdated
} from '@angular/core'; | ||
import {DOCUMENT} from '@angular/common'; | ||
import {Subject, fromEvent} from 'rxjs'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Subject is not used anywhere
}) | ||
export class NgbDropdown implements OnInit { | ||
export class NgbDropdown implements OnInit, | ||
OnDestroy { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding it 👍
src/dropdown/dropdown.spec.ts
Outdated
const compiled = fixture.nativeElement; | ||
const buttonEl = compiled.querySelector('button'); | ||
describe('escape closing', () => { | ||
const testEscapeClosing = ({autoClose, getElementForEventDispatch}) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I would really much prefer reading 4 times duplicated code for many reasons:
- you have all you need in a single
it()
function, don't have to jump back and forth trying to understand what is passed where - don't have to think when reading the tests (ex. conditions, remembering what were the arguments passed, reading
expectation.not.toBeShown()
vsexpect(compiled).not.toBeShown()
, etc.) - all other tests (at least for this component) are written in this style
P.S. Would have nothing against this, if it was in the component code, not the test
@pkozlowski-opensource, should we change or leave like this?
61fb761
to
27b5d12
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
close #1741