0

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).

The inactive BurgerActive burger with NavComponent visible

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!

1
  • Simply store your state in a service, and inject the service in all your components. That's what services are for. Commented Jul 26, 2019 at 13:12

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

3 Comments

...or simply act directly on ApplicationStateService.active. If you inject the service in every component, then ApplicationStateService.active will be available everywhere.
This makes a lot of sense theoretically but I am too much of a beginner to find a practical solution! Do you mind elaborating on your answer a bit? Thanks!
I've updated my answer and provided an example The trick is to put the shared variable in a service. I hope this will help you finish your solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.