Używanie tablicy z obiektu obserwowalnego z ngFor i Async Pipe Angular 2

93

Próbuję zrozumieć, jak używać Observables w Angular 2. Mam tę usługę:

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

To BehaviorSubject jest wypychane nowe wartości z innej usługi:

that._appointmentChoiceStore._appointmentChoices.next(parseObject)

Subskrybuję go w postaci obserwowalnego w komponencie, w którym chcę go wyświetlić:

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

I próba wyświetlenia w widoku tak:

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

Jednak dostępność nie jest jeszcze właściwością obserwowalnego obiektu, więc popełnia błędy, nawet myślałem, że zdefiniowałem to w interfejsie dostępności tak:

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

Jak mogę wyświetlić tablicę asynchronicznie z obserwowalnego obiektu za pomocą potoku asynchronicznego i * ngFor? Otrzymuję komunikat o błędzie:

browser_adapter.js:77 ORIGINAL EXCEPTION: TypeError: Cannot read property 'availabilties' of undefined
C. Kearns
źródło
Jaki jest rzeczywisty komunikat o błędzie?
Günter Zöchbauer
edytowane w celu dodania błędu
C.Kearns
z najnowszym angular-rc1 składnia to*ngFor="let appointment of _nextFourAppointments.availabilities | async">
Jagannath
to prawda, ale nie powoduje błędu. po prostu rzuca ostrzeżenie.
C. Kearns
3
Myślę, że gdzieś jest literówka. Błąd mówi availabilties, że powinno byćavailabilities
Ivan Sivak

Odpowiedzi:

154

Oto przykład

// 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
źródło
moja funkcja get zwraca jednak temat: public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return this._appointmentChoices.map(object=>object.availabilities).subscribe() } w kontrolerze, gdy ustawię go na równą, pojawia się błąd: browser_adapter.js:77Error: Invalid argument '[object Object]' for pipe 'AsyncPipe'jak zmienić temat w obserwowalny?
C. Kearns,
public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return (this._appointmentChoices.map(object=>object.availabilities).asObservable()) } } to daje mi błąd: property asObservable does not exist on type observableale _appointmentChoices to Subject?
C. Kearns
To już było widoczne! Po prostu musiałem to zasubskrybować!
C. Kearns
Miałem dodatkowy problem z integracją przedmiotów. Oto StackBlitz wykorzystujący obserwowalne i tematy: stackblitz.com/edit/subject-as-observable-list-example
IceWarrior353
12

Kto kiedykolwiek potyka się o ten post.

Wierzę, że to właściwy sposób:

  <div *ngFor="let appointment of (_nextFourAppointments | async).availabilities;"> 
    <div>{{ appointment }}</div>
  </div>
Martin Søberg
źródło
1

Myślę, że szukasz tego

<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
źródło
1

Jeśli nie masz tablicy, ale próbujesz użyć tego, co jest obserwowalne, jak tablicy, nawet jeśli jest to strumień obiektów, nie zadziała to natywnie. Poniżej pokazuję, jak to naprawić, zakładając, że zależy Ci tylko na dodawaniu obiektów do obserwowalnych, a nie na ich usuwaniu.

Jeśli próbujesz użyć obserwowalnego, którego źródło jest typu BehaviorSubject, zmień je na ReplaySubject, a następnie w swoim komponencie zasubskrybuj go w następujący sposób:

Składnik

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

HTML

<div class="message-list" *ngFor="let item of messages$ | async">
Post Impatica
źródło
Zamiast scanoperatora możesz użyć.pipe(toArray())
MotKohn
Inną pułapką podczas tworzenia własnego Subjectjest brak dzwonienia complete(). Akumulator nigdy nie działa.
MotKohn