18

I have a root component that has a changing boolean and I want to subscribe to that changing boolean, with a component within my <router-outlet>. I understand I need to use a shared bidirectional service of some sort. However, the docs for shared services just arent making a whole lot of sense to me. (I guess I cant wrap my head around the astronaut example) here, any help would be greatly appreciated, here is a little bit of code to show what I am trying to do.

root component

@Component({
   selector: 'my-app',
   template: `<nav [state]="boolshow"  (show)="changeValue($event)" ></nav> 
          <article><router-outlet></router-outlet></article>  <-----component in router here
          <footer></footer>
          <h3>toggle state: {{boolshow}}</h3>`,
   styleUrls: ['./Css/app.css'],

   })
 export class AppComponent {
   boolshow: boolean;      <-----boolean that needs to be read
  }
Bean0341
  • 1,632
  • 2
  • 17
  • 37
  • 1
    If your application state tree doesn't fit your components tree, http://redux.js.org/ can help. Just a suggestion – mfrachet Oct 03 '16 at 15:13
  • You can inject AppComponent instance into route component and use its property. But it is a lousy practice. And you can't pass `boolshow` through inputs to route component. That's because shared service is recommended way to do this. – Estus Flask Oct 03 '16 at 15:49

1 Answers1

35

It's exactly how they say in that Angular2 Docs :

  • Create a Service with an Observable

  • Inject the same Service in both components

  • From one component you update the data to the Service

  • From the other component you read the data from the Service

Ex.

The Service :

@Injectable()
export class DataService {
    private dataObs$ = new Subject();

    getData() {
        return this.dataObs$;
    }

    updateData(data: boolean) {
        this.dataObs$.next(data);
    }
}

The Components :

@Component({
  selector: 'my-app',
  template: `<div (click)="updateData(false)">Click t oupdate Data FALSE</div>
             <div (click)="updateData(true)">Click to update Data TRUE</div>
            <child></child>
            `
})
export class AppComponent {
    constructor(private dataService: DataService) {}

    updateData(value: boolean) {
      this.dataService.updateData(value);
    }
}


@Component({
  selector: 'child',
  template: `<div><p>data from Service HERE:</p><p style="color:red"> {{myData}}</p></div>`
})
export class ChildComponent {
    myData: boolean;

    constructor(private dataService: DataService) {}

    ngOnInit() {
      this.dataService.getData().subscribe(data => {
        this.myData = data;
      })
    }
}

Make sure to have the same Service injected in the components (Singleton):

@NgModule({
  imports:      [ BrowserModule, HttpModule ],
  declarations: [ AppComponent, ChildComponent ],
  providers: [ DataService ],
  bootstrap:    [ AppComponent ]
})

A full working example can be found HERE : http://plnkr.co/edit/nJVC36y5TIGoXEfTkIp9?p=preview

PS: This is how the communication via Service works in Angular2, it doesn't matter if your component is inside a router-outlet via a router, it works everywhere.

Tiberiu Popescu
  • 4,486
  • 2
  • 26
  • 38
  • 2
    This was so much simpler to understand and I got my service working correctly. thank you! – Bean0341 Oct 03 '16 at 17:00
  • 1
    what if we want to update a variable in other sibling component when a method is called in component, I have done this with EventEmitter but that doesn't work with routerOutlet, so How to use service to instantly update data in other component? – Saurabh Singh Nov 18 '17 at 21:12
  • it's the same, do the communication with the service and observables as in this example – Tiberiu Popescu Nov 19 '17 at 07:27
  • 3
    In my case, I had to remove the service from providers attribute of particular components. Take care about that, if not, it doesn't work. This should be registered as global provider in some module as the answer example. – The.Bear Jun 07 '18 at 13:38
  • Does this still work in angular 7? The example in plnkr doesnt open – Mohit Harshan Mar 28 '19 at 11:48