Leonardo Minati
Leonardo Minati

Reputation: 360

Angular - How can I toggle the visibility of an element in a component from another component?

I have the following scenario in my Angular app:

A component MainDashboardComponent that is visible when I have the route /. Obviously I have the <router-outlet> tag in my app.component.html file, which looks like this:

<app-side-menu></app-side-menu>
<div class="main-container">
  <div class="content">
    <router-outlet></router-outlet>
  </div>
</div>

As you can see I have a SideMenuComponent I use to have a side menu on all my routes. In MainDashboardComponent I have a method that for some reason needs to toggle a chat element that is situated on the side menu. Inside the SideMenuComponent I have a method that handles the visibility toggle for the chat element and it works as expected. How can I call this method from my MainDashboardComponent and toggle the chat element from there?

What I tried with no success

I tried to inject the SideMenuComponent inside my MainDashboardComponent but, though the method toggleChat() is called, the element doesn't change it's visibility. Looks like I have a kind of multiple instance of the same component I guess...

Can you please help me with this? Thank you!

MainDashboardComponent

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-main-dashboard',
  templateUrl: './main-dashboard.component.html',
  styleUrls: ['./main-dashboard.component.scss']
})
export class MainDashboardComponent implements OnInit {

  constructor() { }

  ngOnInit() {}

  setFocus(id) {
    // here I'd like to call SideMenuComponent togglechat() ... 
  }
}

SideMenuComponent

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-side-menu',
  templateUrl: './side-menu.component.html',
  styleUrls: ['./side-menu.component.scss']
})
export class SideMenuComponent implements OnInit {

  showChat: boolean;

  constructor() {
    this.showChat = false;
  }

  ngOnInit() {
  }

  toggleChat() {
    this.showChat = !this.showChat;
  }

}

Upvotes: 2

Views: 6340

Answers (3)

Torsten Weggen
Torsten Weggen

Reputation: 151

Generally this is the domain of a service!

  • Just create a service and add the "showCat" property.
  • Inject the service into both components
  • Alter SideMenuComponent to:

    toggleChat() {
        this.myService.showChat = !this.myService.showChat;
    }
    
  • Alter MainDashboardComponent, also use this.myService.showChat to show / hide your chat window

Service TS

@Injectable()
export class MyService{
  showCat:boolean = true
}

MainDashboardComponent

toggleChat() {
   this.myService.showChat = !this.myService.showChat;
}

SideMenuComponent

chatVisiblity = this.myService.showCat //<-- bind this to the element attribute

Upvotes: 1

Tushar Walzade
Tushar Walzade

Reputation: 3819

You could efficiently use child to parent communication in this scenario. You'll need to create a custom event using angular's EventEmitter in your SideMenuComponent and use it in your MainDashboardComponent.

So, here is some code that may help you -

// SideMenuComponent
import { Component, OnInit } from '@angular/core';
@Component({
    selector: 'app-side-menu',
    templateUrl: './side-menu.component.html',
    styleUrls: ['./side-menu.component.scss']
})
export class SideMenuComponent implements OnInit {
    @Output() valueChange = new EventEmitter();
    showChat: boolean;

    constructor() {
        this.showChat = false;
    }

    ngOnInit() {
    }

    toggleChat() {
        this.showChat = !this.showChat;
        this.valueChange.emit(this.showChat);
    }

}

// MainDashboardComponent
import { Component, OnInit } from '@angular/core';
@Component({
    selector: 'app-main-dashboard',
    template: `<app-side-menu (valueChange)='setFocus($event)'></app-side-menu>`
    styleUrls: ['./main-dashboard.component.scss']
})
export class MainDashboardComponent implements OnInit {

    constructor() { }

    ngOnInit() { }

    setFocus(event) {
        // check for required input value 
        console.log(event);
    }
}

Refer these tutorials if required - https://dzone.com/articles/understanding-output-and-eventemitter-in-angular, https://angular-2-training-book.rangle.io/handout/components/app_structure/responding_to_component_events.html

Upvotes: 0

Sarthak Aggarwal
Sarthak Aggarwal

Reputation: 2312

To communicate between different components, there are different ways.

  • If you want to communicate between parent and child component, you can use EventEmitter to emit event from child component and handle the event in your parent component
  • If you want to communicate between any components, you can use Service and implement communication with the help of EventEmitter or Subject/BehaviorSubject

In your case, we can create a service, myService.ts and declare and eventEmitter

.service.ts

@Injectable()
export class AppCommonService {

 toggle : EventEmitter<boolean> = new EventEmitter<boolean>()

}

mainDashboard.component.ts

constructor(private myService : myService){}

chatStatus : boolean = false;
ngOnInit(){
 this.myService.toggle.subscribe(status=>this.chatStatus = status);
}

toggleChat(){
 this.myService.toggle.emit(!this.chatStatus);
}

sideMenu.component.ts

constructor(private myService : myService){}

chatStatus : boolean = false;

ngOnInit(){
  this.myService.toggle.subscribe(status=>this.chatStatus = status);
}

Upvotes: 7

Related Questions