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

fix(overlay): overlay directives not emitting when detached externally #7950

Merged

Conversation

crisbeto
Copy link
Member

@crisbeto crisbeto commented Oct 22, 2017

Currently the ConnectedOverlayDirective only emits the detach event when it thinks that the overlay is detached (escape press, backdrop click etc.), but this won't necessarily be correct (e.g. when it was closed by a scroll strategy). These changes refactor the outputs to always be one-to-one with the OverlayRef detachments.

Fixes #16779

@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Oct 22, 2017
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

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

LGTM, can add merge-ready when ready

@@ -256,7 +256,7 @@ export class ConnectedOverlayDirective implements OnDestroy, OnChanges {
}

ngOnChanges(changes: SimpleChanges) {
if (changes['open'] || changes['_deprecatedOpen']) {
if (changes.open || changes._deprecatedOpen) {
Copy link
Member

Choose a reason for hiding this comment

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

We should stick with the string access here; Closure Compiler may attempt to rename these otherwise

@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from 9198234 to b5672e7 Compare October 26, 2017 19:59
@crisbeto crisbeto added the action: merge The PR is ready for merge by the caretaker label Oct 26, 2017
@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from b5672e7 to af12c9c Compare November 4, 2017 22:38
@crisbeto crisbeto added the target: patch This PR is targeted for the next patch release label Dec 6, 2017
@andrewseguin andrewseguin added the presubmit failures This PR has failures in Google's internal presubmit process and cannot be immediately merged label Dec 13, 2017
@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from af12c9c to 4dac772 Compare January 28, 2018 19:06
@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from 4dac772 to 0f076fd Compare February 13, 2018 21:35
@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from 0f076fd to 353df7a Compare March 18, 2018 17:37
@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from 353df7a to 3a32a52 Compare May 19, 2018 14:13
@ngbot
Copy link

ngbot bot commented Jul 11, 2018

Hi @crisbeto! This PR has merge conflicts due to recent upstream merges.
Please help to unblock it by resolving these conflicts. Thanks!

1 similar comment
@ngbot
Copy link

ngbot bot commented Jul 11, 2018

Hi @crisbeto! This PR has merge conflicts due to recent upstream merges.
Please help to unblock it by resolving these conflicts. Thanks!

@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from 3a32a52 to bcda183 Compare July 15, 2018 09:14
@josephperrott josephperrott removed the presubmit failures This PR has failures in Google's internal presubmit process and cannot be immediately merged label Jul 18, 2018
@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from bcda183 to 35d2f12 Compare September 30, 2018 19:08
@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from 35d2f12 to 7b4adab Compare November 11, 2018 21:28
@mmalerba mmalerba added aaa and removed aaa labels Apr 25, 2019
@skoropadas
Copy link

any news?

@jelbourn jelbourn added the P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent label Jun 20, 2019
@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from 7b4adab to 698ccb9 Compare August 18, 2019 04:15
@crisbeto crisbeto removed the P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent label Aug 18, 2019
@crisbeto crisbeto added the P2 The issue is important to a large percentage of users, with a workaround label Aug 18, 2019
@crisbeto
Copy link
Member Author

Rebased and bumping to a P2, because we're getting new reports about this.

@DMezhenskyi
Copy link
Contributor

are there any plans to merge this branch?

@andrewseguin
Copy link
Contributor

After a full day's deep dive into the test failures, I think I figured out how we can get this merged in.

When the OverlayRef is being destroyed, it emits a detachment which now causes the OverlayContainer to emit on detach.

Can you add a check so that it will not emit a detach from the OverlayRef's destroy?

@crisbeto
Copy link
Member Author

crisbeto commented Jun 17, 2020

@andrewseguin emitting the detached event on destruction is by design. It happens since we're detaching an overlay first, before we destroy it, and it's been this way for a long time so I suspect that we might break somebody if we did it at the OverlayRef level. We could have an exception in CdkConnectedOverlay specifically, but that feels like it would be inconsistent. How many apps is the current behavior breaking and is it some kind of runtime error or does the app's logic break down?

@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from 3f025c6 to f6ee9da Compare June 17, 2020 06:04
@andrewseguin
Copy link
Contributor

andrewseguin commented Jun 18, 2020

The issue boils down to really one component that essentially wraps our overlay directive, so if we can make it work there then I think we're good.

What's happening is that this component's view contains an <ng-template cdkConnectedOverlay>. They subscribe to the (detach) output and then emit an event that their overlay's open state has changed. Listeners to that event are then using that as a hint that they should (for whatever reason) call detectChanges().

It's there that we seem to have an issue, because that detectChanges() fails for reasons that I haven't been able to totally nail down. It seems to me that the reason is because the view contains some components that are being destroyed or have been destroyed.

Does it make sense that calling detectChanges() during an onDestroy would be dangerous? Or perhaps I'm on the wrong track and Angular handles this gracefully

Oh and something really important - it seems this is fine for client code. I'm seeing this fail during test code, and it seems that it's specifically only failing during the teardown and only when the overlay is left open. Therefore I suspect what we're seeing is that the teardown tries to start destroying everything, but the detach causes a call to detectChanges()

@crisbeto
Copy link
Member Author

crisbeto commented Jun 18, 2020

I believe that the framework will throw an error if you try to call detectChanges on a destroyed ChangeDetectorRef, although assuming that the view is destroyed, the detach listener should've been removed from the view as well. We've dealt with something similar in the autocomplete trigger so maybe the same approach can be applied to their project? It boils down to setting a flag in ngOnDestroy and using it to guard all of the detectChanges calls. Here's the relevant code: https://github.com/angular/components/blob/master/src/material/autocomplete/autocomplete-trigger.ts#L291

@andrewseguin
Copy link
Contributor

That was my initial thinking too, but adding that across the affected components didn't fix anything. For some reason the teardown is destroying in a strange order, probably due to these cases having a weird view tree with all the amount of content projection and view insertions.

Since you are sure this logic is sound and what we want, I'll focus on making changes to these tests. While there are a dozen different failing targets, they all use the same wrapper for our overlay, so I suspect I can make adjustments in that wrapper to fix this.

@andrewseguin
Copy link
Contributor

@crisbeto Please check out crisbeto#10

I managed to distill our internal tests into a single simple case that I can put into our repo. It's a little contrived, but it's because I'm trying to reduce it down as much as possible. This one test represents multiple components with tons of code.

Let me know what you think on moving forward to get this to pass.

Currently the `ConnectedOverlayDirective` only emits the `detach` event when it _thinks_ that the overlay is detached (escape press, backdrop click etc.), but this won't necessarily be correct (e.g. when it was closed by a scroll strategy). These changes refactor the outputs to always be one-to-one with the `OverlayRef` detachments.
@crisbeto crisbeto force-pushed the overlay-directives-detach-events branch from f6ee9da to 99bd29a Compare June 20, 2020 09:04
@crisbeto
Copy link
Member Author

Wow that's one convoluted bug @andrewseguin! What seems to be happening is that the automatic change detection triggers another run when the output emits, even though the related component was destroyed. It looks like the only way forward is to stop emitting the event ourselves once we hit ngOnDestroy. I've updated the code so it shouldn't emit anymore and I've added a link to your repro so we don't regress in the future. Thank you for investigating it!

@andrewseguin andrewseguin merged commit 4a3c960 into angular:master Jul 14, 2020
andrewseguin pushed a commit that referenced this pull request Jul 14, 2020
#7950)

Currently the `ConnectedOverlayDirective` only emits the `detach` event when it _thinks_ that the overlay is detached (escape press, backdrop click etc.), but this won't necessarily be correct (e.g. when it was closed by a scroll strategy). These changes refactor the outputs to always be one-to-one with the `OverlayRef` detachments.
ngwattcos pushed a commit to ngwattcos/components that referenced this pull request Jul 20, 2020
angular#7950)

Currently the `ConnectedOverlayDirective` only emits the `detach` event when it _thinks_ that the overlay is detached (escape press, backdrop click etc.), but this won't necessarily be correct (e.g. when it was closed by a scroll strategy). These changes refactor the outputs to always be one-to-one with the `OverlayRef` detachments.
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Aug 14, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement P2 The issue is important to a large percentage of users, with a workaround target: patch This PR is targeted for the next patch release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CDK Overlay not calling the detach event while using CloseScrollStrategy
8 participants