I am trying to understand how to use Observables in Angular 2. I have this 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));
}
}
This BehaviorSubject is pushed new values as so from another service:
that._appointmentChoiceStore._appointmentChoices.next(parseObject)
I subscribe to it in the form of an observable in the component I want to display it in:
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
})
}
}
And the attempt to display in the view as so:
<li *ngFor="#appointment of _nextFourAppointments.availabilities | async">
<div class="text-left appointment-flex">{{appointment | date: 'EEE' | uppercase}}
However, availabilities isn't yet a property of the observable object so it errors out, even though I define it in the availabilities interface as so:
export interface Availabilities {
"availabilities": string[],
"length": number
}
How can I display an array asynchronously from an observable object with the async pipe and *ngFor? The error message I get is:
browser_adapter.js:77 ORIGINAL EXCEPTION: TypeError: Cannot read property 'availabilties' of undefined
*ngFor="let appointment of _nextFourAppointments.availabilities | async">
availabilties
while there should be availabilities
Here's an example
// 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>
Who ever also stumbles over this post.
I belive is the correct way:
<div *ngFor="let appointment of (_nextFourAppointments | async).availabilities;">
<div>{{ appointment }}</div>
</div>
I think what u r looking for is this
<article *ngFor="let news of (news$ | async)?.articles">
<h4 class="head">{{news.title}}</h4>
<div class="desc"> {{news.description}}</div>
<footer>
{{news.author}}
</footer>
If you don't have an array but you are trying to use your observable like an array even though it's a stream of objects, this won't work natively. I show how to fix this below assuming you only care about adding objects to the observable, not deleting them.
If you are trying to use an observable whose source is of type BehaviorSubject, change it to ReplaySubject then in your component subscribe to it like this:
Component
this.messages$ = this.chatService.messages$.pipe(scan((acc, val) => [...acc, val], []));
Html
<div class="message-list" *ngFor="let item of messages$ | async">
scan
operator you can use .pipe(toArray())
Subject
is not calling complete()
. The accumulator will never run.
Success story sharing
public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return this._appointmentChoices.map(object=>object.availabilities).subscribe() }
, in the controller when I set it equal, I get the error:browser_adapter.js:77Error: Invalid argument '[object Object]' for pipe 'AsyncPipe'
, how do I turn the subject into an observable?public _appointmentChoices: Subject<any> = new Subject() getAppointments() { return (this._appointmentChoices.map(object=>object.availabilities).asObservable()) } }
this gives me the error:property asObservable does not exist on type observable
, but _appointmentChoices is aSubject
?