Update, in short:
I am looking for the equivalent of doing something similar, but for an observable, not a regular array:
var i = this.customers.findIndex(customer => customer._id === id); ~i && this.customers[i] = newObject.
I have 2 components on the screen. The list component on the left and the display component on the right (imagine this is a PDF file that simply displays 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 list item has a child component. You can click the icon on one item that changes the data of this child. The child has an event emitter to inform parents that the data has changed:
@Output() proposalDataChanged: EventEmitter<string> = new EventEmitter();
The parent becomes attached to him:
<fb-proposal-list-item [proposal]="proposal" (proposalDataChanged)="handleDataChanged(p)"> </fb-proposal-list-item>
The problem is that in the handleDataChanged method I want to do an Observable search for the changed item and replace it with the new payload returned by the emitter. I do not want to call the server to update the entire list.
I need to do this so that the component on the right reflects the new data.
I can find the element as follows:
handleDataChanged(data: Proposal){ this.items$.subscribe((items: Proposal[]) => item = items.find(p => p.id == data.id)); }
but can't figure out how to update an item in Observable, and not just find the one that has changed.
I know that I can "trick" the component by moving to another place and then return again to make it update, but it also gets into the API (and reloads the page).
The url is as follows:
/pages/proposals/manage/-XHzOJY/document
This pool in the URL is the identifier of the currently selected item (which is displayed in the component on the right).
So I can’t use params change detection here because it does not change. The user causes a change to the already selected object, which is one of many inside the observed array.
UPDATE
Here is the complete 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); } }