Angular cross-service communication

谁说胖子不能爱 提交于 2020-12-06 07:06:26

问题


I have a statistics application. On the left side of my page I have list of themes, on the top - list of groups. The main part contains statistics items related to both theme and group.

Also I have several services which provide business logic for my application. For simplicity let's talk about three of them: ThemeSerivce, GroupService and StatisticsService.

End users could manipulate lists of themes and groups (add or remove items) and I have to recalculate statistics after each change. In this application I use Subjects and Subsription from rx.js to track such kind of changes.

So, in my components I could write something like this:

for GroupComponent

 removeGroup() {
        this.groupService.removeGroup(this.group);
        this.statisticsService.updateStatistics();
      }

for ThemeComponent

removeTheme() {
    this.themeService.removeTheme(this.theme);
    this.statisticsService.updateStatistics();
  }

But logically these components don't have to know about statistics. Of course I can move dependency of StatisticsService into ThemeService and GroupService, but then I will have to call statisticsService.updateStatistics() in every method which changes collection of themes or groups. That's why I want to implement direct cross-service communication with subscription.

And finally my questions:

  1. Is it a good idea at all?

  2. If it's ok, what is the best way to implement it? When I use Subscription in components, I register it in ngOnInit() method and unsubscribe in ngOnDestroy() to prevent memory leaks. Could I subscribe it in service's constructor? And when or where should I unsubscribe? Or maybe it's not necessary when I register my services as provider on App module level?


回答1:


StatisticsService should subscribe to the list of themes and groups. Your individual components should only subscribe to their respective services (ThemeComponent to ThemeService, Group to Group etc).

For simplicity, I'll just focus on the ThemeService but GroupService is similar. ThemeService should have an internal Subject when remove is called, the Subject will next a value (probably the entire new list).

StatisticsService will subscribe to the ThemeService observable and recalculate after change. It will look something like this

/* theme.service.ts */
@Injectable()
export class ThemeService {
    private _list$ = new Subject<ThemeList>();

    get list(): Observable<ThemeList> {
        return this._list$.asObservable();
    }

    set list(newList: ThemeList) {
       this._list$.next(newList);
    }
}


/* statistics.service.ts */
@Injectable()
export class StatisticsService {
    private _calculation$ = new Subject<StatisticResult>();

    constructor(private themeService: ThemeService) {
        themeService.list.subscribe((themeList: ThemeList) => this.updateCalculation(themeList));
    }

    get calculation(): Observable<StatisticResult> {
        return this._calculation$.asObservable();
    }

    updateCalculation(newData: ThemeList | GroupList) {
        // ... do stuff
        this._calculation.next(statisticResult);
    }
}


/* statistics.component.ts */
@Component({
  selector: 'statistics',
  template: '<p>{{ statisticResult$ | async }}</p>'
})
export class StatisticsComponent {
    statisticResult$: Observable<StatisticResult>;

    constructor(private statisticsService: StatisticsService) {
        this.statisticResult$ = statisticsService.calculation;
    }
}


来源:https://stackoverflow.com/questions/44975816/angular-cross-service-communication

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!