Issue
I have a parent component HeaderComponent with two children, NavComponent
and BurgerComponent
! At the moment, there is a class that toggles the active/inactive state of the burger when clicked on it! Below is the first image when the BurgerComponent
is inactive, the second with an active BurgerComponent
and NavComponent
visible.
The issue
The NavComponent
is closed by a click on nav area, but I also need the BurgerComponent
to go to the inactive state(image 1).
What I have so far:
NavCompoent HTML with click event
<nav class="nav-menu {{ menuStatus }}" (click)="collapseMenu($event)">
NavComponent TS:
export class NavComponent implements OnInit {
title: string;
closeMenu: boolean;
@Output() sendTitle = new EventEmitter < string > ();
@Output() menuClose = new EventEmitter<any>();
@Input() menuStatus: boolean;
active = false;
constructor() {}
ngOnInit() {}
getText(event) {
this.title = event.target.innerText;
this.sendTitle.emit(this.title)
console.log("title sent", this.title);
}
collapseMenu($event) {
this.menuStatus = false;
this.menuClose.emit(this.menuStatus);
}
}
HeaderComponent HTML (this is the parent component)
<header class="sticky">
<div class="header-container">
<div class="header-left">
<h1>{{pageTitle}}</h1>
</div>
<div class="header-right">
<app-burger (opened)="burgerStatus($event)" [menuCloseBurger]="menuClose"></app-burger>
</div>
</div>
</header>
<app-nav (sendTitle)="getTitle($event)" [menuStatus]="burger" (menuClose)="sendingMenuClose($event)"></app-nav>
Header Component TS:
export class HeaderComponentComponent implements OnInit {
route: string;
pageTitle: string;
burger: string;
menuClose: string;
constructor(location: Location, router: Router) {
router.events.subscribe(val => {
this.pageTitle = location.path();
this.pageTitle = this.pageTitle.substring(1);
});
}
ngOnInit() {
this.pageTitle = this.route;
console.log(this.pageTitle);
}
getTitle($event) {
console.log(this.route);
this.pageTitle = $event;
}
burgerStatus($event) {
this.burger = $event;
console.log($event);
}
sendingMenuClose($event) {
this.menuClose = $event;
console.log("menu close at parent", this.menuClose);
}
}
BurgerComponent TS:
export class BurgerComponent implements OnInit {
active: boolean;
@Output() opened = new EventEmitter<any>();
@Input() menuCloseBurger: string;
constructor() { }
ngOnInit() {
this.active = false;
}
onBurgerClicked() {
this.active = !this.active;
this.opened.emit(this.active);
}
}
BurgerComponent HTML:
<div class="burger-menu" [class.active]="active" (click)="onBurgerClicked()">
<div class="burger-container">
<div class="burger-inner"></div>
</div>
</div>
collapseMenu() send a boolean value false, I need to get this into the BurgerCompnent class somehow so the value of that is false and the burger close. I am so close, I can't figure out the last step!
As per @PitchBlackCat's recommendation I have create a service NavStatusService!
import { Injectable } from '@angular/core';
import { EventEmitter } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class NavStatusService {
constructor() { }
public readonly isNavCollapsed$ = new EventEmitter<boolean>();
}
I have implemented it in the BurgerComponent:
onBurgerClicked() {
this.active = !this.active;
this.state.isNavCollapsed$.emit(this.active);
}
Now I am stuck as to how the communication between in the two component, Burger and Nav supposed to work!
Solution
You need a separate service to manage the shared variables.
You could try a framework like ngrx or create your own service along the lines of the example provided below.
Notice how the application-state.service has become the owner of the data that is shared between multiple components. This way, components that live in seperate parts of your layout can share data, whithout knowing about eachother.
application-state.service
export class ApplicationStateService implements OnInit {
public isNavCollapsed: boolean = false;
}
burger.component
<button class="burger" [class.active]="!state.isNavCollapsed" (click)="onBurgerClicked()">
</button>
import { Component, OnInit } from '@angular/core';
import { ApplicationStateService } from '../application-state.service';
@Component({
selector: 'app-burger',
templateUrl: './burger.component.html',
styleUrls: ['./burger.component.css']
})
export class BurgerComponent implements OnInit {
constructor(public state: ApplicationStateService) { }
ngOnInit() {
}
onBurgerClicked() {
this.state.isNavCollapsed = !this.state.isNavCollapsed;
}
}
nav.component
<ul *ngIf="!state.isNavCollapsed">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>
<button (click)="state.isNavCollapsed = true">close</button>
</li>
</ul>
import { Component, OnInit } from '@angular/core';
import { ApplicationStateService } from '../application-state.service';
@Component({
selector: 'app-nav',
templateUrl: './nav.component.html',
styleUrls: ['./nav.component.css']
})
export class NavComponent implements OnInit {
constructor(public state: ApplicationStateService) { }
ngOnInit() {
}
}
Check out this example on StackBlitz to see it in action
Answered By - PitchBlackCat
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.