Angular2如何更新可观察集合中的项目

Angular2如何更新可观察集合中的项目,angular,rxjs,observable,Angular,Rxjs,Observable,简而言之,更新: 我正在寻找类似于这样做的等效方法,但对于可观察数组而不是规则数组: var i=this.customers.findIndex(customer=>customer.\u id==id); ~i&&this.customers[i]=newObject。 我在屏幕上有两个组件。左边是一个列表组件,右边是一个显示组件(想象一下,它是一个PDF,只是呈现数据的最新版本) 单击列表中的项目时,将在右侧的零部件中显示该选定项目的数据 列表是一个可观察的数组: 项目$:可观察;

简而言之,更新:

我正在寻找类似于这样做的等效方法,但对于可观察数组而不是规则数组:

var i=this.customers.findIndex(customer=>customer.\u id==id);
~i&&this.customers[i]=newObject。

我在屏幕上有两个组件。左边是一个列表组件,右边是一个显示组件(想象一下,它是一个PDF,只是呈现数据的最新版本)

单击列表中的项目时,将在右侧的零部件中显示该选定项目的数据

列表是一个可观察的数组:

项目$:可观察;
列表中的每个项目都有一个子组件。可以单击单个项目上的图标,从而更改该子项的数据。子级有一个事件发射器,用于通知父级数据已更改:

@Output()proposalDataChanged:EventEmitter=新的EventEmitter();
父项绑定到它:


我遇到的问题是,在handleDataChanged方法中,我希望在Observable中搜索已更改的项,并将其替换为发射器返回的新有效负载。我不想调用服务器刷新整个列表

我需要这样做,以便右侧的组件反映新数据

我可以找到如下项目:

处理数据已更改(数据:提案){
this.items$.subscribe((items:Proposal[])=>item=items.find(p=>p.id
==data.id));
}
但是,我们无法找出如何更新可观察项中的项,而不仅仅是查找已更改的项

我知道我可以通过导航到其他地方,然后再次返回以强制刷新来“欺骗”组件,但这也会影响API(并重新加载页面)

url如下所示:

/pages/propositions/manage/-XHzOJY/document
url中的slug是当前选定项的id(在右侧的组件中呈现)

所以我不能在这里使用参数更改检测,因为它不会更改。用户正在对已选择的对象进行更改,该对象是可观察数组中的许多对象之一

更新

以下是父组件的完整代码:

从'@angular/core'导入{Component,OnInit};
从'@angular/Router'导入{Router};
从'rxjs/Rx'导入{可观察,主题};
从“../Proposal”导入{Proposal};
从“../proposal.service”导入{ProposalService};
从“../../services/search service”导入{SearchService};
@组成部分({
选择器:“fb建议书列表”,
templateUrl:'./提案列表.component.html',
样式URL:['./建议列表.component.css']
})
导出类ProposalListComponent实现OnInit{
总数$:可观察到的;
项目$:可观察;
术语:string=“”;
当前页面:编号=1;
私有页面流=新主题();
建造师(
私人搜索服务:搜索服务,
private\u proposalService:proposalService,
专用路由器(路由器){
}
恩戈尼尼特(){
这是setupsearch();
//设定时器=可观测定时器(0,60000);
//timer.subscribe(()=>this.goToPage(this.currentPage));
}
设置搜索(){
const searchSource=this.\u searchService.searchTermStream
.map(searchTerm=>{
this.term=searchTerm;
返回{search:searchTerm,第1页}
});
const pageSource=this.pageStream.map(页码=>{
this.currentPage=页码;
返回{search:this.term,page:pageNumber}
});
常量源=页面源
.merge(搜索源)
.startWith({search:this.term,page:this.currentPage})
.switchMap((参数:{search:string,page:number})=>{
返回此。\u ProposalsService.getProposalsPaged(params.search,params.page)
})
.share();
this.total$=source.pull('meta').pull('total_items');
this.items$=source.pull('items');
}
goToPage(页码:编号){
this.pageStream.next(第页)
}  
handleDataChanged(id:字符串){
this.goToPage(this.currentPage);
}
}

我认为您不完全理解可观测数据是如何工作的。你们在这里所说的“可观察的集合”并不是你们所认为的,就像“可观察元素的集合”一样

实际上,它是一个发出的集合流。因此,当你拥有可观察的
时,它不是某个观察者正在观察的集合,而是一个发出的
模型[]
集合流。从这个意义上讲,您不能更新发出的值(显然,因为它已经发出),但您希望的是,observable发出另一个已更新的
模型
集合

在你尝试这一点之前,你必须知道,你不能从你自己没有创造出来的可见光中发射出一些东西。您需要的是一个主体,一个既可观察又可观察的对象(它继承自观察者和可观察界面)

那么,让我们构建这样的东西:

subject: Subject<Proposal[]> = new Subject();
_proposals: Proposal[] = [];

get proposals() {
  return this.subject.asObservable();
}

这可能看起来太多了,我建议大家多读一些关于可观测数据是如何工作的,以便将来有更多的问题。干杯。

您可以通过以下方式完成

  • 使用
    | async
    管道
  • 创建一个私有变量,并在subscribe块中添加将反映该变量的值

你说得对,来自Silverlight/WPF世界,可观测到的东西对我来说完全是另一回事。谢谢你的详细解释。问题是我已经有了一个主题,因为列表已经分页了。我将为父组件添加完整代码。您只需将
\u items$
转换为
Subject
,添加一个新的
this.\u items
集合并添加一个getter
items$
,就像我的示例中那样。当你想更新项目时,只需按照我在回答中的最后一个方法中向你展示的操作即可。谢谢,我
http.get("...").map(response => response.json().subscribe(data => {
  this._proposals= <Proposal[]>data; // save your data
  this.subject.next(this._proposals); // emit your data
});
updateProposals() {
  this._proposals = this._proposals.filter(...); // or whatever
  this.subject.next(Object.assign({}, this._proposals)); // emit completely new value
}