如何在Angular中使用rxjs运算符加入Observable(angularfire2)
我试图找出在Angular中加入Observables的基本知识。我找到了几个例子,但似乎无法弄清楚如何有效地工作。如何在Angular中使用rxjs运算符加入Observable(angularfire2)
我有以下数据结构:
- courses
- $courseid1
- $courseid2
- $courseid3
- ...
- teachers
- $teacherid1
- $teacherid2
- $teacherid3
- ...
- teachersPerCourse
- $courseid1
- $teacherid1 : true
- $teacherid2 : true
- $courseid2
- $teacherid1 : true
- $courseid3
- $teacherid3 : true
- ...
现在,我使用下面的函数来获取其塞课程:
getFullCourseBySlug(slug:string) {
return this.db.list('academy/courses', {
query: {
orderByChild: 'slug',
equalTo: slug
}
}).map((courses) => courses[0]);
}
现在我想老师的数组映射到课程对象,以便我最终得到一个可观察到的东西,如下所示:
{
title: ...,
slug: ...,
teachers: {
$teacherid1: {
firstname: ...,
lastname: ...,
etc ... },
$teacherid2: {
firstname: ...,
lastname: ...,
etc ... }
}
}
我在其他地方有相同的原理工作,但我必须在地图功能中使用订阅,或使用Observable内的Observables。例如:
getCoursesPerCategory(categoryid:string):Observable<Course[]> {
return this.db.list(`academy/coursesPerCategory/${categoryid}`).map(courses => {
courses.map(course => {
this.db.object(`academy/courses/${course.$key}`).subscribe((data) => {
course.$value = data;
});
return course;
});
return courses;
});
}
如果有人可以帮助我举一个例子,说明如何更有效地做到这一点,将不胜感激!
UPDATE:
我已经成功地得到它的工作,但我仍然无法摆脱嵌套的观测量,这意味着我必须使用特里普尔异步管道(这可能不是最好的做法: P)我试图按照建议使用flatMap,但还不知道如何去做。我现在所拥有的:
getFullCourseBySlug(slug:string): Observable<any> {
return this.db.list('academy/courses', {
query: {
orderByChild: 'slug',
equalTo: slug
}
}).map(courses => courses[0]).switchMap(course => {
course.teachers = this.db.list(`academy/teachersPerCourse/${course.$key}`)
.map(teachers => {
teachers.map(teacher => {
teacher.$value = this.db.object(`academy/teachers/${teacher.$key}`);
});
return teachers;
});
return Observable.of(course);
});
}
用下面的模板:
{{ (course | async)?.title }}
<ul>
<li *ngFor="let teacher of ((course | async)?.teachers) | async">
{{ (teacher.$value | async)?.firstname }}
</li>
</ul>
更新2:
见我的回答对我的解决方案
我会做的是沿着东西以下几行。
首先,我将建立查询课程的方法,像你
getFullCourseBySlug(slug:string) {
return this.db.list('academy/courses', {
query: {
orderByChild: 'slug',
equalTo: slug
}
}).map((courses) => courses[0]);
}
然后我会创造你需要执行第二个查询,即取即教师课程的标识之一。
查询的代码可能看起来像
getTeacherIdsPerCourse(course: any) {
return this.db.list('academy/teachersPerCourse', {
query: {
orderByChild: 'slug',
equalTo: course.slug
}
}).map((teacherIds) => [teacherIds, course]);
}
看看这个事实,这第二个查询是建立在同时返回teacherIds并已作为参数传递的过程。 现在,您可以使用switchMap运算符连接2个查询。 级联会再像
this.getFullCourseBySlug(slug)
.switchMap(course => this.getTeacherIdsPerCourse(course))
.map(([teacherIds, course]) => {
// here you have the TeacherIds and the course and therefore you
// need to fetch from DB the details for each teacherId and build the
// full course object with all the details
})
现在的问题是如何执行一堆的查询和管理产生可观,因为你需要从教师收集阅读所有其ID已提取与老师第二个查询。
首先构建您需要的第三个查询,即从教师ID开始获取教师所有细节的查询。该代码可能看起来像
getTeacher(id:string) {
return this.db.list('academy/teachers', {
query: {
orderByChild: 'slug',
equalTo: slug
}
}).map((teachers) => teachers[0]);
}
如果你可以用HTTP调用的异步回住,也就是说,如果你不需要等待最后老师是牵强,比你能有这样的事情
this.getFullCourseBySlug(slug)
.switchMap(course => this.getTeacherIdsPerCourse(course))
.map(([teacherIds, course]) => {
for(let id of teacherIds) {
this.getTeacher(id).subscribe(teacher => {
course.teachers.push(teacher);
}
}
})
相反,如果您需要将所有教师的所有详细信息返回到完整课程,那么您需要执行一些更复杂的操作,因为您需要等待所有由教师返回的可观察项getTeacher()
方法待解决。
代码这样做可能会像
this.getFullCourseBySlug(slug)
.switchMap(course => this.getTeacherIdsPerCourse(course))
.map(([teacherIds, course]) => {
const arrayOfObservables = new Array<Observable>();
for(let id of teacherIds) {
arrayOfObservables.push(this.getTeacher(id)
.map(teacher => course.teachers.push(teacher)));
}
return Observable.combineLatest(arrayOfObservables):
})
免责声明:我不是完全肯定的代码是正确的,因为我没有建立一个真正的考验,但简单地组装,我认为相关概念 - 我希望反正我已经给你出个主意
Picci的回答让我在正确的方向,这是我最终的解决方案:
getTeachersPerCourse(courseid:string):Observable<Teacher[]> {
return this.db.list(`academy/teachersPerCourse/${courseid}`)
.switchMap((teachers) => {
let teacherObservables = [];
for(let teacher of teachers){
teacherObservables.push(this.db.object(`academy/teachers/${teacher.$key}`));
}
return Observable.combineLatest(teacherObservables);
});
}
getFullCourseBySlug(slug:string): Observable<any> {
return this.db.list('academy/courses', {
query: {
orderByChild: 'slug',
equalTo: slug
}
}).map(courses => courses[0]).switchMap(course => {
return Observable.combineLatest(Observable.of(course), this.getTeachersPerCourse(course.$key), (fullCourse, teachers) => {
fullCourse['teachers'] = teachers;
return fullCourse;
});
});
}
这给了我一个流与课程,和教师的数组作为课程的孩子:
{
title: ...,
slug: ...,
teachers: [
{
firstname: ...,
lastname: ...,
etc ...
},
{
firstname: ...,
lastname: ...,
etc ...
}
]
}
的观发出任何小孩的任何变化,正是我一直在寻找。而我只需要在我的模板使用一个异步管道:
{{ (course | async)?.title }}
<ul>
<li *ngFor="let teacher of (course | async)?.teachers">
{{ teacher.firstname }}
</li>
</ul>
希望这有助于其他人:)
这真的帮了我在正确的方向,最终我设法得到它的工作,因为我祝愿!非常感谢广泛的答复和帮助。我会为其他人发布我的最终解决方案 –