Angular 如何同步多个角度可观测数据服务

Angular 如何同步多个角度可观测数据服务,angular,rxjs,observable,Angular,Rxjs,Observable,假设我使用服务器端端点支持的可观察数据服务构建Angular应用程序: @Injectable() 将类导出到服务{ 待办事项:可观察 private _todos:行为主体; 构造函数(专用http:http){ 这。_todos=新行为主体([]); this.todos=this.\u todos.asObservable(); } loadData(){ this.http.get(dataUrl).subscribe(数据=>this.\u todos.next(数据)); } }

假设我使用服务器端端点支持的可观察数据服务构建Angular应用程序:

@Injectable()
将类导出到服务{
待办事项:可观察
private _todos:行为主体;
构造函数(专用http:http){
这。_todos=新行为主体([]);
this.todos=this.\u todos.asObservable();
}
loadData(){
this.http.get(dataUrl).subscribe(数据=>this.\u todos.next(数据));
}
}
现在假设我的数据引用了其他模型,并由其他服务公开(某种形式的多对多关系):

接口待办事项{
标题:字符串;
状态:StatusEnum;
所需资源:资源[];
}
接口资源{
名称:字符串;
待办事项:待办事项[];
}
@可注射()
导出类资源服务{
资源:可观察
私有资源:行为主体;
...
}
现在,假设我向“链接”todo和资源的任何一个服务添加了一个方法,该服务将能够向下推送主题的更新状态,但另一个服务将不知道该更改。例如:

将类导出到服务{
...
addResourceRequirement(todo:todo,资源:资源){
this.http.post(`${url}/${todo.id}/`,{addResource:resource.id})
.subscribe(()=>this.loadData());
}
}
将导致任何“todos”观察器刷新,但任何“资源”观察器仍将显示旧状态

您将使用什么设计/模式/体系结构来同步这两个服务



(我知道有一些架构可以从整体上避免这一困难,特别是基于流量的解决方案——NgRX等……但我对一个专门针对可观测数据服务模式的解决方案感兴趣)

您的模式几乎完成了,您只需避免在启动时创建可观测数据,请记住,
BehaviorSubject
扩展了
Observable
,因此您可以按原样使用它,如果您想让它易于使用,可以使用隐式getter

@Injectable()
export class TodoService {
  private _todos: BehaviorSubject<Todo[]>;

  constructor() {
    this._todos = new BehaviorSubject<Todo[]>([]);
  }

  public get todos(): Observable<Todo[]>{
    return this._todos;
  }
}
这样,如果您的
TodoService
发出一个新数组,
ResourcesService
将发出一个状态为done的新todo数组,而不需要任何其他操作

另一种方法 如果您的资源来自另一个端点(意味着在更新数据后需要另一个请求来获取它们),则最好使用重载模式:

@Injectable()
export class DataReloaderService{

  public readonly reloader: BehaviorSubject<void> = new BehaviorSubject<void>(null);

  public reload():void{
    this.reloader.next(null);
  }
}
@Injectable()
导出类DataReloaderService{
public readonly重载器:BehaviorSubject=new BehaviorSubject(null);
公共重新加载():void{
this.reloader.next(null);
}
}
然后,无论何时创建数据服务,您只需将其与可观察的重新加载程序合并:

@Injectable()
export class ResourceService {

  private _resources: Observable<Resource[]>;

