J'essaie de comprendre comment utiliser les Observables dans Angular 2. J'ai ce service :
import {Injectable, EventEmitter, ViewChild} from '@angular/core';
import {Observable} from "rxjs/Observable";
import {Subject} from "rxjs/Subject";
import {BehaviorSubject} from "rxjs/Rx";
import {Availabilities} from './availabilities-interface'
@Injectable()
export class AppointmentChoiceStore {
public _appointmentChoices: BehaviorSubject<Availabilities> = new BehaviorSubject<Availabilities>({"availabilities": [''], "length": 0})
constructor() {}
getAppointments() {
return this.asObservable(this._appointmentChoices)
}
asObservable(subject: Subject<any>) {
return new Observable(fn => subject.subscribe(fn));
}
}
Ce BehaviorSubject est poussé de nouvelles valeurs ainsi d'un autre service :
that._appointmentChoiceStore._appointmentChoices.next(parseObject)
Je m'y abonne sous la forme d'un observable dans le composant dans lequel je veux l'afficher :
import {Component, OnInit, AfterViewInit} from '@angular/core'
import {AppointmentChoiceStore} from '../shared/appointment-choice-service'
import {Observable} from 'rxjs/Observable'
import {Subject} from 'rxjs/Subject'
import {BehaviorSubject} from "rxjs/Rx";
import {Availabilities} from '../shared/availabilities-interface'
declare const moment: any
@Component({
selector: 'my-appointment-choice',
template: require('./appointmentchoice-template.html'),
styles: [require('./appointmentchoice-style.css')],
pipes: [CustomPipe]
})
export class AppointmentChoiceComponent implements OnInit, AfterViewInit {
private _nextFourAppointments: Observable<string[]>
constructor(private _appointmentChoiceStore: AppointmentChoiceStore) {
this._appointmentChoiceStore.getAppointments().subscribe(function(value) {
this._nextFourAppointments = value
})
}
}
Et la tentative d'affichage dans la vue comme tel :
<li *ngFor="#appointment of _nextFourAppointments.availabilities | async">
<div class="text-left appointment-flex">{{appointment | date: 'EEE' | uppercase}}
Cependant, availabilities n'est pas encore une propriété de l'objet observable, ce qui entraîne une erreur, même si je la définis comme telle dans l'interface availabilities :
export interface Availabilities {
"availabilities": string[],
"length": number
}
Comment puis-je afficher un tableau de manière asynchrone à partir d'un objet observable avec le tube asynchrone et *ngFor ? Le message d'erreur que j'obtiens est le suivant :
browser_adapter.js:77 ORIGINAL EXCEPTION: TypeError: Cannot read property 'availabilties' of undefined
0 votes
Quel est le message d'erreur réel ?
0 votes
Modifié pour ajouter l'erreur
0 votes
Avec la dernière version d'angular-rc1, la syntaxe est la suivante
*ngFor="let appointment of _nextFourAppointments.availabilities | async">
0 votes
C'est vrai, mais cela ne provoque pas l'erreur. cela génère simplement un avertissement.
3 votes
Je crois qu'il y a une faute de frappe quelque part. L'erreur dit
availabilties
alors qu'il devrait y avoiravailabilities
0 votes
Correction de la faute d'orthographe, mais les disponibilités ne sont pas le problème, l'erreur est que l'observable n'est pas défini au moment où le modèle est analysé, et malgré le pipe asynchrone, il essaie toujours de trouver la clé je crois
0 votes
Sur
AppointmentChoiceStore
Je pense que vous pouvez simplement retourner le sujet au lieu de le mettre dans un nouvel Observable.BehaviorSubject
s'étend deObservable
. SurAppointmentChoiceComponent
vous vous abonnez auAppointmentChoiceStore
observable. Cela devrait vous renvoyer unAvailabilities
(et non unstring[] observable
) que vous mettez dans_nextFourAppointments
. Alors changez_nextFourAppointments: Observable<string[]>
a_nextFourAppointments: Availabilities
et mettez à jour le modèle en conséquence. @Ivan : cela n'explique pas pourquoi l'erreur concerne la lecture de la propriété 'X' d'undefined.0 votes
C'est logique @Sjoerd. Si je garde le modèle avec
_nextFourAppointments.availabilities
avec les modifications que vous avez apportées, j'obtiens toujours l'erreur. Si je modifie la fonction d'abonnement pour définir_nextFourAppointments = value.availabilities
et changer le modèle pour juste itérer sur_nextFourAppointments
Je peux confirmer qu'il est défini dans le tableau que je veux, mais qu'il ne remplit pas le modèle, je pense que c'est parce que l'optionasync
attend unObservable
y_nextFourAppointments
est maintenant_nextFourAppointments: Availabilities
0 votes
Vous essayez de lire le
availabilities
clé de_nextFourAppointments
dans le modèle, mais (et c'est ce que le message d'erreur essaie de vous dire)_nextFourAppointments
est indéfinie. Cela peut se produire lorsqu'Angular instancie le composant. Je ne suis pas sûr que cela fonctionne ici, mais vous pouvez essayer l'opérateur Elvis :_nextFourAppointments?.availabilities
. L'opérateur Elvis protège contre les valeurs nulles.0 votes
@Sjoerd, l'opérateur elvis permet effectivement d'éviter l'erreur, et je suis bien en train de paramétrer _
nextFourAppointments
au tableau dans mon abonnement, mais le modèle n'est toujours pas rempli, avec ou sans l'optionasync pipe
. Je crois que le seul moyen d'utiliser le tuyau asynchrone et*ngFor
est avec un tableau d'observables et je ne sais toujours pas comment saisir le tableau de l'objet observable avant d'avoir l'objet observable. Je vais devoir y réfléchir.0 votes
Pourquoi ne pas supprimer le tuyau aync, car vous ne regardez plus un Observable. Au fait, il serait également utile que vous fournissiez un exemple de plunker fonctionnel. De cette façon, nous pourrons voir plus clairement quel est le problème et comment le résoudre.
0 votes
J'ai essayé d'enlever le tuyau asynchrone mais il ne s'est toujours pas rempli. Je vais éditer avec un plunk dans la matinée. J'aurais aimé trouver rxjs moins intimidant, cela aurait facilité le travail avec Angular 2.