Reputation: 155
I'm struggling to understand how to tie RxJS into a RESTful API.
I have 2 components side by side, both displaying the same list of models. The left hand one can create, update and delete these models inline. The right hand one should update accordingly. They talk via an API Service which talks to the API and holds the latest list of models in an Observable.
The Question:
How can I update the models in the service such that these are pushed out to the components? It feels like I have use the wrong architecture but it seems like a pretty standard use case talking to a RESTful API.
Note: I don't want to re-query the API every time something is added or updated. I just want to edit the list locally.
Here are the components:
class EditComponent implements ngOnInit {
private models: Model[];
constructor(private api: ApiService)
ngOnInit() {
this.api.getAll().subscribe(models => this.models = models);
}
create(name: string) {
this.api.create(name);
}
update(model: Model) {
this.api.update(model);
}
delete(model: Model {
this.api.delete(model);
}
}
class ListComponent implements ngOnInit {
private models: Models[];
constructor(private api: ApiService)
ngOnInit() {
this.api.getAll().subscribe(models => this.models = models);
}
}
These talk to the following API Service:
class ApiService {
private models: Observable<Model[]>;
getAll(): Observable<Model[]> {
if (!this.models) {
this.models = this.http.get(URL)
.map((res: Response) => res.json())
.publishReplay(1)
.refCount()
}
return this.models;
}
create(name: string) {
const Observable<Model> = this.http.post(URL, {name: name});
// What should be done here with the new model
}
update(model: Model) {
// And here
}
delete(model: Model) {
// And here
}
}
Upvotes: 2
Views: 1832
Reputation: 7123
You should keep a local value of the data sent/received to your backend and update it accordingly. Then publish the value to observers. A simple solution is to use a BehaviorSubject:
class ApiService {
public static URL = 'test.com/api/resource';
private models = new Array<Model>();
private cache = new BehaviorSubject<Array<Model>>(this.models);
constructor(private http: Http) { }
getAll(): Observable<Model[]> {
if (this.models.length === 0) {
this.http.get(ApiService.URL).map(res => res.json())
.publishReplay(1)
.refCount().subscribe(value => {
// update the local value
this.models = value;
// publish update to observers
this.cache.next(this.models);
}, this._handleError);
}
return this.cache;
}
create(name: string) {
this.http.post(ApiService.URL, { name: name }).map(res => res.json()).subscribe(data => {
this.models.push(data);
this.cache.next(this.models);
}, this._handleError);
}
update(model: Model) {
this.http.patch(ApiService.URL, {data: model}).map(res => res.json()).subscribe(data => {
// update the value in models
const idxToUpdate = this.models.findIndex(value => value.id === model.id);
this.models[idxToUpdate] = model;
this.cache.next(this.models);
}, this._handleError);
}
delete(model: Model) {
this.http.delete(ApiService.URL + '/' + model.id).map(res => res.json()).subscribe(data => {
// delete value from models
const idxToUpdate = this.models.findIndex(value => value.id === model.id);
this.models.splice(idxToUpdate, 1);
this.cache.next(this.models);
}, this._handleError);
}
private _handleError(error: any) {
this.cache.error(error);
}
}
Upvotes: 3