简体   繁体   中英

How do I share data between sibling components in angular?

I have an Angular application with 3 sibling components, they are able to access and update the variable "data". They are connected to the router, but the data I want to pass is sensitive (api endpoints to determine discounts) so I cannot use cmp2/:data

Component 1 has an object called data and Components 2 and 3 need to receive this data object. I think this can be done with a shared service, but I'm not quite sure how to get this event emitter to work..

My index.html:

<router-outlet></router-outlet>

Component 1:

<button [routerLink]=['cmp2/']>Go to Comp 2 </button>
<button [routerLink]=['cmp3/']>Go to Comp 3 </button>

Components 2 and 3:

{{ data }}

As it looks like you are looking to redirect to those components, what you can do is have an event emitter on component one, that on click will emit the data to the parent(of all 3). Then in the parent you would catch the emit, and assign that to data that you pass into the other components.

Component1

import { Component, EventEmitter, Output } from '@angular/core';
import { Router }                          from '@angular/router';

@Component(...)
export class Component1 {
    @Output() redirect:EventEmitter<any> = new EventEmitter();

    data:any = {text: "example"};

    constructor(private router:Router){}

    changeComponent(url:string){
        this.redirect.emit(data);//emits the data to the parent
        this.router.navigate([url]);//redirects url to new component
    }
}

Component2 & Component3

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

@Component(...)
export class Component2 {
    @Input() data:any;
}

Parent

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

@Component(...)
export class Parent {
    parentData:any;
}

Parent.html

<component1 (redirect)="parentData=$event"></component1>
<component2 [data]="parentData"></component2>
<component3 [data]="parentData"></component3>

Another option, if you don't have a parent, is to have a service, that you inject into each parent, and then for the receivers hook into the OnInit lifecycle hook. This works because services are a singleton if in a provider of a shared module.

Service

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

@Injectable()
export class SharingService{
    private data:any = undefined;

    setData(data:any){
        this.data = data;
    }

    getData():any{
        return this.data;
    }
}

Component1

import { Component }      from '@angular/core';
import { Router }         from '@angular/router';
import { SharingService } form './sharing.service';

@Component(...)
export class Component1 {

    data:any = {text: "example"};

    constructor(private router:Router,
        private sharingService:SharingService){}

    changeComponent(url:string){
        this.sharingService.setData(this.data);
        this.router.navigate([url]);//redirects url to new component
    }
}

Component2 & Component3

import { Component, OnInit } from '@angular/core';
import { SharingService }    form './sharing.service';

@Component(...)
export class Component2 implements OnInit{
    data:any;

    constructor(private router:Router,
        private sharingService:SharingService){}

    ngOnInit(){
        this.data = this.sharingService.getData();
    }
}

Make sure you add it to providers array of the module.

Module

import { SharingService } from './sharing.service';
...

@NgModule({
    ...
    providers: [ SharingService ]
})

Since you have asked to share the data between sibling components we can achieve it by using BehaviourSubject in service.

The BehaviorSubject holds the value that needs to be shared with other components. These components subscribe to data which is simple returning the BehaviorSubject value without the functionality to change the value.

Service.ts

import { Observable, BehaviorSubject } from 'rxjs';

export class Service {
       private data = new BehaviorSubject("")
       currentData = this.data.asObservable();

 constructor() { }

 setData(data) {
      this.data.next(data);
 }

Component1.ts

import { Service } from '../service.service';

export class component1 implements OnInit {

data: any;

constructor (private service: Service) {}

sendDataToService() {
     this.service.setData(this.data);
}

Component2.ts

import { Service } from '../../service.service';

export class component2 implements OnInit {

constructor ( private service: Service ) { }

ngOnInit() {
    this.service.currentData.subscribe(data => {
      console.log(data);
    });
}

Since you have multiple receiver components , Best way is to use a singleton shared service . Because later if you create more receiver components , emitting to each and every individual component would not be appropriate.

Incase you need :

Simple explanation for Output and EventEmitter

https://angular.io/docs/ts/latest/api/core/index/EventEmitter-class.html

Angular has the facility to share data between siblings through $emit, $broadcast and $on in angular's $scope and $rootScope event system.

<div>
  <div ng-controller="SiblingOneCtrl1 as sib1" class="ng-scope">
    // SiblingOneCtrl
  </div>
  <div ng-controller="SiblingTwoCtrl2 as sib2" class="ng-scope">
    // SiblingTwoCtrl
  </div>
</div>

app.controller('SiblingOneCtrl1',
  function SiblingOneCtrl1 ($rootScope) {

  $rootScope.$on('rootScope:emit', function (event, data) {
    console.log(data); // 'Emit!'
  });

  $scope.$on('rootScope:broadcast', function (event, data) {
    console.log(data); // 'Broadcast!'
  });

  $rootScope.$on('rootScope:broadcast', function (event, data) {
    console.log(data); // 'Broadcast!'
  });

});

app.controller('SiblingOneCtrl2',
  function SiblingOneCtrl2($rootScope) {

  $rootScope.$emit('rootScope:emit', 'Emit!'); // $rootScope.$on
  $rootScope.$broadcast('rootScope:broadcast', 'Broadcast'); // $rootScope.$on && $scope.$on

});

also, you can follow this and this

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM