In this code below , I want student list to be rendered immediately and not wait for the second observable , but when second observable comes , it should check that student is not enrolled in all courses and then enable the button to add to course.
Asked
Active
Viewed 233 times
1
-
1Please don't include screenshots of code. Include your actual code, instead. – Cerbrus Aug 23 '22 at 12:08
-
@cebrus I have added stackblitz – Seth Aug 23 '22 at 12:12
-
1In the question itself. Not just an external link. – Cerbrus Aug 23 '22 at 12:15
-
Have you tried to use "merge" https://www.learnrxjs.io/learn-rxjs/operators/combination/merge rather than switchmap ? – user1075296 Aug 23 '22 at 12:22
2 Answers
1
You need to first create a behaviour subject, the special property of behaviour subject is we can have a initialization value. Then when each api call completes we can update the subject with the latest value.
Learn more about behaviour subject
html
<div class="container">
<div class="list" *ngIf="studentDataSubject | async as studentData">
<div *ngFor="let student of studentData">
<div>{{ student.name }}</div>
<button class="btn" [disabled]="student.enable">Add to course</button>
</div>
</div>
<div class="list" *ngIf="courseDataList | async as courseData">
<div *ngFor="let course of courseData">
<div>{{ course.name }}</div>
</div>
</div>
</div>
ts
import { Component, OnInit, VERSION } from '@angular/core';
import { BehaviorSubject, map, Observable, switchMap, tap } from 'rxjs';
import {
IStudentData,
getStudentList,
ICourseData,
getCourseList,
} from './dummyApi';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
studentDataSubject: BehaviorSubject<any> = new BehaviorSubject<any>([]);
name = 'Angular ' + VERSION.major;
studentDataList: Observable<IStudentData[]> = getStudentList(); // no delay
courseDataList: Observable<ICourseData[]> = getCourseList(); // data comes after 3 seconds
ngOnInit() {
this.studentDataList
.pipe(
switchMap((studentData) => {
this.studentDataSubject.next(studentData);
return this.courseDataList.pipe(
tap((courseData) => {
const newStudentData = studentData.map((student) => {
let dummyStudentObj = {
...student,
enable: student.courseCount < courseData.length,
};
return dummyStudentObj;
});
this.studentDataSubject.next(newStudentData);
})
);
})
)
.subscribe();
}
}

Naren Murali
- 19,250
- 3
- 27
- 54
-
Thanks for reply , but it has to be done reactively. Manual subscription is not allowed , only async pipe is accepted. So can you do it without subscribing manually in ngOnInit – Seth Aug 23 '22 at 15:37
1
studentDataList.pipe(switchMap(...courseDataList...))
to
courseDataList.pipe(switchMap(...studentDataList...))
ts
export class AppComponent {
name = 'Angular ' + VERSION.major;
studentDataList: Observable<IStudentData[]> = getStudentList(); // no delay
courseDataList: Observable<ICourseData[]> = getCourseList(); // data comes after 3 seconds
resultData = this.courseDataList.pipe(
map(({length}) => length),
// startWith(Infinity),
switchMap((len) => this.studentDataByLength(len))
);
studentDataByLength(length: number){
return this.studentDataList.pipe(
map((datas) => datas.map((d) => ({...d, enable: d.courseCount < length})))
);
}
ngOnInit() { }
}
html
<div class="container">
<div class="list" *ngIf="resultData | async as studentData">
<div *ngFor="let student of studentData">
<div>{{ student.name }}</div>
<button class="btn" [disabled]="student.enable">Add to course</button>
</div>
</div>
<div class="list" *ngIf="courseDataList | async as courseData">
<div *ngFor="let course of courseData">
<div>{{ course.name }}</div>
</div>
</div>
</div>

Eddy Lin
- 513
- 2
- 6
-
Hi @Eddy , thanks for reply. But this doesn't solve the problem , using this also I have to wait until data of course observable comes , only then the student data shows. I want student data to show earlier , but when course data comes then it changes the button states – Seth Aug 24 '22 at 06:57
-
-
it will still only show after the courseList comes which comes after 3 seconds. I tried uncommenting , still both comes together . I need studentList to comes first as there is no delay in that API and then after 3 seconds next on comes and changes button states – Seth Aug 24 '22 at 07:14
-
1
-
-
1courseDataList need delay 3 sec, so just use `startWith(Infinity)` make it trigger `switchMap` on first time – Eddy Lin Aug 24 '22 at 09:15