HttpClient角度。将数据保存在变量中并从其他组件访问。空或未定义

问题描述 投票:0回答:2

我通过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);
    ...
  }

对父组件的子组件的调用。我也知道这是一个异步调用,因此直到它完成为止,我还没有填充变量。但是在看到父组件中的所有数据后,我将其称为。我不明白为什么如果我填充了变量,那么此数组对其他组件是空的。谢谢您的回答。

angular httpclient angular-components
2个回答
1
投票

从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中有一棵组件注入器树。当您尝试注入某些东西时,只需将令牌作为构造函数参数传递即可。组件注入器开始在组件提供者上寻找该令牌。在这种情况下,组件注入程序在其自己的提供程序中找到了一个实例,而不是所需的实例(父组件),因此它停止了将进行的递归搜索(通过询问父级的组件注入程序,该搜索将返回正确的实例)。


0
投票

我注意到的几件事:1.不要在Component或其他providers中使用Services内的providers2.使用服务或@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>
© www.soinside.com 2019 - 2024. All rights reserved.