【问题标题】:BehaviorSubject wont update in different routeBehaviorSubject 不会在不同的路径中更新
【发布时间】:2020-08-07 03:33:06
【问题描述】:

我对 Angular 很陌生,并且在将数组传递给 不同路径 上的不同(与父/子相关)组件时遇到了麻烦。我想要在我的应用程序中单击一个按钮以将预订标记为“已接受”,并在不同的视图中显示相同的已接受预订数组(更改路线)。

我尝试实现一个 BehaviorSubject,但它不起作用。我可以成功设置数组,但是当我想通过在第二个组件中订阅它来检索它时,它只显示主题的初始值,在本例中为“Hello World”。请帮助我,我已经尝试了一周,观看 youtube 视频和谷歌搜索,但我找不到什么问题。 PD:如果有人想知道的话,我没有在 app.component.ts 中添加 sharedService 作为提供程序。

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
}

}

现在,共享服务

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


 }




}

最后是第二个组件,它必须显示所有已接受的预订。我已经使用了使用异步管道的管道(share())和订阅()选项来查看是否有任何工作,但是当我调用 console.log 时,两者都只显示“Hello World”。

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) { }

}

【问题讨论】:

  • 我有一个问题需要更好地理解才能更好地回答:您什么时候第一次在第二个组件中调用订阅?通常,根据我的经验,您应该在更新之前订阅。
  • @LuDeveloper 我已经尝试在 OnInit 和构造函数中订阅,我对此不太了解,因为我是 Angular 新手。在更新其他组件之前如何订阅?

标签: angular rxjs observable subscription behaviorsubject


【解决方案1】:

首先,由于您在根 (provideIn: 'root') 中提供服务,因此您需要将其从组件和任何其他模块(如果在那里提供)的 providers 数组中删除。

当使用主题在组件之间传递数据时,您必须记住,您通过主题的next 方法将来自组件的数据作为有效负载发送,但是为了“读取”数据,您必须使用就像您在第二个组件中所做的那样,将主题作为源(asObservable() 方法)。

为您服务:

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

在您的第一个组件中:

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

在您的第二个组件中:

public acceptedBookings$: Observable<any[]>;

  ngOnInit(): void {
    this.acceptedBookings$ = this._sharedService.bookingListener$;

    this.acceptedBookings$.subscribe(console.log);
  }

我创建了this stackBlitz 给你一个例子。希望对你有帮助。

提示:使用async 管道来显示您的数据并使用tap 运算符来获得副作用,而不是在组件中手动订阅。

【讨论】:

  • 我非常感谢您的回答,因为您实际上花时间为我编写所有这些代码,甚至制作了一个堆栈闪电战,但不幸的是,如果您将组件放在不同的路线上,它就无法正常工作,它仅当它们在同一路线上时才有效。如果我试图实现的目标是不可能的,你现在可能会吗?
  • @Ayrton 我更新了 stackblitz 以演示数据在组件之间通过路由传递。试一试。也许我没有正确理解你想要达到的目标。你能用你想要的行为创建一个堆栈闪电战还是分叉我的?
  • 你是对的!!我通过直接在另一个选项卡中打开组件而不是通过另一个组件中的链接单击它来访问路由!这就是问题所在!非常感谢
  • 很高兴能为您提供帮助。编码愉快!
【解决方案2】:

TurnosComponent 和 SharedService 中的代码看起来是正确的。

但是在您的 TurnoaceptadoComponent 中,您的“console.logs”在 RXJS 流之外。您应该在订阅中使用 console.log,例如:

this.array.subscribe(response=&gt; console.log(response));

然后您应该能够看到来自流的所有值。

【讨论】:

  • 我现在已经完成了,但它只是显示'Observable',里面有很多东西,但没有值或数组;当我在另一个组件中单击接受预订时,控制台日志保持不变,没有任何变化。
  • 所以我确实在您的代码中看到了另一个潜在问题。在您的下一个值的服务中,您始终传递对同一数组的引用。尝试像这样解构它: this.acceptedBookingsSubject.next( [... this.acceptedBookings] )
猜你喜欢
  • 1970-01-01
  • 2016-01-23
  • 2018-12-26
  • 2014-01-04
  • 1970-01-01
  • 2011-09-05
  • 2023-02-03
  • 2019-02-08
  • 2023-04-11
相关资源
最近更新 更多