2017-02-24 5 views
1

Ich habe 3 Angular2-Dienste erstellt, die Kategorien, Standorte und Elemente von verschiedenen http-Endpunkten abrufen. Ich möchte jetzt einen neuen Dienst erstellen, der Daten von diesen Diensten abruft und ein neues DataSet aus allen abgerufenen Daten erstellt, aber ich kann kein Observable aus dem nicht-iterierbaren DataSet-Objekt erstellen.Beobachtbar über einen Nicht-Array-Typ

Gibt es eine bessere Möglichkeit, Daten in einer einzigen Struktur zu konsolidieren, wie bei der Verwendung von Observables?

export class DataSet { 
    items: Item[]; 
    locations: Location[]; 
    categories: Category[]; 
} 

@Injectable() 
export class DataService { 

_data : DataSet; 

constructor(
    private _http: Http, 
    private _categoryService: CategoryService, 
    private _locationService: LocationService, 
    private _itemService: ItemService) { } 

getDataSet(): DataSet { 
    this._data = new DataSet(); 

    this._categoryService.getCategories().subscribe(cats => { 
     this._data.categories = cats; 
    }); 

    this._locationService.getLocations().subscribe(locs => { 
     this._data.locations = locs; 
    }); 

    this._itemService.getItems(null).subscribe(items => { 
     this._data.items = items; 
    }); 

    // ERROR can't create observable from non array type dataset 
    return Observable.from(this._data); 
    } 
} 

Antwort

1

Ja, Sie brauchen Observable.of als zu verwenden, in

return Observable.of(this._data); 

Sie müssen möglicherweise die Einfuhr für die Funktion explizit

import {Observable} from 'rxjs/Observable'; 
import 'rxjs/add/observable/of'; 

UPDATE hinzuzufügen:

Ich war unzufrieden mit meiner Antwort, wie gesagt In Kommentaren wurde das zugrunde liegende Problem nicht gelöst. So habe ich eine Lösung gegeben

import 'rxjs/add/observable/forkJoin'; 
import {Observable} from 'rxjs/Observable'; 

export class DataService { 

    constructor(
    private http: Http, 
    private categoryService: { getCategories(): Observable<{ categoryName: string }[]> }, 
    private locationService: { getLocations(): Observable<{ locationName: string }[]> }, 
    private itemService: { getItems(options): Observable<{ itemName: string }[]> }) { } 

    getDataSet() { 
    return Observable 
     .forkJoin(
     this.categoryService.getCategories(), 
     this.locationService.getLocations(), 
     this.itemService.getItems(undefined) 
    ) 
     .map(([categories, locations, items]) => ({ 
     categories, 
     locations, 
     items 
     })); 
    } 
} 

Observable.forkJoin hat die Semantik die Sie suchen, dass sie bewahrt die Unterscheidung zwischen den verschiedenen Eingangs Observable durch sie in die resultierende Anordnung der Ergebnisse der Sequenzierung.

Beachten Sie, dass dies auch unseren Code bereinigt, da kein veränderbares Klassenfeld mehr vorhanden ist.

Nur ein paar Gedanken:

Etwas, das ich interessant finde, ist, dass ich Observable.forkJoin verwenden musste (es kann ein einfacher Weg sein, und mir bitte sagen, ob es ist!), Die keine sehr auffindbar Funktion ist, und hat auch keine Dokumentation in ForkJoinObservable.d.ts.

Der Grund, warum dies mich stört ist, dass diese Frage beschreibt ein grundlegendes Szenario bei der Verwendung von Observable als Schnittstelle für Singular Web-Anfragen. Es sollte offensichtlich und intuitiv sein, wenn wir glauben, dass Observable die richtige Abstraktion für diesen Anwendungsfall ist.

Sobald wir über Dinge wie typeahead Eingaben sprechen, die asynchrone Abfragen ausführen, die im Laufe der Zeit zwischen 0 und einigen willkürlichen n Werten zurückkommen, dann scheint Observable imbued Web Requests wertvoll zu werden.

Das einzige Problem mit diesem ist, dass das typeahead-Szenario, das eine Art des Aushängeschilds für RxJS + Angular ist, flatMapping die Ergebnisse sowieso enthält. Die gesamte Abstraktion wird auf die Ebene gehoben, auf der RxJS bereits anwendbar, relevant und elegant ist, weil die Domäne die der Ströme ist.

+0

Dank Aluan, Sie beantwortet die Frage in Bezug auf Observable.of aber das hat nicht das gewünschte Ergebnis erreicht. Ich habe erwartet, dass der Abonnent nicht angerufen wird, bis die verschachtelten Sammlungen gefüllt sind, aber ich denke, dass ich dafür in beobachtbare Verkettung schauen muss. – Dennis

+0

Das ist richtig. Sie können Merge oder Fork-Join oder Concat verwenden. Alle sind anders. –

+0

Natürlich gibt es ein paar Dutzend andere Möglichkeiten, das auch in RxJS zu tun. Der offensichtlichste Weg besteht darin, dass alle abonnierten Anrufe durch Kartenanrufe ersetzt und dann verschachtelt werden, was zu unlesbarem Code führt. –

Verwandte Themen