Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

MediaObserver.isActive not working before subscribe MediaObserver.media$ #1025

Closed
keatkeat87 opened this issue Feb 24, 2019 · 7 comments · Fixed by #1244
Closed

MediaObserver.isActive not working before subscribe MediaObserver.media$ #1025

keatkeat87 opened this issue Feb 24, 2019 · 7 comments · Fixed by #1244
Assignees
Labels
bug P4 Low-priority issue that needs to be resolved
Milestone

Comments

@keatkeat87
Copy link

Bug Report

ngOnInit() {
  let active = this.mediaObserver.isActive('xs');
  console.log(active); // always false

  this.mediaObserver.media$.subscribe((v) => {
    if (v.mqAlias === 'xs') {
      active = this.mediaObserver.isActive('xs');
      console.log(active);  // true
    }
  });
}

What is the expected behavior?

this.mediaObserver.isActive('xs') should get true

What is the current behavior?

this.mediaObserver.isActive('xs') always return false

What are the steps to reproduce?

F12 see the console
https://stackblitz.com/github/keatkeat87/angular-flex-is-active-issue
https://github.com/keatkeat87/angular-flex-is-active-issue

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

this is a bug.

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

angular 7.x,
flex-layout 7.0.0-beta.23

Is there anything else we should know?

i think this is because of the rxjs behavior.
if no subscribe,
observe pipe won't run -> registerQuery no call -> _registry no set -> isActive always return false

isActive(mediaQuery: string): boolean {
  const mql = this._registry.get(mediaQuery);  // _registry must be set before calling isActive
  return !!mql ? mql.matches : false;
}

workaround :
const isActive = await this.mediaObserver.media$.pipe(take(1), map(media => media.mqAlias === 'xs')).toPromise();

@CaerusKaru CaerusKaru added bug P4 Low-priority issue that needs to be resolved labels Mar 2, 2019
@CaerusKaru
Copy link
Member

I'm going to leave this up to @ThomasBurleson to investigate and drive towards a resolution.

@CaerusKaru CaerusKaru added this to the Backlog milestone Mar 17, 2019
@JayEnaR
Copy link

JayEnaR commented Jul 17, 2019

I have the same issue. In core.js, the registry has no entries to compare with my query, thus always returning false.

image

"@angular/core": "~8.1.1",
"@angular/flex-layout": "^8.0.0-beta.26",
"@angular/cdk": "^8.1.1",
"typescript": "~3.4.3"

@gedclack
Copy link

gedclack commented Nov 14, 2019

Hi, is this bug solved yet ?
I stumbled upon this when I want to use isActive() in angular material sidenav template to make it responsive

@intellix
Copy link

intellix commented Nov 28, 2019

This one is killing us. media.asObservable() is async so we get issues with mat-sidenav animating open -> closed when on mobile because first the observable is NULL and then it's TRUE.

One way to mitigate this was to add startsWith(media.isActive('lt-sm')) and surprisingly it emits the wrong value :/

BreakpointObserver is sync but doesn't have an SSR shim so the page will initially deliver the menu open when on mobile.

I believe the problem is caused by:

* Use deferred registration process to register breakpoints only on subscription
* This logic also enforces logic to register all mediaQueries BEFORE notify
* subscribers of notifications.

The workaround I'm using is registering the mqList straight away above the observable. This patch-package will correct the initial isActive so you can do:

this.isHandset$ = media.asObservable().pipe(
  map(() => media.isActive('lt-lg')),
  startWith(media.isActive('lt-lg')),
);

patch-package:

