【问题标题】:Angular2 how to update an item inside an observable collectionAngular2如何更新可观察集合中的项目
【发布时间】:2017-03-14 23:10:45
【问题描述】:

简而言之,更新:

我正在寻找类似这样的操作,但要使用 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(在右侧的组件中呈现)。

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

更新

这是父组件的完整代码:

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

【问题讨论】:

    标签: angular rxjs observable


    【解决方案1】:

    我认为您并不完全了解 Observables 的工作原理。您在此处所说的“可观察集合”并不是您想象的那样,如“可观察元素的集合”。

    实际上,它是一个发出集合的流。因此,当您拥有Observable&lt;Model[]&gt; 时,它不是某个观察者正在观察的集合,它实际上是发出的Model[] 集合流。从这个意义上说,您无法更新发出的值(显然,因为它已经发出),但您想要的是 observable 发出 另一个更新的 Model 集合。

    在你尝试之前,你必须知道你不能从 observable 中发出不是你自己创建的东西。你需要的是一个 Subject,一个既是 Observable 又是 Observer 的对象(它继承自 Observer 和 Observable 接口)。

    那么,让我们构建类似的东西:

    subject: Subject<Proposal[]> = new Subject();
    _proposals: Proposal[] = [];
    
    get proposals() {
      return this.subject.asObservable();
    }
    

    假设您从某个 API 调用中获得建议:

    this.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 如何工作的内容,以便您将来可能遇到问题。干杯。

    【讨论】:

    • 你说得对,来自 Silverlight/WPF 世界,observables 对我来说完全是另外一回事。感谢您的详细解释。
    • 问题是我已经有一个主题,因为列表是分页的。我将添加父组件的完整代码。
    • 好吧,您可以将_items$ 转换为Subject,添加一个新的this._items 集合并添加一个getter items$,就像在我的示例中一样。当您想更新项目时,只需按照我在答案中的最后一种方法中向您展示的操作即可。
    • 谢谢,我现在明白了。 :)
    【解决方案2】:

    你可以通过以下方式做到这一点

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

    【讨论】:

    • 感谢您的帮助,但我需要查看代码才能了解如何解决此问题。对不起,我比英语更懂代码。无论如何,另一个答案现在帮助解决了它。但再次感谢。
    • @Aniruddha Das,如果您希望它成为答案,请提供更多信息,否则,将其作为评论发布。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-04
    • 2021-05-27
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多