Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Material: BreakpointObserver not available from load?

While using the Angular BreakpointObserver in conjunction with Angular Material, I try to use Material Design-spec breakpoints (they're defined in Breakpoints, for example Breakpoints.LandscapePortrait, Breakpoints.HandsetPortrait).

The breakpointObserver works, except for when I freshly load the page. The breakpointObserver is only triggered after a change is observed, but considering it's a fresh load, there is no change yet. This means the initial viewport is not yet evaluated against the breakpoints. I've tried using a single BreakpointObserver.isMatched in OnInit, but this does not seem to take any effect.

I included BreakpointObserver, Breakpoints and MediaMatcher into a shared service, to which I subscribe in all the components that need to "listen" to the breakpoints.

My question is: how can I make sure that the breakpoints are evaluated before the first viewport-change (which may not happen at all, if the user does not resize the window/change device orientation)?

Here's the code of my shared.service.ts:

import {Component, OnDestroy, OnInit, Injectable,Input,Output,EventEmitter} from '@angular/core';
import {BreakpointObserver, Breakpoints, MediaMatcher} from '@angular/cdk/layout';

@Injectable()
export class SharedService implements OnDestroy, OnInit {
    public isCollapsed = false;
    public isOpen = false;
    public isMobileView = false;
    public isTabletView = false;
    private breakpointObserver: BreakpointObserver;
    @Output() mediaChange = new EventEmitter();
    constructor(breakpointObserver: BreakpointObserver) {
        this.breakpointObserver = breakpointObserver;
        // check if the viewport matches Material Design-spec handset displays
        this.breakpointObserver.observe([
          Breakpoints.HandsetPortrait
        ]).subscribe(result => {
          if (result.matches) {
            this.isMobileView = true;
            this.isTabletView = false;
            this.isOpen = false;
            this.isCollapsed = false;
          }
          else {
            this.isMobileView = false;
            this.isOpen = true;
            this.isCollapsed = false;
          }
          this.mediaChanged();
        });
        // check if the viewport matches Material Design-spec tablet displays
        this.breakpointObserver.observe([
          Breakpoints.TabletPortrait
        ]).subscribe(result => {
          if (result.matches) {
            this.isTabletView = true;
            this.isMobileView = false;
            this.isOpen = true;
            this.isCollapsed = true;
          }
          else {
            if(!this.isMobileView){
                this.isOpen = true;
            }
            this.isTabletView = false;
            this.isCollapsed = false;
          }
          this.mediaChanged();
        });
    }
    mediaChanged() {
        this.mediaChange.emit({
          "isMobileView" : this.isMobileView,
          "isTabletView" : this.isTabletView,
          "isCollapsed" : this.isCollapsed,
          "isOpen" : this.isOpen
      });
    }
    ngOnInit() {
        // MY ATTEMPT
        // Running the same checks as the observer, but this time on init(?)
        // does not seem to take any effect
        if(this.breakpointObserver.isMatched([
          Breakpoints.HandsetPortrait
        ])){
            this.isMobileView = true;
            this.isTabletView = false;
            this.isOpen = false;
            this.isCollapsed = false;
        }
        if(this.breakpointObserver.isMatched([
          Breakpoints.TabletPortrait
        ])){
            this.isTabletView = true;
            this.isMobileView = false;
            this.isOpen = true;
            this.isCollapsed = true;
        }
        this.mediaChanged();
    }
}
like image 531
Jeroen Avatar asked Apr 19 '18 12:04

Jeroen


People also ask

How to set up a breakpointobserver in Angular 2?

The first step is to install the CDK to your project: Next, import the LayoutModule from @angular/cdk/layout to your module. For example, like this in the app.module.ts file: After importing the LayoutModule, inject the BreakpointObserver into your component like any other service you would use: Alright, now everything is set up and ready to use.

How does the breakpointobserver work?

The breakpointObserver works, except for when I freshly load the page. The breakpointObserver is only triggered after a change is observed, but considering it's a fresh load, there is no change yet. This means the initial viewport is not yet evaluated against the breakpoints.

How do I use the material design breakpoints?

They are based on Google's Material Design specification, and the values are: You can use them by importing Breakpoints from the CDK's layout folder: You can then use a breakpoint, like Breakpoint.Handset, in the observe or isMatched functions.

Why doesn't the breakpointobserver work with oninit?

The breakpointObserver is only triggered after a change is observed, but considering it's a fresh load, there is no change yet. This means the initial viewport is not yet evaluated against the breakpoints. I've tried using a single BreakpointObserver.isMatched in OnInit, but this does not seem to take any effect.


1 Answers

set a local variable to false and change it depending on the value in the subscription.

import { Component, OnInit } from '@angular/core';
import { BreakpointObserver, Breakpoints, BreakpointState } from '@angular/cdk/layout';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-main-menu',
  templateUrl: './main-menu.component.html',
  styleUrls: ['./main-menu.component.css']
})
export class MainMenuComponent implements OnInit {
  isHandset = false;

  constructor(private breakpointObserver: BreakpointObserver, private route: ActivatedRoute) {}

  ngOnInit() {
    this.breakpointObserver.observe(Breakpoints.Handset)
      .subscribe((state: BreakpointState) => {
        if (state.matches) {
          this.isHandset = true;
        } else {
          this.isHandset = false;
        }
      });
  }

}

Template code:

<mat-sidenav-container class="sidenav-container">
  <mat-sidenav #drawer class="sidenav" fixedInViewport
      [attr.role]="isHandset ? 'dialog' : 'navigation'"
      [mode]="isHandset ? 'over' : 'side'"
      [opened]="isHandset === false">
    <mat-toolbar>Menu</mat-toolbar>
    <mat-nav-list>
      <a mat-list-item href="#">Link 1</a>
      <a mat-list-item href="#">Link 2</a>
      <a mat-list-item href="#">Link 3</a>
    </mat-nav-list>
  </mat-sidenav>
  <mat-sidenav-content>
    <mat-toolbar color="primary">
      <button
        type="button"
        aria-label="Toggle sidenav"
        mat-icon-button
        (click)="drawer.toggle()"
        *ngIf="isHandset">
        <mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
      </button>
      <span>timplaw-dotcom</span>
    </mat-toolbar>
    <!-- Add Content Here -->
    <router-outlet></router-outlet>
  </mat-sidenav-content>
</mat-sidenav-container>

Reference: https://alligator.io/angular/breakpoints-angular-cdk/

like image 150
Where's-the-pi Avatar answered Oct 12 '22 09:10

Where's-the-pi