Angular2如何更新可观察集合中的项目 [英] Angular2 how to update an item inside an observable collection

查看:48
本文介绍了Angular2如何更新可观察集合中的项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简而言之:

我正在寻找等效的方法,但是需要一个Observable而不是常规数组:

I am looking for the equivalent of doing something like this but for an Observable rather than a regular array:

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


我在屏幕上有2个组件.左侧的列表组件和右侧的显示组件(假设它是仅呈现最新数据版本"的PDF)


I have 2 components on the screen. A list component on the left and a display component on the right (imagine it to be a PDF that is just rendering the latest 'version' of data)

单击列表中的项目时,它将在右侧的组件中显示所选项目的数据.

When you click an item in the list, it displays the data for that selected item in the component on the right.

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

The list is an observable array:

items$: Observable<Proposal[]>;

列表中的每个项目都有一个子组件.可以单击单个项目上的图标,这将更改该子项的数据.子级有一个事件发射器来告诉父级数据已更改:

Each item in the list has a child component. It is possible to click an icon on a single item, which changes the data of that child. The child has an event emitter to tell the parent the data has changed:

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

父级绑定到它:

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

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

The problem I have is that in the handleDataChanged method I want to search the Observable for the item that has changed and replace it with the new payload returned from the emitter. I do not want to call the server to refresh the entire list.

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

I need to do this so that the component on the right reflects the new data.

我能够找到这样的物品:

I am able to find the item like this:

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

但是无法找出如何更新Observable中的项目,而不仅仅是找到已更改的项目.

but cannot figure out how to update the item in the Observable, rather than just finding the one that changed.

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

I know I can 'trick' the component by navigating elsewhere and then back again to force it to refresh, but that also hits the API (and reloads the page as well).

网址看起来像这样:

/pages/proposals/manage/-XHzOJY/document

URL中的该段是当前所选项目的ID(在右侧的组件中呈现).

That slug in the url is the id of the currently selected item (which is rendered in the component on the right).

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

So I cannot use params change detection here, because it doesn't change. The user is causing a change to the already selected object, which is one of many inside the observable array.

更新

这是父组件的完整代码:

Here is the full code for the parent component:

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);  
  }
}

推荐答案

我认为您并不完全了解Observable的工作原理.您在这里所说的可观察的集合"并不是您可能认为的那样,就像在可观察的元素的集合"中一样.

I don't think you fully understand how Observables work. What you call here "observable collection" is not what you might think it is, as in "collection of observable elements".

实际上是发出的集合流.因此,当您拥有Observable<Model[]>时,它不是某个观察者正在观察的集合,而是实际上是发出的Model[]集合的流.从这种意义上讲,您不能更新发射的值(显然,因为它已经被发射了),但是可以观察到的是发射另一个更新的 集合的Model.

What it is, actually, is a stream of emitted collections. So when you have Observable<Model[]>, it's not a collection that's being observed by some observer, it's actually a stream of emitted Model[] collections. In that sense, you can't update the emitted value (obviously, as it already has been emitted), but what you want is it for observable to emit another, updated collection of Model.

在尝试该操作之前,您必须知道您无法从尚未创建的可观察对象中发出某些东西.您需要的是一个Subject,既是Observable也是Observer的对象(它同时继承于Observer和Observable接口).

Before you try that, you'll have to know that you can't emit something from observable that you haven't created yourself. What you need is a Subject, an object that is both Observable and Observer (it inherits from both Observer and Observable interfaces).

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

So, let's construct something like that:

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

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

假设您从一些API调用中获得建议:

Let's say you get your proposals from some API call:

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
}

这似乎很多,我建议您阅读更多有关Observables如何工作的信息,以备将来可能遇到的问题.干杯.

This may seem like a lot and I would recommend reading more on how Observables work for the sake of future issues that you might have. Cheers.

这篇关于Angular2如何更新可观察集合中的项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