Skip to content
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

Closed

Conversation

ymeine
Copy link
Contributor

@ymeine ymeine commented Dec 19, 2017

close #1741

@devoto13
Copy link
Contributor

Not sure listening for ESC on document is the right choice. Consider for example a dropdown inside a modal. What I would expect as a user is that first ESC click closes dropdown and second ESC click closes modal.

@ymeine
Copy link
Contributor Author

ymeine commented Jan 25, 2018

I don't know any other way to catch events from any element without listening to the document object.

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.).

@ymeine ymeine force-pushed the pr/feat/accessibility/1741 branch 2 times, most recently from 2beb316 to 6ac78f2 Compare January 29, 2018 09:56
@ymeine ymeine force-pushed the pr/feat/accessibility/1741 branch 2 times, most recently from b017512 to 6ac78f2 Compare March 29, 2018 13:43
Copy link
Member

@maxokorokov maxokorokov left a 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.

  1. What would you think about the alternative approach with observables. It's shorter and doesn't use private variables

https://github.com/ng-bootstrap/ng-bootstrap/pull/2432/files#diff-5cfc08b6431988bde23a7633f56270cdR281

  1. I'm not sure there is much added value in setting handler outside of angular

  2. Please remove keys.ts from this PR. For now I would add the enum Keys as everywhere else and refactor separately afterwards

WDYT?

this._escapeListener = (event) => {
if (isEscape(event)) {
this.closeFromOutsideEsc();
this.changeDetector.detectChanges();
Copy link
Member

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?

Copy link
Contributor Author

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.

@@ -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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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.

@maxokorokov maxokorokov added this to the 2.1.1 milestone Jun 12, 2018
@ymeine
Copy link
Contributor Author

ymeine commented Jun 12, 2018

I can remove the keys.ts utility, it's subject to discussion and would slow down the acceptation of other features.

Regarding the event handler registered outside Angular: if we don't don't it, isn't the change detection triggered after every keyup then?

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.

@pkozlowski-opensource pkozlowski-opensource modified the milestones: 2.1.1, 2.2.0 Jun 13, 2018
@ymeine ymeine force-pushed the pr/feat/accessibility/1741 branch 2 times, most recently from a34c0a6 to ec1bc31 Compare June 15, 2018 09:40
export class NgbDropdown implements OnInit {
export class NgbDropdown implements OnInit,
OnDestroy {
private _closed$ = new Subject();
Copy link
Member

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))) ?

Copy link
Member

@maxokorokov maxokorokov left a 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!

import {NgbDropdownConfig} from './dropdown-config';
import {positionElements, PlacementArray, Placement} from '../util/positioning';

enum Key {
Copy link
Member

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?

} from '@angular/core';
import {DOCUMENT} from '@angular/common';
import {Subject, fromEvent} from 'rxjs';
Copy link
Member

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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding it 👍

const compiled = fixture.nativeElement;
const buttonEl = compiled.querySelector('button');
describe('escape closing', () => {
const testEscapeClosing = ({autoClose, getElementForEventDispatch}) => {
Copy link
Member

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() vs expect(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?

@ymeine ymeine force-pushed the pr/feat/accessibility/1741 branch from 61fb761 to 27b5d12 Compare June 29, 2018 13:52
@pkozlowski-opensource pkozlowski-opensource removed this from the 2.2.0 milestone Jun 29, 2018
Copy link
Member

@maxokorokov maxokorokov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

dropdown: properly close on outside ESC
4 participants