Utilizzo di un array da Observable Object con ngFor e Async Pipe Angular 2


91

Sto cercando di capire come utilizzare Observables in Angular 2. Ho questo servizio:

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

Questo BehaviorSubject riceve nuovi valori come da un altro servizio:

that._appointmentChoiceStore._appointmentChoices.next(parseObject)

Mi iscrivo ad esso sotto forma di osservabile nel componente in cui voglio visualizzarlo:

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

E il tentativo di visualizzare nella vista in questo modo:

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

Tuttavia, le disponibilità non sono ancora una proprietà dell'oggetto osservabile, quindi si sbaglia, anche se l'ho definito nell'interfaccia delle disponibilità in questo modo:

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

Come posso visualizzare un array in modo asincrono da un oggetto osservabile con la pipe asincrona e * ngFor? Il messaggio di errore che ricevo è:

browser_adapter.js:77 ORIGINAL EXCEPTION: TypeError: Cannot read property 'availabilties' of undefined

Qual è il messaggio di errore effettivo?
Günter Zöchbauer

modificato per aggiungere errore
C. Kearns

con l'ultimo angular-rc1 la sintassi è*ngFor="let appointment of _nextFourAppointments.availabilities | async">
Jagannath

questo è vero, ma non causa l'errore. lancia semplicemente un avvertimento.
C. Kearns

3
Credo che da qualche parte ci sia un errore di battitura. L'errore dice che availabiltiesmentre dovrebbe esserciavailabilities
Ivan Sivak

Risposte:


152

Ecco un esempio

// 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>

la mia funzione get però restituisce un soggetto:, public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return this._appointmentChoices.map(object=>object.availabilities).subscribe() } nel controller quando lo imposto uguale, ottengo l'errore:, browser_adapter.js:77Error: Invalid argument '[object Object]' for pipe 'AsyncPipe'come faccio a trasformare il soggetto in un osservabile?
C. Kearns

public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return (this._appointmentChoices.map(object=>object.availabilities).asObservable()) } } questo mi dà l'errore property asObservable does not exist on type observable:, ma _appointmentChoices è un Subject?
C. Kearns

Era già un osservabile! Avevo solo bisogno di iscrivermi!
C. Kearns

Ho avuto un ulteriore problema con l'integrazione dei soggetti. Ecco uno StackBlitz che utilizza osservabili e soggetti: stackblitz.com/edit/subject-as-observable-list-example
IceWarrior353

12

Chi mai si imbatte anche in questo post.

Credo sia il modo corretto:

  <div *ngFor="let appointment of (_nextFourAppointments | async).availabilities;"> 
    <div>{{ appointment }}</div>
  </div>

1

Penso che quello che stai cercando sia questo

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


1

Se non si dispone di un array ma si sta tentando di utilizzare l'osservabile come un array anche se è un flusso di oggetti, non funzionerà in modo nativo. Ti mostro come risolvere questo problema di seguito assumendo che ti interessi solo aggiungere oggetti all'osservabile, non eliminarli.

Se stai tentando di utilizzare un osservabile la cui origine è di tipo BehaviorSubject, modificalo in ReplaySubject quindi nel tuo componente iscriviti in questo modo:

Componente

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

HTML

<div class="message-list" *ngFor="let item of messages$ | async">

Al posto scandell'operatore puoi usare.pipe(toArray())
MotKohn

Un'altra trappola quando si crea il proprio Subjectnon è chiamare complete(). L'accumulatore non funzionerà mai.
MotKohn
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.