我通过Httpclient获得请求。我遇到的问题是当我尝试从其他组件访问此请求加载的变量时。当我尝试这样做时,我发现它是空的。
这是服务中的方法:
import { HttpClient } from '@angular/common/http';
...
getBooks(page: string) {
let url = `${this.urlAPI}books?page=${page}`;
return this.http.get<Book[]>(url).pipe(map((res: Book[]) => res));
}
这是component.ts中的代码。这是递归的,因为api每次仅加载50。
import { ApiService } from 'src/app/services/api.service';
...
books: Book[] = [];
...
constructor(public auth: AuthService, public _api: ApiService, private router: Router) {
this.loadBooks(1);
}
...
loadBooks(page: number) {
this._api.getBooks(page.toString()).subscribe((resp: Book[]) => {
this.books = this.books.concat(resp);
if (resp.length !== 0)
this.loadBooks(page + 1)
else{
...
}
});
}
这是从子componenet加载变量的方法:
import { Component, OnInit, Input } from '@angular/core';
import { BooksComponent } from '../../tab/books/books.component';
...
import { ApiService } from 'src/app/services/api.service';
@Component({
selector: 'app-book',
templateUrl: './book.component.html',
styleUrls: ['./book.component.scss'],
providers: [BooksComponent]
})
export class BookComponent implements OnInit {
book: Book = new Book();
constructor(private bc:BooksComponent, public _api: ApiService, private route: ActivatedRoute) {
console.log(bc.books);
...
}
对父组件的子组件的调用。我也知道这是一个异步调用,因此直到它完成为止,我还没有填充变量。但是在看到父组件中的所有数据后,我将其称为。我不明白为什么如果我填充了变量,那么此数组对其他组件是空的。谢谢您的回答。
从providers数组中删除BooksComponent
。您不希望子组件提供其自己的BooksComponent
实例,而是希望angular获得已经存在的实例,即父组件。
@Component({
selector: 'app-book',
templateUrl: './book.component.html',
styleUrls: ['./book.component.scss'],
providers: [BooksComponent] // <= remove this
})
export class BookComponent implements OnInit {...}
[Angular中有一棵组件注入器树。当您尝试注入某些东西时,只需将令牌作为构造函数参数传递即可。组件注入器开始在组件提供者上寻找该令牌。在这种情况下,组件注入程序在其自己的提供程序中找到了一个实例,而不是所需的实例(父组件),因此它停止了将进行的递归搜索(通过询问父级的组件注入程序,该搜索将返回正确的实例)。
我注意到的几件事:1.不要在Component
或其他providers
中使用Services
内的providers
2.使用服务或@Input()
/ @Output()
在组件之间共享数据。3.尽量避免嵌套订阅和递归订阅,因为这将是内存泄漏的主要风险。
现在考虑我的改进思路:我假设该书组件实际上是一本书的显示组件。
这是book.component.ts
import { Component, OnInit, Input } from '@angular/core';
...
import { ApiService } from 'src/app/services/api.service';
@Component({
selector: 'app-book',
templateUrl: './book.component.html',
styleUrls: ['./book.component.scss'],
})
export class BookComponent implements OnInit {
@Input() book: Book = new Book();
constructor(public _api: ApiService, private route: ActivatedRoute) {
}
ngOnInit() {
console.log(this.book) // either is new Book() or the given book from its parent (look parent .html)
}
...
import { ApiService } from 'src/app/services/api.service';
import { Subject } from 'rxjs'
import { mergeMap } from 'rxjs/operators'
@Component({
...
})
export class ParentComponent implements OnInit, OnDestroy {
...
books: Book[] = [];
private loadPage = new Subject<number>()
...
constructor(public auth: AuthService, public _api: ApiService, private router: Router) {
//
}
ngOnInit() {
this.loadPage
.pipe(
mergeMap(number => this.loadBooks(number),
(page, books) => {
if (books.length !== 0) {
this.loadPage.next(page+1)
}
return books
}
)
).subscribe({
next: books => {
this.books = this.books.concat(books)
};
error: () => console.log("error");
})
}
ngOnDestroy() {
this.loadPage.complete()
}
loadBooks(page: number) {
return this._api.getBooks(page.toString())
}
Api服务保持不变。
和parent.component.html
:
<app-book *ngFor="let book of books" [book]="book"></app-book>