diff --git a/node_modules/@angular/flex-layout/bundles/flex-layout-core.umd.js b/node_modules/@angular/flex-layout/bundles/flex-layout-core.umd.js
index 24a0aa2..6306bef 100644
--- a/node_modules/@angular/flex-layout/bundles/flex-layout-core.umd.js
+++ b/node_modules/@angular/flex-layout/bundles/flex-layout-core.umd.js
@@ -1318,6 +1318,7 @@ var MatchMedia = /** @class */ (function () {
         var _this = this;
         if (filterOthers === void 0) { filterOthers = false; }
         if (mqList && mqList.length) {
+            _this.registerQuery(mqList);
             /** @type {?} */
             var matchMedia$ = this._observable$.pipe(operators.filter((/**
              * @param {?} change
diff --git a/node_modules/@angular/flex-layout/bundles/flex-layout.umd.js b/node_modules/@angular/flex-layout/bundles/flex-layout.umd.js
index bef13bd..28798c6 100644
--- a/node_modules/@angular/flex-layout/bundles/flex-layout.umd.js
+++ b/node_modules/@angular/flex-layout/bundles/flex-layout.umd.js
@@ -1318,6 +1318,7 @@ var MatchMedia = /** @class */ (function () {
         var _this = this;
         if (filterOthers === void 0) { filterOthers = false; }
         if (mqList && mqList.length) {
+            _this.registerQuery(mqList);
             /** @type {?} */
             var matchMedia$ = this._observable$.pipe(operators.filter((/**
              * @param {?} change
diff --git a/node_modules/@angular/flex-layout/esm2015/core.js b/node_modules/@angular/flex-layout/esm2015/core.js
index a1ee8b1..2647cc3 100644
--- a/node_modules/@angular/flex-layout/esm2015/core.js
+++ b/node_modules/@angular/flex-layout/esm2015/core.js
@@ -1059,6 +1059,7 @@ class MatchMedia {
      */
     observe(mqList, filterOthers = false) {
         if (mqList && mqList.length) {
+            this.registerQuery(mqList);
             /** @type {?} */
             const matchMedia$ = this._observable$.pipe(filter((/**
              * @param {?} change
diff --git a/node_modules/@angular/flex-layout/esm5/core.es5.js b/node_modules/@angular/flex-layout/esm5/core.es5.js
index b26329e..9633cc1 100644
--- a/node_modules/@angular/flex-layout/esm5/core.es5.js
+++ b/node_modules/@angular/flex-layout/esm5/core.es5.js
@@ -1278,6 +1278,7 @@ var MatchMedia = /** @class */ (function () {
         var _this = this;
         if (filterOthers === void 0) { filterOthers = false; }
         if (mqList && mqList.length) {
+            _this.registerQuery(mqList);
             /** @type {?} */
             var matchMedia$ = this._observable$.pipe(filter((/**
              * @param {?} change

It seems the problem is that the mqList is only loaded lazily and the observe that registers them is async using debounceTime(0).

@intellix
Copy link

intellix commented Feb 7, 2020

New patch. I can do a PR for something like this if wanted but not sure if it's the solution you're after @ThomasBurleson

@angular+flex-layout+9.0.0-beta.29.patch

diff --git a/node_modules/@angular/flex-layout/bundles/flex-layout-core.umd.js b/node_modules/@angular/flex-layout/bundles/flex-layout-core.umd.js
index fbce2f8..516495d 100644
--- a/node_modules/@angular/flex-layout/bundles/flex-layout-core.umd.js
+++ b/node_modules/@angular/flex-layout/bundles/flex-layout-core.umd.js
@@ -1349,6 +1349,8 @@ var MatchMedia = /** @class */ (function () {
         var _this = this;
         if (filterOthers === void 0) { filterOthers = false; }
         if (mqList && mqList.length) {
+            _this.registerQuery(mqList);
+
             /** @type {?} */
             var matchMedia$ = this._observable$.pipe(operators.filter((/**
              * @param {?} change
diff --git a/node_modules/@angular/flex-layout/bundles/flex-layout.umd.js b/node_modules/@angular/flex-layout/bundles/flex-layout.umd.js
index 939f0a3..9efdb98 100644
--- a/node_modules/@angular/flex-layout/bundles/flex-layout.umd.js
+++ b/node_modules/@angular/flex-layout/bundles/flex-layout.umd.js
@@ -1349,6 +1349,7 @@ var MatchMedia = /** @class */ (function () {
         var _this = this;
         if (filterOthers === void 0) { filterOthers = false; }
         if (mqList && mqList.length) {
+            _this.registerQuery(mqList);
             /** @type {?} */
             var matchMedia$ = this._observable$.pipe(operators.filter((/**
              * @param {?} change
diff --git a/node_modules/@angular/flex-layout/esm2015/core.js b/node_modules/@angular/flex-layout/esm2015/core.js
index 8981efd..c3ccf25 100644
--- a/node_modules/@angular/flex-layout/esm2015/core.js
+++ b/node_modules/@angular/flex-layout/esm2015/core.js
@@ -1082,6 +1082,7 @@ class MatchMedia {
      */
     observe(mqList, filterOthers = false) {
         if (mqList && mqList.length) {
+            _this.registerQuery(mqList);
             /** @type {?} */
             const matchMedia$ = this._observable$.pipe(filter((/**
              * @param {?} change
diff --git a/node_modules/@angular/flex-layout/esm5/core.es5.js b/node_modules/@angular/flex-layout/esm5/core.es5.js
index 97db726..c794689 100644
--- a/node_modules/@angular/flex-layout/esm5/core.es5.js
+++ b/node_modules/@angular/flex-layout/esm5/core.es5.js
@@ -1301,6 +1301,7 @@ var MatchMedia = /** @class */ (function () {
         var _this = this;
         if (filterOthers === void 0) { filterOthers = false; }
         if (mqList && mqList.length) {
+            _this.registerQuery(mqList);
             /** @type {?} */
             var matchMedia$ = this._observable$.pipe(filter((/**
              * @param {?} change

@danmana
Copy link
Contributor

danmana commented Mar 12, 2020

Alternatively, you can use an app initializer in app.module.ts to make sure the first media event is processed before your app loads.
This way the isActive check will work directly in your component's constructor

providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: (media: MediaObserver) => {
        return () => {
          return media.asObservable()
            .pipe(first())
            .toPromise();
        };
      },
      multi: true,
      deps: [MediaObserver]
    }

  ]

CaerusKaru added a commit that referenced this issue May 8, 2020
Previously, only triggering `MatchMedia.observe` would correctly
register media queries for later usage in the `MediaObserver`.
This is incorrect, and queries should be registered if a) they
are valid breakpoints in Angular Layout, and b) they are not
currently registered.

Fixes #1025
@CaerusKaru CaerusKaru modified the milestones: Backlog, 9.0.0-beta.30 May 10, 2020
@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 Jun 10, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug P4 Low-priority issue that needs to be resolved
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants