Adding/Deleting Angular/RXJS 中对象数组的 Observable 对象?
Adding/Deleting an object to an Obervable of an object array in Angular/RXJS?
目标: 将对象添加到现有的 Observable 对象数组。对 DOM 进行反思是最后一步。
NewObject.ts
:
export class NewObject {
name: string;
title: string;
}
这是 example.component.ts
:
import { Observable } from 'rxjs';
import { Component, OnInit, Inject, EventEmitter } from '@angular/core';
import { NewObject } from 'objects';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
// Initializing the object array Observable from a service (step 1)
readonly objects$: Observable<NewObject[]> = this.objectSvc.getAllObjects("objects").pipe(
map(obj => obj.map(x => ({ name: x.name, title: alterString(x.title) }))),
shareReplay(1)
);
constructor(
private objectSvc: ObjectService
) { }
ngOnInit() {
somethingThatHappensToAdd = (response: any) => {
let data = JSON.parse(response);
data.forEach(x => {
let obj: NewObject = { name: x.name, title: alterString(x.title) }
// Here's where I'm trying to add the obj object into the already existing object array Observable
});
};
somethingThatHappensToDelete = (response: any) => {
let data = JSON.parse(response);
data.forEach(x => {
let obj: NewObject = { name: x.name, title: alterString(x.title) }
// Here's where I'm trying to delete the obj object from the already existing object array Observable
});
};
}
}
这是我的 example.component.html
:
<div *ngFor="let o of objects$ | async">
<p>{{ o.name }}</p>
<p>{{ o.title}}</p>
</div>
这是我的服务object.service.ts
:
import { Injectable } from '@angular/core';
import { Observable, throwError, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { ClientApi, ApiException, NewObject } from '../client-api.service';
@Injectable({
providedIn: 'root'
})
export class ObjectService {
constructor(
private clientApi: ClientApi
) { }
getAllObjects(name: string): Observable<NewObject[]> {
return this.clientApi.getAllObjects(name)
.pipe(
map((x) => x.result),
catchError(err => {
if (ApiException.isApiException(err)) {
if (err.status === 404) {
return of<NewObject[]>(undefined);
}
}
return throwError(err);
})
);
}
}
在 JSON
中格式化响应后,我希望能够将 obj
对象插入 objects$
Observable 并让它反映在 UI 中。
我被建议使用 BehaviorSubject
元素来实现这一点。谁能建议如何轻松完成此操作?
您可以创建一个 BehaviorSubject
来发出来自 somethingThatHappens()
的结果,并使用 combineLatest()
将结果与来自服务的结果合并。
objectsFromService$ = this.objectSvc.getAllObjects("objects").pipe(
map(obj => obj.map(x => ({ name: x.name, title: alterString(x.title) })))
);
resultsArray = []
resultsSubject = new BehaviorSubject(this.resultsArray);
results$ = this.resultsSubject.asObservable()
readonly objects$: Observable<NewObject[]> = combineLatest(
this.results$,
this.objectsFromService$
).pipe(
map(([results, objects]) => ([...results, ...objects])),
shareReplay(1)
)
somethingThatHappens = (response: any) => {
let data = JSON.parse(response);
data.forEach(x => {
let obj: NewObject = { name: x.name, title: alterString(x.title) }
this.resultsArray.push(obj)
});
this.resultsSubject.next(this.resultsArray)
};
我创建了一个工作 stackblitz 项目:https://stackblitz.com/edit/angular-jnngwh
希望这能给你一点线索。
我觉得哈伦回答的不错()
如果您只更新此可观察对象一次(在初始化时),您可以做一些简单的事情:
export class ExampleComponent implements OnInit {
let objects$: Observable<NewObject[]>;
constructor(
private objectSvc: ObjectService
) { }
private initializeObservable() {
return this.objectSvc.getAllObjects("objects").pipe(
map(obj => obj.map(x => ({ name: x.name, title: alterString(x.title) }))),
shareReplay(1)
);
}
private getObservableWithNewValues() {
const response = callService();
let array = [];
let data = JSON.parse(response);
data.forEach(x => {
let obj: NewObject = { name: x.name, title: alterString(x.title) }
array.push(obj);
});
// This creates an observable of the array
return of(array);
}
ngOnInit() {
const initialObservable = this.initializeObservable();
const anotherObservable = this.getObservableWithNewValues();
this.objects$ = concat(initialObservable, anotherObservable);
}
}
参考文献:
我找到了两种方法来解决这个问题。
解决方案一: https://stackblitz.com/edit/angular-rajvqq
constructor(private myService: MyService){
this.myService.getObjects().subscribe(x => this.somethingThatHappensToAdd(x));
}
resultsArray = []
resultsSubject = new BehaviorSubject(this.resultsArray);
readonly objects$: Observable<number[]> = combineLatest(
this.resultsSubject,
).pipe(
map(([results]) => ([...results])),
shareReplay(1)
)
somethingThatHappensToAdd( arrayOfValues ) {
arrayOfValues.forEach(x => {
this.resultsArray.push(x)
});
this.resultsSubject.next(this.resultsArray)
};
delete(o: any) {
// This is the same as just accessing this.resultsArray
let newArray: any[] = this.resultsSubject.getValue();
for (let i = newArray.length - 1; i >= 0; i--) {
if (newArray[i] == o) {
newArray.splice(i, 1);
}
}
this.resultsSubject.next(newArray);
}
方案二: https://stackblitz.com/edit/angular-gxfk16
deleteSubject = new Subject<any>();
addSubject = new Subject<any[]>();
objects$ = this.myService.getObjects().pipe(
switchMap(x => merge(
of(x),
this.deleteSubject.pipe(map(y => this.deleteAll(y, x))),
this.addSubject.pipe(map(y => { x.push(...y); return x; }))
)),
shareReplay(1)
);
constructor(private myService: MyService){ }
deleteAll(o: any, v: any[]) {
for (let i = v.length - 1; i >= 0; i--) {
if (v[i] == o) {
v.splice(i, 1);
}
}
return v;
}
目标: 将对象添加到现有的 Observable 对象数组。对 DOM 进行反思是最后一步。
NewObject.ts
:
export class NewObject {
name: string;
title: string;
}
这是 example.component.ts
:
import { Observable } from 'rxjs';
import { Component, OnInit, Inject, EventEmitter } from '@angular/core';
import { NewObject } from 'objects';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
// Initializing the object array Observable from a service (step 1)
readonly objects$: Observable<NewObject[]> = this.objectSvc.getAllObjects("objects").pipe(
map(obj => obj.map(x => ({ name: x.name, title: alterString(x.title) }))),
shareReplay(1)
);
constructor(
private objectSvc: ObjectService
) { }
ngOnInit() {
somethingThatHappensToAdd = (response: any) => {
let data = JSON.parse(response);
data.forEach(x => {
let obj: NewObject = { name: x.name, title: alterString(x.title) }
// Here's where I'm trying to add the obj object into the already existing object array Observable
});
};
somethingThatHappensToDelete = (response: any) => {
let data = JSON.parse(response);
data.forEach(x => {
let obj: NewObject = { name: x.name, title: alterString(x.title) }
// Here's where I'm trying to delete the obj object from the already existing object array Observable
});
};
}
}
这是我的 example.component.html
:
<div *ngFor="let o of objects$ | async">
<p>{{ o.name }}</p>
<p>{{ o.title}}</p>
</div>
这是我的服务object.service.ts
:
import { Injectable } from '@angular/core';
import { Observable, throwError, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { ClientApi, ApiException, NewObject } from '../client-api.service';
@Injectable({
providedIn: 'root'
})
export class ObjectService {
constructor(
private clientApi: ClientApi
) { }
getAllObjects(name: string): Observable<NewObject[]> {
return this.clientApi.getAllObjects(name)
.pipe(
map((x) => x.result),
catchError(err => {
if (ApiException.isApiException(err)) {
if (err.status === 404) {
return of<NewObject[]>(undefined);
}
}
return throwError(err);
})
);
}
}
在 JSON
中格式化响应后,我希望能够将 obj
对象插入 objects$
Observable 并让它反映在 UI 中。
我被建议使用 BehaviorSubject
元素来实现这一点。谁能建议如何轻松完成此操作?
您可以创建一个 BehaviorSubject
来发出来自 somethingThatHappens()
的结果,并使用 combineLatest()
将结果与来自服务的结果合并。
objectsFromService$ = this.objectSvc.getAllObjects("objects").pipe(
map(obj => obj.map(x => ({ name: x.name, title: alterString(x.title) })))
);
resultsArray = []
resultsSubject = new BehaviorSubject(this.resultsArray);
results$ = this.resultsSubject.asObservable()
readonly objects$: Observable<NewObject[]> = combineLatest(
this.results$,
this.objectsFromService$
).pipe(
map(([results, objects]) => ([...results, ...objects])),
shareReplay(1)
)
somethingThatHappens = (response: any) => {
let data = JSON.parse(response);
data.forEach(x => {
let obj: NewObject = { name: x.name, title: alterString(x.title) }
this.resultsArray.push(obj)
});
this.resultsSubject.next(this.resultsArray)
};
我创建了一个工作 stackblitz 项目:https://stackblitz.com/edit/angular-jnngwh
希望这能给你一点线索。
我觉得哈伦回答的不错(
如果您只更新此可观察对象一次(在初始化时),您可以做一些简单的事情:
export class ExampleComponent implements OnInit {
let objects$: Observable<NewObject[]>;
constructor(
private objectSvc: ObjectService
) { }
private initializeObservable() {
return this.objectSvc.getAllObjects("objects").pipe(
map(obj => obj.map(x => ({ name: x.name, title: alterString(x.title) }))),
shareReplay(1)
);
}
private getObservableWithNewValues() {
const response = callService();
let array = [];
let data = JSON.parse(response);
data.forEach(x => {
let obj: NewObject = { name: x.name, title: alterString(x.title) }
array.push(obj);
});
// This creates an observable of the array
return of(array);
}
ngOnInit() {
const initialObservable = this.initializeObservable();
const anotherObservable = this.getObservableWithNewValues();
this.objects$ = concat(initialObservable, anotherObservable);
}
}
参考文献:
我找到了两种方法来解决这个问题。
解决方案一: https://stackblitz.com/edit/angular-rajvqq
constructor(private myService: MyService){
this.myService.getObjects().subscribe(x => this.somethingThatHappensToAdd(x));
}
resultsArray = []
resultsSubject = new BehaviorSubject(this.resultsArray);
readonly objects$: Observable<number[]> = combineLatest(
this.resultsSubject,
).pipe(
map(([results]) => ([...results])),
shareReplay(1)
)
somethingThatHappensToAdd( arrayOfValues ) {
arrayOfValues.forEach(x => {
this.resultsArray.push(x)
});
this.resultsSubject.next(this.resultsArray)
};
delete(o: any) {
// This is the same as just accessing this.resultsArray
let newArray: any[] = this.resultsSubject.getValue();
for (let i = newArray.length - 1; i >= 0; i--) {
if (newArray[i] == o) {
newArray.splice(i, 1);
}
}
this.resultsSubject.next(newArray);
}
方案二: https://stackblitz.com/edit/angular-gxfk16
deleteSubject = new Subject<any>();
addSubject = new Subject<any[]>();
objects$ = this.myService.getObjects().pipe(
switchMap(x => merge(
of(x),
this.deleteSubject.pipe(map(y => this.deleteAll(y, x))),
this.addSubject.pipe(map(y => { x.push(...y); return x; }))
)),
shareReplay(1)
);
constructor(private myService: MyService){ }
deleteAll(o: any, v: any[]) {
for (let i = v.length - 1; i >= 0; i--) {
if (v[i] == o) {
v.splice(i, 1);
}
}
return v;
}