25

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?

1
  • 1
    You can use EventEmitter in a service. Then let AppComponent subscribe it to get the event of the change. Commented Mar 2, 2016 at 4:15

4 Answers 4

30

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;
   }

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

6 Comments

Where does this.subscription come from on AppComponent? I'm getting an error that the property subscription does not exist on AppComponent
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 thanks. Can you also share the package.json? Because things are not working with latest platform and other packages please.
@RaviManiyar. please look here angular.io/docs/ts/latest/quickstart.html for latest package.json.
Thanks @micronyks! This was exactly what I needed!!
|
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:

Comments

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

2 Comments

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.
Yeah this should work with angular 6 as well, I'll Update answer shortly
2

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();
    }
}

1 Comment

Agreed with your comment. No need to code a whole service on this case.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.