Can someone break down to me what loadNotes is doing and why updateAllNotes() is called in ngOnInit? I have no clue why ReplaySubject is being returned or what ".pipe(switch" is even doing.
export class StudyComponent implements OnInit {
public notes$: Observable<NoteModel[]>;
constructor(private state: StateService,
private noteUpdateService: NoteUpdateService,
private studentNotesService: StudentNotesService,
@Inject(Spinner) private spinner: SpinnerService
) {
const {noteId} = this.state.params;
this.notes$ = this.loadNotes(noteId);
}
public ngOnInit(): void {
this.noteUpdateService.updateAllNotes();
}
private loadNotes(noteId: number): Observable<NoteModel[]> {
return this.noteUpdateService.noteUpdate$.pipe(switchMap(() => this.getNotes(noteId)));
}
private getNotes(noteId: number): Observable<NoteModel[]> {
this.spinner.show();
return this.studentNotesService.getStudentNotes(noteId).pipe(
finalize(() => {
this.spinner.hide();
})
);
}
}
export class NoteUpdateService {
private localNoteUpdate$ = new ReplaySubject<void>(1);
public get noteUpdate$(): Observable<void> {
return this.localNoteUpdate$.asObservable();
}
public updateAllNotes$(): <void> {
this.localNoteUpdate.next();
}
}
export class StudentNotesService {
constructor(private studentNotesGridService: StudentNotesGridService) {}
public getStudentNotes(noteId: number): Observable<NoteModel[]> {
return this.studentNotesGridService.getNotes(noteId);
}
}
I understand that ReplaySubject emits it's previous values when something new subscribes to it but nothing is being subscribed to it so what is the point in it being returned? and what is the point in the "pipe(switch"?
CodePudding user response:
switchMap takes the emission from one observable and uses the value to subscribe to another observable. In this case the note update service is pretty pointless as it doesn't emit a value, it is just used to trigger the next call. You could simplify this component with a subject.
export class StudyComponent {
noteId$ = new Subject<number>();
notes$ = noteId$.pipe(
tap(() => { this.spinner.show(); }),
switchMap(noteId => this.studentNotesService.getStudentNotes(noteId)),
tap(() => { this.spinner.hide(); })
);
constructor(private state: StateService,
private studentNotesService: StudentNotesService,
@Inject(Spinner) private spinner: SpinnerService
) {
const {noteId} = this.state.params;
this.getNotes(noteId);
}
private getNotes(noteId: number) {
this.noteId$(noteId);
}
}
Seeing that getNotes is private so it can't be called from anywhere else you even go so far as
export class StudyComponent implements OnInit {
notes$ = this.studentNotesService.getStudentNotes(this.state.params.noteId).pipe
tap(() => { this.spinner.hide(); })
);
constructor(private state: StateService,
private studentNotesService: StudentNotesService,
@Inject(Spinner) private spinner: SpinnerService
) {}
ngOnInit(): void {
this.spinner.show();
}
}
CodePudding user response:
loadNotes(noteId: number) function returns an observable of an array of NoteModel objects. It does this by taking the noteUpdate$ property from NoteUpdateService and using the pipe() operator to call switch() operator. switch() takes an inner observable and switches to a new inner observable whenever the outer observable emits a value. In this case, loadNotes() returns an observable that switches to the result of calling getNotes(noteId) whenever noteUpdate$ emits a value.
getNotes(noteId: number) function returns an observable of an array of NoteModel objects. It does this by calling studentNotesService.getStudentNotes(noteId), which in turn calls studentNotesGridService.getNotes(noteId). Before making the call, spinner.show() is called to show the loading spinner, and spinner.hide() is called in the finalize() operator to hide the spinner after the data has been retrieved.
NoteUpdateService has a ReplaySubject called localNoteUpdate$ which is a subject that emits its previous values to new subscribers. The noteUpdate$ getter returns an observable that's created from localNoteUpdate$ using asObservable(). The updateAllNotes() function calls localNoteUpdate$.next(), which causes the localNoteUpdate$ subject to emit a value.
In the ngOnInit() lifecycle hook, noteUpdateService.updateAllNotes() is called to emit a value from localNoteUpdate$. This will cause the observable returned by loadNotes() to switch to a new inner observable, which is the result of calling getNotes(noteId).
The purpose of returning ReplaySubject and using the pipe(switch...) is to trigger a call to getNotes(noteId) whenever noteUpdate$ emits a value. The reason why this is useful is not specified in the code snippet you posted, so it's unclear what the intended use case is.