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
- Using
BehaviorSubject
instead ofEventEmitter
Optimization
- Always unsubscribe from observable!
Refactoring
- Do not declare
:boolean
if you're already adding a value to it, this is implicit. - Move toggle logic inside the
service
- Do not declare
ngOnInit
if not used - Make services
private
if not used in thehtml
file