Im fairly new to Angular and am having trouble passing an array to a different (not parent/child related) component on a different route. What I want in my app is to click on a button to mark a booking as 'accepted', and to display that same array of accepted bookings in a different view (changing the route).
I've tried implementing a BehaviorSubject but its not working. I can set the array succesfully, but when I want to retrieve it by subscribing to it in the 2nd component, it only shows the initial value of the subject, which in this case is 'Hello World'. Please help me, I've been trying this for a week, watching youtube videos and googling, but I cant find whats wrong. PD: I have not added sharedService as a provider in the app.component.ts, if anyone was wondering.
First component
import { Component, OnInit } from '@angular/core';
import {SharedService} from '../../services/shared.service';
import {share} from 'rxjs/operators';
@Component({
selector: 'app-turnos',
templateUrl: './turnos.component.html',
styleUrls: ['./turnos.component.css'],
providers:[TurnoService]
})
export class TurnosComponent implements OnInit {
public turnos: Turno;
public status;
constructor(
private _sharedService: SharedService
) { }
acceptBooking(booking){
this._sharedService.addToAccepted(booking);
this._sharedService.acceptedBookingsSubject.pipe(share()).subscribe(res=>console.log(res));
//this is just to watch the response, which shows the correct array, but it works only in this component
}
}
Now, the shared service
import {Injectable} from '@angular/core';
import {BehaviorSubject} from 'rxjs';
import {Turno} from '../models/turno';
import {Observable} from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class SharedService{
private acceptedBookings=[];
public acceptedBookingsSubject= new BehaviorSubject<any[]>(['Hello World']);
constructor(){
}
addToAccepted(turno : Turno){
this.acceptedBookings.push(turno);
this.acceptedBookingsSubject.next(this.acceptedBookings);
}
}
And finally, the 2nd component, which has to show all the accepted bookings. I've used both the pipe(share()) using async pipe ,and subscribe() options to see if any worked, but both just show 'Hello World' when I call a console.log.
import { Component, OnInit} from '@angular/core';
import {SharedService} from '../../services/shared.service';
import {Observable} from 'rxjs';
import {Turno} from '../../models/turno';
import {share} from 'rxjs/operators';
@Component({
selector: 'app-turnoaceptado',
templateUrl: './turnoaceptado.component.html',
styleUrls: ['./turnoaceptado.component.css'],
providers:[SharedService]
})
export class TurnoaceptadoComponent implements OnInit {
public acceptedBookings;
public array:Observable<any[]>;
public test;
ngOnInit(): void {
this.array = this._sharedService.acceptedBookingsSubject.asObservable();
this.array.subscribe(response=>this.acceptedBookings=response);
this.test=this.array.pipe(share());
console.log(this.test);
console.log(this.acceptedBookings);
}
constructor(private _sharedService: SharedService) { }
}
First of all, since you're providing the service in the root (
provideIn: 'root'
) you need to remove it from theproviders
array from your components and any other module if it's provided there.
When passing data between components using subjects you must keep in mind that you send that data from a component as a payload through the next
method of the subject but for 'reading' the data you must create a new observable with the subject as the source (asObservable()
method) as you do in the second component.
In your service:
@Injectable({
providedIn: 'root',
})
export class SharedService{
private acceptedBookingsSubject= new BehaviorSubject<any[]>(['Hello World']);
public bookingListener$ = this.acceptedBookingsSubject.asObservable();
constructor(){ }
addToAccepted(turno : Turno){
this.acceptedBookingsSubject.next(turno);
}
}
In your first component:
acceptBooking(booking) {
this._sharedService.addToAccepted(booking);
// you should move this in the OnInit life cycle hook but you need to remove the take operator or to increase the value
this._sharedService.bookingListener$
.pipe(take(1))
.subscribe(console.log);
}
In your second component:
public acceptedBookings$: Observable<any[]>;
ngOnInit(): void {
this.acceptedBookings$ = this._sharedService.bookingListener$;
this.acceptedBookings$.subscribe(console.log);
}
I've created this stackBlitz to give you an example. I hope it helps you.
Tip: Use the
async
pipe for displaying your data and usetap
operator for side effects instead of manually subscribing in the component.