flex-layout icon indicating copy to clipboard operation
flex-layout copied to clipboard

[Chrome] MediaObserver asObservable() emit wrong events on breakpoints

Open eprevot opened this issue 5 years ago • 9 comments

Bug Report

What is the expected behavior?

When I resize the screen from 959px to 960px, MediaObserver.asObservable() should emit a MediaChange event with mqAlias="md"

What is the current behavior?

When I resize the screen from 959px to 960px, MediaObserver.asObservable() emits (among others) 2 MediaChange events with mqAlias="md" and mqAlias="sm"

What are the steps to reproduce?

A component with

public ngOnInit() {
    this.watcher = this.mediaObserver.asObservable()
      .subscribe((changes: MediaChange[]) => {
        console.log(changes)
      })
}

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

When I resize slowly, MediaObserver.media$ does not always emit an event when breakpoints are crossed. I think it may be related.

Is there anything else we should know?

It may be related to the recent changes about the breakpoints (i.e. max-width: 959.99 instead of 959) fxLayout version: 7.0.0-beta.24

eprevot avatar May 09 '19 09:05 eprevot

Same here.

This is my code

mediaObserver.asObservable().subscribe(changes => {
  console.log(changes.map(c => c.mqAlias));
});

In Chrome, when I resize fast (from lg to md and back), I get the following outputs

(5) ["lg", "lt-xl", "gt-md", "gt-sm", "gt-xs"] # after page load
(5) ["md", "lt-lg", "lt-xl", "gt-sm", "gt-xs"] # after making window smaller
(5) ["md", "lt-lg", "lt-xl", "gt-sm", "gt-xs"] # same event at the same time
(5) ["lg", "lt-xl", "gt-md", "gt-sm", "gt-xs"] # after making window larger
(5) ["lg", "lt-xl", "gt-md", "gt-sm", "gt-xs"] # same event at the same time

This is expected (except that all events are emitted twice).

When resizing slowly, I get the following outputs

(5) ["lg", "lt-xl", "gt-md", "gt-sm", "gt-xs"] # after page load
(7) ["md", "lt-lg", "lg", "lt-xl", "gt-md", "gt-sm", "gt-xs"] # after making window smaller
(7) ["md", "lt-lg", "lg", "lt-xl", "gt-md", "gt-sm", "gt-xs"] # same event at the same time
(7) ["md", "lt-lg", "lg", "lt-xl", "gt-md", "gt-sm", "gt-xs"] # after making window larger
(7) ["md", "lt-lg", "lg", "lt-xl", "gt-md", "gt-sm", "gt-xs"] # same event at the same time

As you can see, both "md" and "lg" are reported.

In Firefox, things get even weirder:

Array(5) [ "lg", "lt-xl", "gt-md", "gt-sm", "gt-xs" ] # after page load
Array(4) [ "lt-lg", "lt-xl", "gt-sm", "gt-xs" ] # after making window smaller
Array(5) [ "md", "lt-lg", "lt-xl", "gt-sm", "gt-xs" ] # second yet different event at the same time
Array(6) [ "md", "lt-lg", "lt-xl", "gt-md", "gt-sm", "gt-xs" ] # after making window larger
Array(7) [ "md", "lt-lg", "lg", "lt-xl", "gt-md", "gt-sm", "gt-xs" ] # second yet different event at the same time

First, when making the window smaller, no 'single' mqAlias is reported, but only ranges. In contrast to the initial result, the "lg" and "gt-md" aliases are removed, but only the "lt-lg" alias is added. I would expect that also the "md" alias is added.

Then right after the first event, a second event gets fired with the correct "md" alias added.

When making the window larger, the "gt-md" alias is added, but not the "lg" alias. The "md" alias is not removed. I would expect that "md" would also be removed and "lg" would be added.

Then right after the first event, a second event gets fired with the "lg" alias added, but the "md" alias is still not removed.

PapaNappa avatar Jun 05 '19 07:06 PapaNappa

