22

How can a component change a variable on another component. Example:

I have a component app.component.ts

@Component({
    selector: 'my-app',
    template: `
    <nav *ngIf="onMain == false">
       Hello
    </nav>
    `
})

export class AppComponent{
  onMain: Boolean;

  constructor(){
      this.onMain = false;
    }
}

I have another component which I want to change onMain in my app component main.component.ts

import {AppComponent} from '../app.component';

@Component({
    selector: 'main-app',
    template: ``
})

export class MainComponent{

  constructor() {
      this.appComponent = AppComponent;
      this.appComponent.onMain = true;
    }
}

I would expect that Hello would disappear, but it doesn't. How can I have one component change the value on another component?

ClickThisNick
  • 4,680
  • 8
  • 32
  • 59
  • 1
    You can use `EventEmitter` in a **service**. Then let AppComponent subscribe it to get the event of the change. – Hongbo Miao Mar 02 '16 at 04:15

4 Answers4

29

First of all, you have no connection between two components or maybe something is not correct in your code. If you have parent/child scenario you can use @Input,@Output of angular2. If you don't have parent/child scenario you can go with EventEmitter,SharedService of angular2.

Working demo-EventEmitter way

I have considered AppComponent is a parentComponent and MainComponent as a child component. Using SharedService & EventEmitter concepts of angular2, I'm able to hide AppComponent's part of view by clicking a button which belongs to 'MainComponent's' view.

AppComponent.ts

import {Component,bind,CORE_DIRECTIVES,OnInit} from 'angular2/core';
import {MainComponent} from 'src/MainComponent';
import {SharedService} from 'src/shared.service';
@Component({
    selector: 'my-app',
    directives:[MainComponent],
    template: `<h1>AppComponent {{onMain}}</h1>
    <div *ngIf="onMain == false">
       Hello
      <br> __________________________________<br>
    </div>

  <main-app></main-app>
    `
})

export class AppComponent implements OnInit {
  onMain: Boolean;

  constructor(ss: SharedService) {
      this.onMain = false;
      this.ss = ss;
    }



    ngOnInit() {
    this.subscription = this.ss.getEmittedValue()
      .subscribe(item => this.onMain=item);
  }

}

MainComponent.ts

import {Component,bind,CORE_DIRECTIVES} from 'angular2/core';
import {SharedService} from 'src/shared.service';
@Component({
    selector: 'main-app',

    template: `<h1> MainComponent</h1>
    <button (click)="changeName()">Change Name</button>
    `
})

export class MainComponent {



    constructor(ss: SharedService) {
      this.ss = ss;
    }

    changeName() {
      this.ss.change();
    }
}

shared.service.ts

import {Component, Injectable,Input,Output,EventEmitter} from 'angular2/core'


@Injectable()
export class SharedService {
  @Output() fire: EventEmitter<any> = new EventEmitter();

   constructor() {
     console.log('shared service started');
   }

   change() {
    console.log('change started'); 
     this.fire.emit(true);
   }

   getEmittedValue() {
     return this.fire;
   }

} 
micronyks
  • 49,594
  • 15
  • 97
  • 129
  • 3
    Where does this.subscription come from on AppComponent? I'm getting an error that the property subscription does not exist on AppComponent – ClickThisNick Mar 03 '16 at 13:32
  • Have you added **`rx.js`** file? look at the **`index.html`** in my plunker demo. you will find necessary referencing of required files. And if answers suits your requirement you should accept it as an answer so other may refer to it as an answer. – micronyks Mar 03 '16 at 16:00
  • @micronyks thanks. Can you also share the package.json? Because things are not working with latest platform and other packages please. – Ravi Maniyar Oct 10 '16 at 16:52
  • @RaviManiyar. please look here https://angular.io/docs/ts/latest/quickstart.html for latest `package.json`. – micronyks Oct 10 '16 at 16:54
  • 1
    Thanks @micronyks! This was exactly what I needed!! – Rapid99 Mar 08 '19 at 18:46
  • How do we fire this (fire) event in the desired component. Can you please explain this? – Ahsan Apr 03 '19 at 11:13
10

If there is no relation between components (I mean parent / child), you need to use a shared service with an EventEmitter property. One component will emit an event based on it and this other component will be notified by subscribing the EventEmitter. When the event is received, this component can set a property used to show / hide the button...

  • Shared service

    @Injectable()
    export class SharedService {
      onMainEvent: EventEmitter = new EventEmitter();
    }
    

    Don't forget to define the corresponding provider in the boostrap function to be able to share the same instance of the service for the whole application: `bootstrap(AppComponent, [ SharedService ]);

  • AppComponent component

    @Component({ ... })
    export class AppComponent {
      onMain: boolean = false;
      constructor(service: MenuService) {
        sharedService.onMainEvent.subscribe(
          (onMain) => {
            this.onMain = onMain;
          }
       );
     }
    

    }

  • MainComponent component:

    export class MainComponent {
      constructor(private service: SharedService) {
      }
    
      updateOnMain(onMain):void {
        this.service.onMainEvent.emit(onMain);
      }
    }
    

These questions for more details:

Community
  • 1
  • 1
Thierry Templier
  • 182,931
  • 35
  • 372
  • 339
4

Yes you can change the variable value from one component to another one for this you have to inject the component exported class into the parent component by doing so you are able to reach each and every method and variable of injected class (component).

import {Component} from 'angular2/core';
@Component({
    selector: 'my-app',
    templateUrl: `myTemplate.html`,
    directive: [AppComponent2]
})

export class AppComponent {
  variable1: boolean = true;
}

@Component({
    selector: 'my-app2',
    templateUrl: `temp2.html`,
    providers: [AppComponent]
})

export class AppComponent2 {
  constructor(private appComponent: AppComponent){ }
  Fun(){
    console.log('Function Called');
    this.appComponent.variable1 = false;
  }
}


<button (click)='Fun()'>Change Variable</button>

{{appComponent.variable1}}
  • Updated as per ng6 -

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

Working Example http://plnkr.co/edit/fpYFueOnkm5sa4JfG7uX?p=preview

Pardeep Jain
  • 71,130
  • 29
  • 141
  • 199
  • It will work with Angular 6? Could you please update the code if possible? Because i have tried to include @Directive for Angular 6, but no luck. – Raja Oct 08 '18 at 01:58
  • Yeah this should work with angular 6 as well, I'll Update answer shortly – Pardeep Jain Oct 08 '18 at 05:28
1

If you have a parent/child relationship you can use an event emitter to flip the variable with just a couple lines of code. There is no need to write a whole shared service.

app.component.ts

@Component({
    selector: 'my-app',
    template: `
    <nav *ngIf="onMain == false" (observableEvent)="onMain == true">
       Hello
    </nav>
    `
})

main.component.ts

import {AppComponent} from '../app.component';
import { Output, EventEmitter } from '@angular/core';

@Component({
    selector: 'main-app',
    template: ``
})

export class MainComponent{
    @Output() observableEvent: EventEmitter<any> = new EventEmitter<any>();

  constructor() {
      this.appComponent = AppComponent;
      this.observableEvent.emit();
    }
}
Arajay
  • 466
  • 5
  • 6