我有从服务中获得的可观察数据:
public events$: Observable<IEvent[]> = of([]);
public filteredEvents$: BehaviorSubject<IEvent[]> = new BehaviorSubject([]);
this.events$ = this.eventsService.get();
当我调用函数时:
public checkAll(): void {
this.events$
.pipe(
map((events: IEvent[]) =>
events.filter(
(event: IEvent) => (event.checked_export = !event.checked_export)
)
)
)
.subscribe((events) => this.filteredEvents$.next(events));
}
它再次调用this.events$ = this.eventsService.get();
并向服务器发出请求。
模板是:
<ng-container *ngIf="filteredEvents$ | async; else nodata">
我知道每个.subscribe((events)
都会再次调用观察者,但是如何修改可观察数组this.events$
并返回到filteredEvents$
?
为什么我在代码中遇到此错误:
RangeError:超出了最大调用堆栈大小
组件方法是:
public delete(event: IEvent): void {
this.confirm
.open({})
.pipe(
filter(Boolean),
concatMap(() => this.eventService.delete(event))
)
.subscribe((response) => this.eventService.next(response));
}
服务是:
public next(events: IEvent[]): void {
this.events$.next(events);
}
public events(): Observable<any> {
return this.events$.asObservable();
}
public delete(event: IEvent): Observable<any> {
return this.eventsService
.delete(event)
.pipe(
concatMap(() =>
this.events$.pipe(
map((events: IEvent[]) =>
events.filter((e) => e.idEvent !== event.idEvent)
)
)
)
);
}
答案 0 :(得分:0)
您的概念是错误的。
interface IEvent {
checked_export: boolean;
}
export class EventService {
private events$: BehaviorSubject<IEvent[]> = new BehaviorSubject<IEvent[]>([]);
public next(events: IEvent[]): void {
this.events$.next(events);
}
public checkAll(): Observable<IEvent[]> {
return this.events$.pipe(
map((events: IEvent[]) => {
return events.filter((event: IEvent) => event.checked_export);
}),
);
}
}
// subscribe with async pipe: <ng-container *ngIf="data$ | async; else nodata">
// subscribe with async pipe: <ng-container *ngIf="isEmpty$ | async">
export class Component {
nodata: any;
constructor(private service: EventService) {
}
get data$(): Observable<IEvent[]> {
return this.service.checkAll();
}
get isEmpty$(): Observable<boolean> {
return this.data$.pipe(map((data) => data.length === 0));
}
}
更新评论
@Injectable() // config into module's provider!!!
export class DataFromServerResolve implements Resolve<IEvent[]> {
constructor(private http: HttpClient) {
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<IEvent[]> {
return this.http.get<IEvent[]>('url'); // then navigate here this resolving all time. Or use Ngrx Store / service to cache
}
}
// to routing
const routes: Routes = [{ path: '', component: MyComponent, resolve: { myData: DataFromServerResolve } }];
interface IEvent {
checked_export: boolean;
}
// subscribe with async pipe: <ng-container *ngIf="checkAll() | async; else nodata">
// subscribe with async pipe: <ng-container *ngIf="isEmpty$ | async">
@Component({
selector: '...',
templateUrl: '...',
styleUrls: ['...'],
})
export class MyComponent implements OnInit {
data: BehaviorSubject<IEvent[]>;
constructor(private route: ActivatedRoute) {
}
ngOnInit(): void {
// resolve: { myData: DataFromServerResolve } -> snapshot.data.myData (It will normal: IEvent[] type)
this.data = new BehaviorSubject<IEvent[]>(this.route.snapshot.data.myData);
}
// There is not ngDestroy to unsubscribe because "| async" will unsubscribe.
// If we use .subscribe(...) and save to variable then have to!
get isEmpty$(): Observable<boolean> {
return this.checkAll().pipe(map((data) => data.length === 0));
}
public next(newData: IEvent[]): void {
this.data.next(newData); // it will trigger all subscribers again
}
// or put service and make input parameter and "this.data" replace by parameter name
public checkAll(): Observable<IEvent[]> {
return this.data.pipe(
map((events: IEvent[]) => {
return events.filter((event: IEvent) => event.checked_export);
}),
);
}
}