Usando una matriz de Observable Object con ngFor y Async Pipe Angular 2


93

Estoy tratando de entender cómo usar Observables en Angular 2. Tengo este servicio:

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

A este BehaviorSubject se le envían nuevos valores desde otro servicio:

that._appointmentChoiceStore._appointmentChoices.next(parseObject)

Me suscribo a él en forma de observable en el componente en el que quiero mostrarlo:

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

Y el intento de mostrar en la vista así:

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

Sin embargo, la disponibilidad aún no es una propiedad del objeto observable, por lo que se produce un error, incluso aunque lo defina en la interfaz de disponibilidades de la siguiente manera:

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

¿Cómo puedo mostrar una matriz de forma asíncrona desde un objeto observable con la tubería asíncrona y * ngFor? El mensaje de error que recibo es:

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

¿Cuál es el mensaje de error real?
Günter Zöchbauer

editado para agregar error
C. Kearns

con el último angular-rc1, la sintaxis es*ngFor="let appointment of _nextFourAppointments.availabilities | async">
Jagannath

esto es cierto, pero no está causando el error. simplemente lanza una advertencia.
C.Kearns

3
Creo que hay un error tipográfico en alguna parte. El error dice availabiltiesmientras debería haberavailabilities
Ivan Sivak

Respuestas:


154

Aquí hay un ejemplo

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

Sin embargo public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return this._appointmentChoices.map(object=>object.availabilities).subscribe() } , mi función get está devolviendo un sujeto:, en el controlador cuando lo configuro igual, obtengo el error:, browser_adapter.js:77Error: Invalid argument '[object Object]' for pipe 'AsyncPipe'¿cómo convierto el sujeto en un observable?
C.Kearns

public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return (this._appointmentChoices.map(object=>object.availabilities).asObservable()) } } esto me da el error:, property asObservable does not exist on type observablepero _appointmentChoices es un Subject?
C.Kearns

¡Ya era un observable! ¡Solo necesitaba suscribirme!
C.Kearns

Tuve un problema adicional con la integración de materias. Aquí hay un StackBlitz usando observables y sujetos: stackblitz.com/edit/subject-as-observable-list-example
IceWarrior353

12

Quien alguna vez también se tropiece con esta publicación.

Creo que es la forma correcta:

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

1

Creo que lo que buscas es esto

<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

Si no tiene una matriz pero está tratando de usar su observable como una matriz, aunque sea una secuencia de objetos, esto no funcionará de forma nativa. A continuación, muestro cómo solucionar este problema, asumiendo que solo le importa agregar objetos al observable, no eliminarlos.

Si está tratando de usar un observable cuya fuente es de tipo BehaviorSubject, cámbielo a ReplaySubject y luego en su componente suscríbase a él de esta manera:

Componente

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

HTML

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

En lugar del scanoperador puede utilizar.pipe(toArray())
MotKohn

Otro error al crear el tuyo propio Subjectes no llamar complete(). El acumulador nunca funcionará.
MotKohn
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.