Home > OS >  toggle sidenav from another component in angular
toggle sidenav from another component in angular

Time:05-08

I want to toggle a sidenav from another component in Angular. I have 3 child Components: menu,content,header. Button is on header component.I want to click on button then menu should toggle.

header.ts

export class HeaderComponent implements OnInit {
  constructor(public service: SharedService) {}

  ngOnInit() {}

  toggleMenu() {
    this.service.flag = !this.service.flag;
    this.service.flagChange.emit(this.service.flag);
  }
}

header.html

<div>
  <a href="">
    <i  ` (click)="toggleMenu()"></i>
  </a>
</div>

menu.ts

export class MenuComponent implements OnInit {
  constructor(public service: SharedService) {
    this.service.flagChange.subscribe((res) => this.service.flag);
  }

  ngOnInit() {}
}

menu.html

<div>
  <ul>
    <li>
      <a routerLink="/dashboard">Dashboard</a>
    </li>
    <li>
      <a routerLink="/user">User</a>
    </li>

    <li>
      <a routerLink="">Currency</a>
    </li>
    <li>
      <a routerLink="/report">Report</a>
      <ul>
        <li>
          <a routerLink="">Report1</a>
        </li>
        <li>
          <a routerLink="">Report2</a>
        </li>
        <li>
          <a routerLink="">Report3</a>
        </li>
      </ul>
    </li>
  </ul>
</div>

service.ts

@Injectable({
  providedIn: "root",
})
export class SharedService {
  public flag: boolean = false;
  public flagChange = new EventEmitter<boolean>();

  constructor() {}
}

CodePudding user response:

You aren't that fare, but you should use BehaviorSubject and not EventEmitter for that purpose
Emitter a meant for @Output()

here some little changes.
I also refactor a little bit your code ;)

header.ts

export class HeaderComponent {
  constructor(public sharedService: SharedService) {}
}

header.html

<div>
  <a href="">
    <i  (click)="sharedService.toggleMenu()"></i>
  </a>
</div>

menu.ts

export class MenuComponent implements OnInit, OnDestroy {
  protected _unsubscribe$: Subject<void> = new Subject();

  flag?: boolean

  constructor(private _sharedService: SharedService) {}

  ngOnInit() {
    this._sharedService.onFlagChange$
      .pipe(takeUntil(this._unsubscribe$))
      .subscribe((value) => {
        this.flag = value
      })
  }

  ngOnDestroy(): void {
    this._unsubscribe$.next();
    this._unsubscribe$.complete();
  }
}

menu.html

<div [class.hidden]="!flag"> <!-- or *ngIf, as you wish ;) -->
  <ul>
    <li>
      <a routerLink="/dashboard">Dashboard</a>
    </li>
    <li>
      <a routerLink="/user">User</a>
    </li>

    <li>
      <a routerLink="">Currency</a>
    </li>
    <li>
      <a routerLink="/report">Report</a>
      <ul>
        <li>
          <a routerLink="">Report1</a>
        </li>
        <li>
          <a routerLink="">Report2</a>
        </li>
        <li>
          <a routerLink="">Report3</a>
        </li>
      </ul>
    </li>
  </ul>
</div>

service.ts

@Injectable({
  providedIn: "root",
})
export class SharedService {
  public flag = false;
  onFlagChange$: BehaviorSubject<boolean> = new BehaviorSubject(this.flag);

  constructor() {}

  toggleMenu() {
    this.flag = !this.flag;
    this.onFlagChange$.next(this.flag); // Here, .next instead of .emit
  }
}

Error

  1. Using BehaviorSubject instead of EventEmitter

Optimization

  1. Always unsubscribe from observable!

Refactoring

  1. Do not declare :boolean if you're already adding a value to it, this is implicit.
  2. Move toggle logic inside the service
  3. Do not declare ngOnInit if not used
  4. Make services private if not used in the html file
  • Related