  constructor(private reloaderService: DataReloaderService, private http: HttpClient){
    this._resources = this.reloaderService.reloader.mergeMap(() => this.http.get(...));
  }

}
@Injectable()
导出类资源服务{
私有资源:可观察;
构造函数(私有重载服务:DataReloaderService,私有http:HttpClient){
this.\u resources=this.reloaderService.reloader.mergeMap(()=>this.http.get(…);
}
}
最后,在您的服务中进行修改:

export class TodoService {

  private _todos: BehaviorSubject<Todo[]>;

  constructor(private reloaderService: DataReloaderService, private http: HttpClient) {
    this._todos = this.reloaderService.reloader.mergeMap(() => this.http.get(dataUrl));
  }

  public get todos(): Observable<Todo[]>{
    return this._todos;
  }

  addResourceRequirement(todo: ToDo, resource: Resource) {
    this.http.post(`${url}/${todo.id}/`, {addResource: resource.id})
      .subscribe(() => this.reloader.reload());
  }
}
将类导出到服务{
private _todos:行为主体;
构造函数(私有重载服务:DataReloaderService,私有http:HttpClient){
this.u todos=this.reloaderService.reloader.mergeMap(()=>this.http.get(dataUrl));
}
public get todos():可观察{
把这个还给我;
}
addResourceRequirement(todo:todo,资源:资源){
this.http.post(`${url}/${todo.id}/`,{addResource:resource.id})
.subscribe(()=>this.reloader.reload());
}
}

注意:您不应订阅服务,Observable的目的是构建冷链,您只需在显示部分订阅,第二种模式确保您的所有Observable都链接到中心重载器(您还可以创建多个重载器,例如,每个模型族一个),订阅使您失去了这一点,从而导致只编辑数据的奇怪方式。如果一切都依赖于您的api,那么您的可观察对象应该只使用此api,在您编辑某些内容时调用重新加载程序,以确保所有链接的数据也得到更新。

我不确定我是否理解这个问题

但是让我们假设你有两个主题,都有资源列表和待办事项

import {combineLatest} from "rxjs/observable/combineLatest";

mergeResourcesAndTodos() {
    return combineLatest(
        this.todoService.todos
        this.resourceService.resources
      ).map((data: any[]) => {
       const todos=data[0]
       const resources=data[1]
       //and here you can map anyway you want like a list of todos that have a list of resources or the other way around, here I will do an example with a list of todos with resources.
         return todos.map(todo=>{
              const resource= resources.find(resource=>resource.id===todo.resourceId)
              todo.resource=resource;
              return todo
          })
     })
  }

看看这些资源和@EduardoVargas-有趣的链接,也许可以设计一些基于这里列出的用例的模式。想试着回答吗?老实说,我试着多次重读这个问题,以正确理解它,这是我第一次看不出我的答案有什么问题,这不是我的第一个答案,对我来说,它给出了问题的解决方案。否决这个问题一点也不幼稚,我这么做是因为我读了4遍都不理解你的问题,这是对一个没有足够细节的问题的描述,不是吗?投票不是为了惩罚,而是为了表明一个问题是否容易理解,答案也是一样,所以你应该否决我。我用一个例子补充了进一步的解释,也许(希望?)现在更清楚了。(请注意,为了保持问题和答案的同步,我建议避免添加新数据-
todosDone
不是问题的一部分)@Amit如果我错了,请纠正我,但您的问题是,如果todo观测值发出新值,您的资源观测值将不会更新?如果是这样的话,您能否添加有关如何创建资源可观察对象的详细信息?我认为问题就在这里。@Supamiu-与
ToDoService
完全相同。简单成员、绑定主题和可观察对象的简单构造函数以及某种形式的加载数据(
loadData()
method)。关键是服务器负责数据和引用的完整性-客户端始终可以查询最新状态,但不应该对数据应用任何业务逻辑。@Amit编辑了我的答案以添加更多细节和其他方法。因此
import {combineLatest} from "rxjs/observable/combineLatest";

mergeResourcesAndTodos() {
    return combineLatest(
        this.todoService.todos
        this.resourceService.resources
      ).map((data: any[]) => {
       const todos=data[0]
       const resources=data[1]
       //and here you can map anyway you want like a list of todos that have a list of resources or the other way around, here I will do an example with a list of todos with resources.
         return todos.map(todo=>{
              const resource= resources.find(resource=>resource.id===todo.resourceId)
              todo.resource=resource;
              return todo
          })
     })
  }