使用Subject Observable的Angular服务调用next()方法,组件订阅未能看到。

13 浏览
0 Comments

使用Subject Observable的Angular服务调用next()方法,组件订阅未能看到。

我想从Angular服务中检索一个更新的对象值(借款人)。我在服务中创建了一个RxJS的Subject,这样多个组件就可以订阅它并获取更新的值。

当我通过组件中提供的服务订阅该Subject时,我发现即使从BorrowerService中调用.next()onNext()函数参数也从未被调用。

如果我在BorrowerService类中订阅,我发现.next()按预期工作。似乎在调用.next()的Service类和组件之间,Subject是不同的实例,因此不能获取该订阅。

这是对Angular服务或Observables的理解上的错误吗?如何在Service中更新值并在Component中被动地获取更改,而无需知道何时调用.next()

borrower-report.component.ts

@Component({
    ...
    providers:   [BorrowerService]
})
export class BorrowerReport {
    private borrower: Borrower;
    constructor(private borrowerService: BorrowerService) {
        this.borrowerService.borrowerChanged.subscribe(borrower => {this.borrower = borrower});
    }
}

borrower.service.ts

@Injectable()
export class BorrowerService {
    public borrowerChanged: Subject = new Subject();
    //event handler
    selectBorrower(borrower: Borrower) {
        this.borrowerChanged.next(borrower);
    }
}

0
0 Comments

在上述代码中,出现了一个问题:当调用`BorrowerService`的`changeValue`方法时,`borrowerChanged`的`BehaviorSubject`被更新,但是在`BorrowerReportComponent`中对`borrowerChangedObservable`的订阅并没有接收到更新的值。

这个问题的出现原因是`borrowerChangedObservable`在`BorrowerReportComponent`中的订阅是在组件初始化时进行的,而此时`borrowerChanged`的`BehaviorSubject`已经被创建并且拥有了默认值。因此,当调用`changeValue`方法更新`borrowerChanged`时,`BorrowerReportComponent`并没有重新订阅,所以无法接收到更新的值。

解决这个问题的方法是,在`BorrowerReportComponent`中使用`ngOnChanges`生命周期钩子重新订阅`borrowerChangedObservable`。这样,每当`borrowerChanged`的值发生变化时,`BorrowerReportComponent`都会重新订阅并接收到更新的值。

修改后的代码如下:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { BorrowerService } from './borrower.service';
import { Subscription } from 'rxjs';
@Component({
  selector: 'app-borrower-report',
  templateUrl: './borrower-report.component.html',
  styleUrls: ['./borrower-report.component.css']
})
export class BorrowerReportComponent implements OnInit, OnDestroy {
  private subscription: Subscription;
  constructor(private borrowerService: BorrowerService) {}
  ngOnInit(): void {
    this.subscription = this.borrowerService.borrowerChangedObservable.subscribe((borrower) => {
      console.log(borrower);
    });
  }
  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }
  sendNewValueToBorrowerService(): void {
    this.borrowerService.changeValue('my new value');
  }
}

通过在`ngOnInit`生命周期钩子中订阅`borrowerChangedObservable`,并在`ngOnDestroy`生命周期钩子中取消订阅,确保了每当`borrowerChanged`的值发生变化时,`BorrowerReportComponent`都能接收到更新的值。

需要注意的是,在组件的模板中,需要添加一个按钮或其他触发器来调用`sendNewValueToBorrowerService`方法,以便测试更新值的功能。

最后,确保在相同的模块中将`BorrowerService`添加到`providers`数组中,将`BorrowerReportComponent`添加到`declarations`数组中,以便正确注入和使用服务。

0
0 Comments

问题的原因是服务的范围,并且没有提供服务。如果您希望这是一个单例服务(多个组件共享同一个服务实例),那么您需要在包含所有子组件的父模块中提供该服务。要确保路由,您需要在app.module.ts中添加这个。在模块中导入它,并像在组件中那样提供它作为服务(不过要从组件中删除它作为提供者,您只需要父模块提供它)。

然后,您可以像之前一样将服务导入到组件中,provider将是父模块。基本思路是父模块将托管所有子组件的服务,因此所有子组件将接收到相同的服务实例(因此相同的值)。

额外说明:这个Stack Overflow回答提供了创建单例服务ApiService的详细信息,并且应该作为一个可靠的指南。其他顶级答案也提供了很好的解释。

第二点说明:如果您希望从您的主题中获得推送更新,您也应该使用BehaviorSubject。对BehaviorSubject的订阅将自动更新,而对Subject的订阅必须手动调用。

这对我有帮助,服务被实例化了两次。谢谢!

0