2
votes

Je veux utiliser les résultats de .subscribe dans une méthode à l'intérieur d'une deuxième méthode dans ngOnInit () {}

J'ai une méthode qui utilise un service pour obtenir une liste de livres, j'avais besoin d'une deuxième méthode qui utilise la liste des livres pour obtenir un livre en le filtrant par identifiant. Les deux méthodes sont appelées dans "ngOnInit" du même composant. Ce que j'obtiens, c'est que la deuxième méthode utilise la liste des livres avant d'obtenir ses résultats.

J'ai résolu le problème en appelant la deuxième méthode dans la première dans les résultats de .subscribe, puis en appelant uniquement la première dans ngOnInit. Je n'ai pas trouvé la solution assez satisfaisante, je veux une manière plus générale et organisée ...

 ERROR TypeError: Cannot read property 'find' of undefined

Voici l'erreur que j'obtiens:

export class BookComponent implements OnInit {
  public books: Book[];
  public book: Book;
  public id;
  public sub;

  constructor(private activatedRoute: ActivatedRoute, private router: Router, private bookService: BookService) {}
  getBooks() {
    this.bookService.getBooks().subscribe(
      result => {
        this.books = result;
      }
    );
  }

  findById() {
    this.sub = this.activatedRoute.paramMap.subscribe(params => {
      console.log(params);
      this.id = params.get('id');
      this.book = this.books.find(a => a.id == this.id);
    });
  }


  ngOnInit() {
    this.getbooks();
    this.findById();
  }
}


0 commentaires

3 Réponses :


0
votes

Essayez ceci

findById() {
this.sub = this.activatedRoute.paramMap.subscribe(params => {
  console.log(params);
  this.id = params.get('id');
  this.book = this.books.find(a => a.id == this.id);
});
}


ngOnInit() {
  this.books = [];
  this.getbooks();
  this.findById();
}


2 commentaires

Cela évite l'erreur non définie, mais ne fait rien pour résoudre le problème sous-jacent quant à la raison pour laquelle elle n'est pas définie (ou maintenant [] ).


Merci pour l'idée, cela fonctionne réellement, mais seulement lors du deuxième essai, le premier essai lorsque je route pour la première fois vers un livre et attribue un "identifiant" spécifique, cela ne fonctionne pas ...



0
votes

Cela se produit parce que les livres n'ont pas été initialisés. Puisque vous exécutez deux fonctions asynchrones en même temps, il n'y a aucune garantie que le contenu des livres a été initialisé par getBooks () avant d'appeler findById () .

Vous pouvez éviter ce problème en plaçant l'appel à findById () dans l'appel à getBooks () . Ce type d'abonnement mène à l'enfer des abonnements (plusieurs abonnements imbriqués) , mais cela peut être nettoyé en utilisant rxjs.

Réorganisé votre code d'origine en conséquence ci-dessous.

export class BookComponent implements OnInit {
  public books: Book[];
  public book: Book;
  public id;
  public sub;

  constructor(private activatedRoute: ActivatedRoute, private router: Router, private bookService: BookService) {}
  ngOnInit() {
    this.getbooks();
  }

  getBooks() {
    this.bookService.getBooks().subscribe(
      result => {
        this.books = result;
        this.findById()
      }
    );
  }

  findById() {
    this.sub = this.activatedRoute.paramMap.subscribe(params => {
      console.log(params);
      this.id = params.get('id');
      this.book = this.books.find(a => a.id == this.id);
    });
  }

}


2 commentaires

Merci pour votre réponse, c'est en fait la solution que j'ai décrite, celle que je n'aimais pas, car de cette façon, getBooks () n'obtient pas seulement des livres mais aussi le filtrage par identifiant ... C'est pourquoi je voulais une manière plus organisée.


Vous pouvez utiliser rxjs pour ce faire, mais cela fonctionne différemment du TS standard. Voir cette question / réponse pour plus d'informations . Je dirais probablement obtenir l'identifiant des paramètres, puis l'utiliser dans votre appel au http



0
votes

Votre instinct est correct que vous ne devriez pas essayer d'appeler des abonnés à l'intérieur des abonnés ... Vous devriez utiliser des observables d'ordre supérieur pour atteindre cet objectif et vous assurer d'obtenir toutes vos données observables là où elles sont nécessaires. Dans ce cas, vous voulez utiliser combineLatest:

ngOnInit() {
  this.sub = combineLatest(this.bookService.getBooks(), this.activatedRoute.paramMap)
               .subscribe(([books, params]) => }
                 this.books = books;
                 this.id = params.get('id');
                 this.book = this.books.find(a => a.id == this.id);
               });
}

maintenant le rappel d'abonnement s'exécutera à chaque fois que l'un ou l'autre des flux observables émet, mais seulement une fois que les deux auront émis au moins une fois. Pas besoin du reste. Dans ce cas, je suppose que getBooks () n'émettra qu'une seule fois, mais la paramMap peut émettre à nouveau si l'utilisateur navigue vers un autre ID de livre.


1 commentaires

Merci pour la réponse bien expliquée, j'ai aimé votre idée, mais j'ai également réfléchi à la façon dont certaines lignes de code seront répétées, car ce que je veux vraiment, c'est une méthode distincte qui me donne des livres, que de réutiliser les résultats sans ré-obtenir eux, peut-être / potentiellement par d'autres méthodes comme findById ...