简体   繁体   中英

Angular transfer data between two unrelated components

I have two elements in my angular project that are completely independent. The first one shows a list of license plates and two buttons for each plate: "View current position" and "View positions for the last 24h". Those two buttons redirect to the same component which shows in a map some points depending of a variable "method". I want to set the "method" in a certain value when the button is clicked, but I have no idea how to do this.

I have tried about the Subject/Subscribe thing but did not work for me. It is possible that I did not apply it properly, as I am not very confident about how it works. In the examples I have found, the subject was emmited by some @Injectable, but I am working with two @Component.

Thank you all.

Edit: I will try to explain what I have tried.

I have the service

import { Inject, Injectable } from "@angular/core";
import { MatriculasListadoComponent } from "../components/matriculas-listado/matriculas-listado.component";
import { Metodos } from "../models/metodos";

@Injectable({
  providedIn: 'root'
})
export class ConexionDataService {
    metodoBoton: Subject<Metodos>
  
    constructor() {
      this.metodoBoton = new Subject<Metodos>();
    }
    
    } 

Then I have a method in my component from where I want to send the data which is called clicking the buttons:

constructor(private matriculaService: MatriculaService, private conexionDataService: ConexionDataService) {
    this.dataSource = new MatTableDataSource<Matricula>([]);
  }

...

enviarMetodo(metodo:Metodos) {
    this.conexionDataService.metodoBoton.next(metodo);
  }

And I have this NgOnInit in the component where I want to recieve the data

providers: [ListaPosicionesService, DatePipe, ConexionDataService]

...

ngOnInit(): void {
    this.conexionDataService.metodoBoton.subscribe(log=> {
      this.metodo=log
      console.log(log)
    })

I am getting log as "undefined". Probably I am not doing it properly as I do not understand at all how those services work...

When passing data between components that lack a direct connection, such as siblings, grandchildren, etc, you should use a shared service. When you have data that should aways been in sync, I find the RxJS BehaviorSubject very useful in this situation.

You can also use a regular RxJS Subject for sharing data via the service, but here's why I prefer a BehaviorSubject.

  1. It will always return the current value on subscription - there is no need to call onnext
  2. It has a getValue() function to extract the last value as raw data.
  3. It ensures that the component always receives the most recent data.

Here is the working demo BehaviorSubject | Stackblitz

shared service

private messageSource = new BehaviorSubject('default message');
changeMessage(message: string) {
  this.messageSource.next(message);
}

Parent-Component

constructor(private data: DataService)
this.data.changeMessage('Hello from About component');

sibling-Component

constructor(private data: DataService)
this.data.currentMessage.subscribe(
  (message) => (this.message = message)
);

Whenever the parent emits using the next method, you can receive the data in other component and act on it.

In the demo i have created it will redirect as well and updated data will be available in the component we redirected to.

You can use a library like NgRx . This will allow you to communicate between components easily without creating the relation "parent-child" between them.

Just dispatch an action from your current component and create an effect to catch and trigger the other component

If its a complicated app then NGRX to maintain state is a good idea. However, its a lot of boilerplate code for a simple app where BehaviourSubjects maybe what you are after.

BehaviourSubjects are observables that require initialisation. They tend to sit on an existing service you may have defined (DI injected via your component constructor).

BehaviorSubject vs Observable?

The flow is like this...

Define your BehaviourSubject on a service. Mine is a service called CommonSvc. Here is a good article about services. https://angular.io/tutorial/toh-pt4

public loadingSub: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

Create a public method to expose the subject and set the next value

  public setLoading(loading: boolean,): void {
      this.loadingSub.next(loading);
  }

On your component, inject your service into the constructor.

private commonSvc: CommonService

You can now access the BehaviourSubject directly. Something like this.

  this.commonSvc.loadingSub
  .subscribe((loading) => {
    this.loading = loading;
  });

...and it you need to update the BehaviourSubject, call the public method.

this.commonSvc.setLoading(true);

Now, the beauty of this method is that everywhere you subscribe to the BehaviourSubject, the same value will be presented. You can inject the service anywhere in your components so it makes it pretty flexible too.

The downside is that when you have lots of them (Subjects & BehaviourSubjects) they can get tricky to manage. That's where NGRX comes in.

PS. If you are subscribing to subscriptions, don't forget to unsubscribe when you are done.

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