I can perhaps see why you would potentially get two aliases (md and lg) in a single report after reading the comments made in the related commit/issue where this change was implemented (not that I agree with this breaking change at all, but that's a different thought process unrelated to this issue here).

However, that said, what you are reporting for this bug does seem like it contradicts the note in the comments that this MediaChange[] emission would be sorted in priority of the aliases; if the intent is for the return packet to include all aliases involved in the change, a shrinking of the window which crosses from lg over to md would make sense to lead off with ["lg", "lt-xl", "gt-md", "gt-sm", "gt-xs", ...] before then listing ["md", "lt-lg", "lt-xl", ...]. At least in that instance, if you parse the returned array and look for the first "non-comparative" alias you encounter (which would be "lg"), you would "know" in your code which sizing breakpoint the window is currently "in".

As it stands, though, it's wrong. In your Chrome example at the end, my logic would try to tell me the window is still in "md", even though it is in "lg" mode at that point. It is almost as though the act of slowly dragging the window locks the MediaChange[] result into the first alias it determines, and then it will doggedly report that until you release the drag operation.

Londovir avatar Jun 06 '19 12:06 Londovir

I am having a similar issue, I am just posting here to help a bit with videos and stackblitz of the problem:

On Firefox, when I am on XS screen size and change the width of my screen to be more than 600px, a MediaQuery with an alias of SM should be emitted. But what actually happens on Firefox is that I receive a XS MediaQuery.

This also happens when changing other screen sizes, for example, from SM to MD.

Check the stackblitz here: https://stackblitz.com/edit/angular-flex-layout-seed-a9w5hl

https://imgur.com/vEgsTAW


Also, there is another issue that happens in Chrome and Safari too:

If you resize slowly the screen, it is possible that both XS and SM MediaQuery will be activated. If you resize at normal speed, then it works as intended:

https://imgur.com/DzjVm8B

paulotokimatu avatar Jul 30 '19 00:07 paulotokimatu

As a workaround you might use the BreakpointObserver from Angular CDK.

nilsmehlhorn avatar Sep 30 '19 07:09 nilsmehlhorn

Since this hasn't been fixed yet, this can be circumvented with the distinctUntilChanged operator. It'll compare between previous and current breakpoint alias, and prevent the emission if identical:

this.mediaObserver.asObservable()
 .pipe(
   distinctUntilChanged((prev, curr) => prev[0].mqAlias === curr[0].mqAlias),
   map((arr: MediaChange[]) => arr.map((change: MediaChange) => change.mqAlias)),
 )

https://stackblitz.com/edit/flex-layout-mediaobserver-deduped

AsafAgranat avatar Jun 10 '20 22:06 AsafAgranat

It is quite honestly ridiculous how annoying this issue is. For those who have been suffering in silence, I feel for you on this. There is some sort of issue with how the media queries are getting fired. The underlying infrastructure is working flawlessly, especially since #1377 was merged. But the issue of events not firing when they should be is perplexing, because in theory everything is in place and should just work. I'll keep digging on this, and hopefully come back with better news.

CaerusKaru avatar Dec 23 '21 06:12 CaerusKaru

So this looks like a browser issue, and one that I'm not sure we'll be able to get patched at a higher level. In Chrome (haven't found the Firefox one yet), this is/was explained in this comment. Essentially, Chrome is suppressing quick changes in display, with a very wonky definition for "quick". This leaves Flex Layout applications and users in a lurch though, because we depend on these events reliably firing for every change, no matter how quick.

I'm currently researching/discussing with team members some possible mitigations for this, because there has to be something we can do in the meantime.

CaerusKaru avatar Dec 27 '21 00:12 CaerusKaru

At least on Mac, I've confirmed this isn't an issue with latest Firefox and Safari releases. Can anyone second/refute this? If so, it may be easier to get this patched in Chromium.

CaerusKaru avatar Dec 27 '21 00:12 CaerusKaru

I've filed a ticket with the Chromium team, and they've identified the root cause and assigned priority to the case, which hopefully means we can get this addressed in one of the next major versions.

Tracking: https://bugs.chromium.org/p/chromium/issues/detail?id=1285532 (please do not spam the ticket)

CaerusKaru avatar Jan 11 '22 22:01 CaerusKaru