Components: mat-menu hides immediately on opening

Created on 19 May 2018  路  10Comments  路  Source: angular/components

Bug, feature request, or proposal:

Bug

What is the expected behavior?

mat-menu should stay opened after clicking activating button

What is the current behavior?

menu opens and closes (hides) instantly, keeping overlay active.
User must click outside of area that should be covered with menu to deactivate overlay.
After that menu opens normally, as it should.

After inspection in chrome developer tools:

Menu is constructed but has styles:

opacity: 0;
transform: scale(0.01, 0.01);

After removing styles , menu shows.

Reverting to version 5.2.4 fixes problem

Problem exists at versions:

  • 6.0.2
  • 6.0.1
  • 6.0.0

Similar issue:
https://github.com/angular/material2/issues/10212
https://github.com/angular/material2/issues/11366

What are the steps to reproduce?

//component.html
<div *ngIf="someBoolean">
    <button mat-icon-button [matMenuTriggerFor]="appMenu">
           <mat-icon>more_vert</mat-icon>
    </button>
</div>
<mat-menu #appMenu="matMenu">
             <button mat-menu-item><mat-icon>visibility</mat-icon>Change visibility</button>
            <mat-divider></mat-divider>
            <button mat-menu-item><mat-icon>delete_forever</mat-icon>Delete</button>
</mat-menu>

//component.ts
ngOnInit() {

        this.someObservable.pipe(
            take(1),
        ).subscribe((s) => {
            this.someBoolean = true;
            this.change.detectChanges();
        });
}

When variable change and detectChanges() is wrapped inside ngZone, problem disappears.

Fix:

    this.someObservable.pipe(
            take(1),
        ).subscribe((s) => {
           this.zone.run(() => {
                this.someBoolean = true;
                this.change.detectChanges();
           });
        });

What is the use-case or motivation for changing an existing behavior?

To work as predicted

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

user agent:

Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36

ng -v output:

Angular CLI: 6.0.3
Node: 10.1.0
OS: linux x64
Angular: 6.0.2
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.5.13
@angular-devkit/build-angular     0.5.13
@angular-devkit/build-optimizer   0.5.13
@angular-devkit/core              0.5.13
@angular-devkit/schematics        0.6.3
@angular/cdk                      6.0.2
@angular/cli                      6.0.3
@angular/flex-layout              6.0.0-beta.15
@angular/material                 6.0.2
@ngtools/webpack                  6.0.0-rc.11
@schematics/angular               0.6.3
@schematics/update                0.6.3
rxjs                              6.1.0
typescript                        2.7.2
webpack                           4.6.0

Is there anything else we should know?

no

Most helpful comment

@kdcro101 Yes wrapping it inside ngZone.run makes it work for me without the need for the polyfill, I don't really understand the underlying issue here, but this made it work for me so I'm happy 馃憤

All 10 comments

Looking at the issue and the workaround, there's probably not much we can do about it on Material's side. If your observable is running outside the NgZone and isn't triggering change detection, there's no way for Material to know that anything changed. In this case it's up to you to bring it back into the NgZone.

@crisbeto

I guess you didn't read issue completely and closed it in haste.

Let me explain:

  • I DO call detectChanges on observable subscription (as you can see in issue explaination) - that is why I opened issue
  • element is shown on template - so variable change is detected
  • when menu is activated, it appears and disappears (stuck in animation state) leaving style:
opacity: 0;
transform: scale(0.01, 0.01);
  • wierd thing is that component detectChanges need to be called even inside ngZone.run block for menu not to hide.

This works:

   this.someObservable.pipe(
            take(1),
        ).subscribe((s) => {
           this.zone.run(() => {
                this.someBoolean = true;
                this.change.detectChanges();
           });
        });

This doesn't work:

   this.someObservable.pipe(
            take(1),
        ).subscribe((s) => {
           this.zone.run(() => {
                this.someBoolean = true;
           });
        });

This, also, doesn't work even it should

   this.someObservable.pipe(
            take(1),
        ).subscribe((s) => {
            this.someBoolean = true;
            this.change.detectChanges();
        });

QUESTION:

  • Why same code works in 5.2.4 and not in 6.0.* ?
  • If component change detection works, why it doesnt work in mat-menu component (component change detection is not detached)?
  • is there possibility of changeDetection/zone problem inside mat-menu?
  • why do i need to use change.detectChanges() inside ngZone.run block?

This issue is same as ::
https://github.com/angular/material2/issues/10212
https://github.com/angular/material2/issues/11366

@crisbeto,

Got it.
Problem is not in material. It is in zone.js->rxjs 6 support .

Adding import into polyfills.ts fixes problem.

import "zone.js/dist/zone-patch-rxjs";

@kdcro101 this does not fix the problem. Added that line to polyfills but I still see the same thing happen.

@bluecaret ,

I guess rxjs 6.* transition is work in progress. Does wrapping inside ngZone.run block helps?

@kdcro101 Yes wrapping it inside ngZone.run makes it work for me without the need for the polyfill, I don't really understand the underlying issue here, but this made it work for me so I'm happy 馃憤

Is there a github issue for zone.js->rxjs 6 support problem?

Btw, I was having this issue too and I don't think I was using observables in any relevant way here. Some seemingly unrelated lack of change detection logic elsewhere in the app appears to trigger the problem.

In my case I had an Angular Element with member variables being set outside of the Angular Zone. I had to change those member variables into getter/setter methods and call both ngZone.run for some menu deep inside the component tree to work. ( changeDetectorRef.detectChanges() did not suffice, and with ngZone.run it was no longer necessary in my case. )

I also have the questions as kdcro101 above, and especially why change detection doesn't work for the menu but it does work for displaying the button.

@crisbeto,

Got it.
Problem is not in material. It is in zone.js->rxjs 6 support .

Adding import into polyfills.ts fixes problem.

import "zone.js/dist/zone-patch-rxjs";

This helped me. Thank you!

I also have this exact bug for
rxjs 6.5.2

So far only found on Safari (only iOS). Another difference is that I need to click outside the menu twice and then it works.
import "zone.js/dist/zone-patch-rxjs"; did not work for me.

The solution I went with was to force the styling when ngZone was running outside of angular

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

michaelb-01 picture michaelb-01  路  3Comments

kara picture kara  路  3Comments

xtianus79 picture xtianus79  路  3Comments

LoganDupont picture LoganDupont  路  3Comments

crutchcorn picture crutchcorn  路  3Comments