Utilisation d'un tableau à partir d'un objet observable avec ngFor et Async Pipe Angular 2

91

J'essaie de comprendre comment utiliser 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 reçoit de nouvelles valeurs comme tel à partir d'un autre service:

that._appointmentChoiceStore._appointmentChoices.next(parseObject)

Je m'y abonne sous forme d'observable dans le composant dans lequel je souhaite 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'afficher dans la vue comme suit:

  <li *ngFor="#appointment of _nextFourAppointments.availabilities | async">
         <div class="text-left appointment-flex">{{appointment | date: 'EEE' | uppercase}}

Cependant, les disponibilités ne sont pas encore une propriété de l'objet observable, donc il se trompe, même si je le définis dans l'interface des disponibilités comme suit:

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 je reçois est:

browser_adapter.js:77 ORIGINAL EXCEPTION: TypeError: Cannot read property 'availabilties' of undefined
C. Kearns
la source
Quel est le message d'erreur réel?
Günter Zöchbauer
modifié pour ajouter une erreur
C. Kearns
avec le dernier angular-rc1, la syntaxe est*ngFor="let appointment of _nextFourAppointments.availabilities | async">
Jagannath
c'est vrai, mais cela ne cause pas l'erreur. il jette simplement un avertissement.
C.Kearns
3
Je crois qu'il y a une faute de frappe quelque part. L'erreur dit availabiltiesalors qu'il devrait y avoiravailabilities
Ivan Sivak

Réponses:

152

Voici un exemple

// in the service
getVehicles(){
    return Observable.interval(2200).map(i=> [{name: 'car 1'},{name: 'car 2'}])
}

// in the controller
vehicles: Observable<Array<any>>
ngOnInit() {
    this.vehicles = this._vehicleService.getVehicles();
}

// in template
<div *ngFor='let vehicle of vehicles | async'>
    {{vehicle.name}}
</div>
Relu Mesaros
la source
ma fonction get renvoie cependant un sujet:, public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return this._appointmentChoices.map(object=>object.availabilities).subscribe() } dans le contrôleur, lorsque je le règle sur égal, j'obtiens l'erreur:, browser_adapter.js:77Error: Invalid argument '[object Object]' for pipe 'AsyncPipe'comment transformer le sujet en observable?
C. Kearns
public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return (this._appointmentChoices.map(object=>object.availabilities).asObservable()) } } cela me donne l'erreur property asObservable does not exist on type observable:, mais _appointmentChoices est un Subject?
C. Kearns
C'était déjà un observable! J'avais juste besoin de m'y abonner!
C. Kearns
J'ai eu un problème supplémentaire avec l'intégration des sujets. Voici un StackBlitz utilisant des observables et des sujets: stackblitz.com/edit/subject-as-observable-list-example
IceWarrior353
12

Qui a jamais trébuché sur ce post.

Je crois que c'est la bonne façon:

  <div *ngFor="let appointment of (_nextFourAppointments | async).availabilities;"> 
    <div>{{ appointment }}</div>
  </div>
Martin Søberg
la source
1

Je pense que ce que tu cherches c'est ça

<article *ngFor="let news of (news$ | async)?.articles">
<h4 class="head">{{news.title}}</h4>
<div class="desc"> {{news.description}}</div>
<footer>
    {{news.author}}
</footer>

Nixon Mathew
la source
1

Si vous n'avez pas de tableau mais que vous essayez d'utiliser votre observable comme un tableau même s'il s'agit d'un flux d'objets, cela ne fonctionnera pas en mode natif. Je montre comment résoudre ce problème ci-dessous en supposant que vous ne vous souciez que d'ajouter des objets à l'observable, pas de les supprimer.

Si vous essayez d'utiliser une observable dont la source est de type BehaviorSubject, changez-la en ReplaySubject puis dans votre composant abonnez-vous comme ceci:

Composant

this.messages$ = this.chatService.messages$.pipe(scan((acc, val) => [...acc, val], []));

HTML

<div class="message-list" *ngFor="let item of messages$ | async">
Post Impatica
la source
Au lieu de l' scanopérateur, vous pouvez utiliser.pipe(toArray())
MotKohn
Un autre écueil lors de la création du vôtre Subjectest de ne pas appeler complete(). L'accumulateur ne fonctionnera jamais.
MotKohn