Verwenden eines Arrays aus Observable Object mit ngFor und Async Pipe Angular 2

91

Ich versuche zu verstehen, wie Observables in Angular 2 verwendet werden. Ich habe diesen 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));
    }
}

Diesem BehaviorSubject werden neue Werte von einem anderen Dienst übertragen:

that._appointmentChoiceStore._appointmentChoices.next(parseObject)

Ich abonniere es in Form eines Observable in der Komponente, in der ich es anzeigen möchte:

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
        })
    }
}

Und der Versuch, in der Ansicht so anzuzeigen:

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

Die Verfügbarkeit ist jedoch noch keine Eigenschaft des beobachtbaren Objekts, sodass es zu Fehlern kommt, obwohl ich es in der Verfügbarkeitsschnittstelle wie folgt definiert habe:

export interface Availabilities {
  "availabilities": string[],
  "length": number
}

Wie kann ich ein Array von einem beobachtbaren Objekt mit der asynchronen Pipe und * ngFor asynchron anzeigen? Die Fehlermeldung, die ich erhalte, lautet:

browser_adapter.js:77 ORIGINAL EXCEPTION: TypeError: Cannot read property 'availabilties' of undefined
C. Kearns
quelle
Was ist die eigentliche Fehlermeldung?
Günter Zöchbauer
bearbeitet, um Fehler hinzuzufügen
C. Kearns
mit dem neuesten angle-rc1 lautet die Syntax*ngFor="let appointment of _nextFourAppointments.availabilities | async">
Jagannath
Dies ist wahr, verursacht aber keinen Fehler. es gibt einfach eine Warnung aus.
C. Kearns
3
Ich glaube, irgendwo gibt es einen Tippfehler. Der Fehler sagt, availabiltiessolange es sein sollteavailabilities
Ivan Sivak

Antworten:

152

Hier ist ein Beispiel

// 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
quelle
Meine Get-Funktion gibt jedoch ein Motiv zurück: public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return this._appointmentChoices.map(object=>object.availabilities).subscribe() } Wenn ich es in der Steuerung gleich setze, wird der Fehler angezeigt: browser_adapter.js:77Error: Invalid argument '[object Object]' for pipe 'AsyncPipe'Wie verwandle ich das Motiv in ein Observable?
C. Kearns
public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return (this._appointmentChoices.map(object=>object.availabilities).asObservable()) } } das gibt mir den property asObservable does not exist on type observablefehler : , aber _appointmentChoices ist ein Subject?
C. Kearns
Es war schon ein beobachtbarer! Ich musste es nur abonnieren!
C. Kearns
Ich hatte ein zusätzliches Problem mit der Integration von Themen. Hier ist ein StackBlitz mit Observablen und Subjekten: stackblitz.com/edit/subject-as-observable-list-example
IceWarrior353
11

Wer stolpert auch über diesen Beitrag.

Ich glaube, das ist der richtige Weg:

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

Ich denke, was du suchst, ist das hier

<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
quelle
1

Wenn Sie kein Array haben, aber versuchen, Ihr Observable wie ein Array zu verwenden, obwohl es sich um einen Objektstrom handelt, funktioniert dies nicht nativ. Im Folgenden wird gezeigt, wie Sie dieses Problem beheben können, vorausgesetzt, Sie möchten dem Observable nur Objekte hinzufügen und nicht löschen.

Wenn Sie versuchen, ein Observable zu verwenden, dessen Quelle vom Typ BehaviorSubject ist, ändern Sie es in ReplaySubject und abonnieren Sie es in Ihrer Komponente wie folgt:

Komponente

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

Html

<div class="message-list" *ngFor="let item of messages$ | async">
Helzgate
quelle
Anstelle des scanOperators können Sie.pipe(toArray())
MotKohn
Eine weitere Gefahr beim Erstellen Ihrer eigenen Subjectist das Nicht-Anrufen complete(). Der Akku wird niemals laufen.
MotKohn