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

时间:2017-03-14 23:10:46

标签: angular rxjs observable

更新,简而言之:

我正在寻找相当于做这样的事情但是对于Observable而不是常规数组:

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

屏幕上有2个组件。左侧的列表组件和右侧的显示组件(假设它是一个只呈现最新'版本'数据的PDF)

单击列表中的项目时,它会在右侧的组件中显示该选定项目的数据。

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

items$: Observable<Proposal[]>;

列表中的每个项目都有一个子组件。可以单击单个项目上的图标,这会更改该子项的数据。孩子有一个事件发射器告诉父母数据已经改变:

@Output() proposalDataChanged: EventEmitter<string> = new EventEmitter();

父母与之绑定:

 <fb-proposal-list-item
  [proposal]="proposal" (proposalDataChanged)="handleDataChanged(p)">
 </fb-proposal-list-item>

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

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

我能找到这样的项目:

handleDataChanged(data: Proposal){
  this.items$.subscribe((items: Proposal[]) => item = items.find(p => p.id 
  == data.id));
}

但无法弄清楚如何更新Observable中的项目,而不仅仅是找到更改后的项目。

我知道我可以通过在别处导航然后再返回以强制刷新来“欺骗”组件,但这也会触及API(并重新加载页面)。

网址如下:

/pages/proposals/manage/-XHzOJY/document

url中的slug是当前所选项目的id(在右侧组件中呈现)。

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

更新

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

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Observable, Subject } from 'rxjs/Rx';

import { Proposal } from '../proposal';
import { ProposalService } from '../proposal.service';
import { SearchService } from '../../services/search-service';

@Component({
  selector: 'fb-proposal-list',
  templateUrl: './proposal-list.component.html',
  styleUrls: ['./proposal-list.component.css']
})
export class ProposalListComponent implements OnInit {
  total$: Observable<number>;
  items$: Observable<Proposal[]>;

  term: string = "";
  currentPage: number = 1;
  private pageStream = new Subject<number>();  

  constructor(
    private _searchService: SearchService,
    private _proposalService: ProposalService,
    private _router: Router) {
  }

  ngOnInit() {
    this.setupSearching();
    // let timer = Observable.timer(0, 60000);
    // timer.subscribe(() => this.goToPage(this.currentPage));
  }

  setupSearching(){
    const searchSource = this._searchService.searchTermStream
      .map(searchTerm => {
        this.term = searchTerm;
        return {search: searchTerm, page: 1}
      });

    const pageSource = this.pageStream.map(pageNumber => {
      this.currentPage = pageNumber;
      return {search: this.term, page: pageNumber}
    });

    const source = pageSource
      .merge(searchSource)
      .startWith({search: this.term, page: this.currentPage})
      .switchMap((params: {search: string, page: number}) => {
        return this._proposalService.getProposalsPaged(params.search, params.page)
      })
      .share();

    this.total$ = source.pluck('meta').pluck('total_items');
    this.items$ = source.pluck('items'); 
  }

  goToPage(page: number) {
    this.pageStream.next(page)
  }  

  handleDataChanged(id: string){
    this.goToPage(this.currentPage);  
  }
}

2 个答案:

答案 0 :(得分:16)

我不认为你完全理解Observables是如何工作的。你在这里叫什么&#34;可观察的收集&#34;不是你可能认为的那样,就像在&#34;可观察元素的集合中那样#34;。

实际上,它是一组发射的集合。因此,当您拥有Observable<Model[]>时,它不是某个观察者正在观察的集合,它实际上是一组发出的Model[]集合。从这个意义上说,你不能更新发射的值(显然,因为它已经被发射),但你想要的是可观察的发射另一个更新的 {{1 }}

在你尝试之前,你必须知道你不能从你自己没有创造的可观察物中发出一些东西。你需要的是一个Subject,一个Observable和Observer的对象(它继承了Observer和Observable接口)。

所以,让我们构建类似的东西:

Model

我们假设您从某个API调用中获取了您的提案:

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

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

现在,您想要更新数据:

http.get("...").map(response => response.json().subscribe(data => {
  this._proposals= <Proposal[]>data; // save your data
  this.subject.next(this._proposals); // emit your data
});

这可能看起来很多,我建议您阅读更多有关Observables如何为您未来可能遇到的问题而工作的内容。欢呼声。

答案 1 :(得分:0)

您可以通过以下方式实现

  • 使用| async pipe
  • 创建一个私有变量,并在您的订阅块中添加值以反映那里的值。