Search code examples
angularrxjsangular-materialobserver-pattern

Observer funtion is not working in app-component when trying to call it from service.ts angular


I have created a responsive side menu and that's work fine in-app component but when I am trying to move the function to my service.ts file it is not working at all. The below code is for my app.component.ts

import { Component} from '@angular/core';
import { MyDataServiceService } from './my-data-service.service';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
})
export class AppComponent {
    title = 'azad-app';
    name = '';
    
    constructor(private user: MyDataServiceService) { }
    
    ngAfterViewInit() {
        this.user.menuDisplay();
    }
}

And this is my function code in service.ts

import { Injectable, ViewChild } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
import { BreakpointObserver } from '@angular/cdk/layout';

@Injectable({
    providedIn: 'root'
})
export class MyDataServiceService {

    @ViewChild(MatSidenav)
    sidenav!: MatSidenav;

    constructor(private observer: BreakpointObserver,) { }

    menuDisplay() {
        this.observer.observe(['(max-width:800px)']).subscribe((res) => {
            if (res.matches) {
                this.sidenav.mode = 'over';
                this.sidenav.close();
            } else {
                this.sidenav.mode = "side";
                this.sidenav.open();
            }
        });
    }
}

Solution

  • Instead of using a service, you should create a directive. Something like this:

    @Directive({selector: 'mat-sidenav[appMenu]'})
    export class AppMenu implements OnDestroy{
      private readonly subscription = this.observer.observe(['(max-width:800px)']).subscribe((res) => {
            if (res.matches) {
                this.sidenav.mode = 'over';
                this.sidenav.close();
            } else {
                this.sidenav.mode = "side";
                this.sidenav.open();
            }
        });
      constructor(private readonly sidenav: MatSidenav, private readonly observer: BreakpointObserver){ } 
    
      ngOnDestroy(){
        this.subscription.unsubscribe();
      }
    }
    

    Angular can inject the componenet to the directive, with this method you can encapsulate your sidenav logic to a separate class.