我已经完成了《英雄之旅》教程(两次),以及Brad Traversy的《从前到后的角度》。我有一点(功能性)Python经验,但是仍然想尽我所能围绕Angular语法以及类如何工作。
作为一种实践,我正在基于ToH制作一个图书馆Web应用程序,在那里我可以使用单独的服务将书和作者存储在单独的组件中,以通过HTTP服务获取它们。
遵循Angular Style Guide,将逻辑放在组件而不是模板中之后,我未成功制作了一个书本/作者-视图组合的组件,显示了作者及其所写的书分别,反之亦然。 (我不想将其放在HTML模板中。)
这是 author.component.ts 。 book.component.ts 是相同的,除了作者被“ book / books”所取代:
import { Component, OnInit } from '@angular/core';
import { Author } from '../../models/author';
import { AuthorService } from '../../services/author.service';
@Component({
selector: 'app-authors',
templateUrl: './authors.component.html',
styleUrls: ['./authors.component.css']
})
export class AuthorsComponent implements OnInit {
authors: Author[];
constructor(private authorService: AuthorService) { }
ngOnInit() {
this.getAuthors();
}
getAuthors(): void {
this.authorService.getAuthors().subscribe(authors =>
this.authors = authors);
}
Book / AuthorService与Tour of Heroes的“ HeroService”相似,因为它们使用http.get:
/** GET authors from the server */
getAuthors (): Observable<Author[]> {
return this.http.get<Author[]>(this.authorsUrl);
模型 author.ts 和 book.ts
export class Author {
id: number;
firstName: string;
lastName: string;
booksAuthored?: number[];
}
export class Book {
id: number;
authorId?: number; // TODO: allow multiple authors
title: string;
}
我可能已经正确理解,一个可观察对象是一个流对象(而不是JSON类型的对象),并且不能像常规数组那样被切片。
我想要一个可以将author.lastName和author.firstName串联在一起的函数,然后列出属于各自作者的书籍。我已经能够在HTML模板中使用ngFor(让作者的作者)和ngIf(如果book.authorId === author.id)做到这一点,但是现在我想在组件(或服务)中做同样的事情。 )
答案 0 :(得分:0)
您可以向Author类添加一个函数以允许串联,
export class Author {
id: number;
firstName: string;
lastName: string;
booksAuthored?: number[];
public fullName() {
return this.firstname + ' ' + this.lastname;
}
}
那么只要您有一个Author对象,就调用author.fullname()
要获取每位作者的书籍,可以在get authors方法中执行以下操作:
getAuthors(): void {
this.authorService.getAuthors().pipe(map(eachAuthor => {
eachAuthor.booksAuthorWrote = this.bookService.getBooks<Book[]>(eachAuthor.id);
}))
.subscribe(authors =>
this.authors = authors
);
}
这将检索由getAuthors()调用返回的每个作者的书籍。如果您想避免进行那么多服务器调用,只需获取所有作者和所有书籍,然后运行与模板中所用类似的循环即可:
for(let author of this.authors) {
for(let book of this.books) {
if(book.authorID === author.id) {
this.authors.booksAuthorWrote.push(book);
}
}
}
这假设您向author类添加了一系列书籍,如下所示:
export class Author {
id: number;
firstName: string;
lastName: string;
booksAuthored?: number[];
booksAuthorWrote?: Book[];
}
答案 1 :(得分:0)
combineLatest
可能是您正在寻找的。 p>
因此,我们将两个流组合在一起:作者和书籍。重要的是要知道,只有在作者流和书籍流都具有事件的情况下,组合流才会开始发送事件。
接下来,我们要操纵结果。因此,我们使用map
运算符在其中循环遍历每个作者,并创建一个包含串联名称和书籍的新对象。在books
属性内,添加与作者ID匹配的所有书籍。
使用此结果流,您可以创建一个显示作者列表及其相应书籍的组件。
import {combineLatest} from 'rxjs';
combineLatest(authors$, books$).pipe(
map(([authors, books]) => {
return authors.map(author => {
return {
name: author.firstName + ' ' + author.lastName,
books: books.filter(book => book.authorId === author.id)
};
})
})
).subscribe(res => console.log(res));
有关combineLatest
的更多文档:
http://rxmarbles.com/#combineLatest
http://reactivex.io/documentation/operators/combinelatest.html