-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
fix(cdk-experimental/menu): fix bug preventing keyboard event handling if opened programmatically #20004
fix(cdk-experimental/menu): fix bug preventing keyboard event handling if opened programmatically #20004
Conversation
detectChanges(); | ||
|
||
fileMenuNativeItems[0].focus(); | ||
dispatchKeyboardEvent(document.activeElement!, 'keydown', TAB); |
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.
This could result in test flakes since browsers won't move focus in some cases on the CI (primarily if the window is out of focus). It might be better if you send the event directly to fileMenuNativeItems[0]
.
item | ||
.getMenuTrigger()! | ||
.closed.pipe(take(1), takeUntil(this._destroyed)) | ||
.subscribe(() => (this._openItem = undefined)); |
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.
Subscribing inside of a subscription is a bit of anti-pattern in rxjs since you can end up with multiple concurrent subscriptions. It might be better if you did this with a switchMap
and only subscribed once at the end.
src/cdk-experimental/menu/menu.ts
Outdated
item | ||
.getMenuTrigger()! | ||
.closed.pipe(take(1), takeUntil(this.closed)) | ||
.subscribe(() => (this._openItem = undefined)); |
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.
Same note here about subscribing inside a subscription.
e2b3c2c
to
7e6f75c
Compare
@@ -207,6 +212,33 @@ export class CdkMenuBar extends CdkMenuGroup implements Menu, AfterContentInit, | |||
return this.orientation === 'horizontal'; | |||
} | |||
|
|||
/** | |||
* Subscribe to the menu trigger's open events in order to track the trigger which opened the menu | |||
* and stop tracking it when the menu is closed closed. |
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.
typo: double 'closed'
.map(item => | ||
item | ||
.getMenuTrigger()! | ||
.opened.pipe(mapTo(item), takeUntil(merge(this._allItems.changes, this._destroyed))) |
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.
Here too, is it possible to unnest some of these nested operators? I've tended to have odd behavior with this sort of thing. (Should there be a persistent object-level observable merging this._allItems.changes and this._destroyed?)
this._allItems.changes | ||
.pipe( | ||
startWith(this._allItems), | ||
mergeMap((list: QueryList<CdkMenuItem>) => |
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.
Similar to above comment?
7e6f75c
to
adf11f3
Compare
@crisbeto @teflonwaffles feedback should be addressed. |
adf11f3
to
39d06ee
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
fixture.debugElement | ||
.queryAll(By.directive(CdkMenuItem))[0] | ||
.injector.get(CdkMenuItem) | ||
.getMenuTrigger()! | ||
.openMenu(); |
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.
nit: +4 indent for line overflow, so this would be e.g.
fixture.debugElement | |
.queryAll(By.directive(CdkMenuItem))[0] | |
.injector.get(CdkMenuItem) | |
.getMenuTrigger()! | |
.openMenu(); | |
fixture.debugElement | |
.queryAll(By.directive(CdkMenuItem))[0] | |
.injector.get(CdkMenuItem) | |
.getMenuTrigger()! | |
.openMenu(); |
* Subscribe to the menu trigger's open events in order to track the trigger which opened the menu | ||
* and stop tracking it when the menu is closed. | ||
*/ | ||
private _subscribeToMenuOpen() { |
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.
Not strictly necessary for this PR, but it would be good to cut down on the duplication between menu and menubar here. Maybe just add a TODO for now
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.
yeah, totally agree. Once everything is finalized I think pulling the duplicated logic out into an abstract Menu class is the way to go.
You can add the merge-ready label when ready |
…g if opened programmatically If a menu is opened programmatically, subsequent keyboard events to close it out are not handled. This fixes the issue by tracking the open sub-menu regardless of how it was opened up.
39d06ee
to
da11787
Compare
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
If a menu is opened programmatically, subsequent keyboard events to close it out are not handled.
This fixes the issue by tracking the open sub-menu regardless of how it was opened up.