que observables example ejemplo angular observable

observables - Crear y devolver Observable desde el Servicio Angular 2



observables angular 5 (6)

En el archivo service.ts:

a. importar ''de'' desde observable / de
si. crear una lista json
C. devolver el objeto json usando Observable.of ()
Ex. -

import { Injectable } from ''@angular/core''; import { Observable } from ''rxjs/Observable''; import { of } from ''rxjs/observable/of''; @Injectable() export class ClientListService { private clientList; constructor() { this.clientList = [ {name: ''abc'', address: ''Railpar''}, {name: ''def'', address: ''Railpar 2''}, {name: ''ghi'', address: ''Panagarh''}, {name: ''jkl'', address: ''Panagarh 2''}, ]; } getClientList () { return Observable.of(this.clientList); } };

En el componente donde estamos llamando a la función get del servicio:

this.clientListService.getClientList().subscribe(res => this.clientList = res);

Esta es más una pregunta de "mejores prácticas". Hay tres jugadores: un Component , un Service y un Model . El Component está llamando al Service para obtener datos de una base de datos. El Service está utilizando:

this.people = http.get(''api/people.json'').map(res => res.json());

para devolver un Observable .

El Component podría suscribirse al Observable :

peopleService.people .subscribe(people => this.people = people); }

Sin embargo, lo que realmente quiero es que el Service devuelva una Array of Model objetos Array of Model que se creó a partir de los datos que el Service recuperó de la base de datos. Me di cuenta de que el Component podría crear esta matriz en el método de suscripción, pero creo que sería más limpio si el servicio lo hace y lo pone a disposición del Component .

¿Cómo puede el Service crear un nuevo Observable que contenga esa matriz y devolverlo?


Este es un ejemplo de los documentos de Angular2 sobre cómo puede crear y usar sus propios Observables:

El servicio

import {Injectable} from ''angular2/core'' import {Subject} from ''rxjs/Subject''; @Injectable() export class MissionService { private _missionAnnouncedSource = new Subject<string>(); missionAnnounced$ = this._missionAnnouncedSource.asObservable(); announceMission(mission: string) { this._missionAnnouncedSource.next(mission) } }

El componente

import {Component} from ''angular2/core''; import {MissionService} from ''./mission.service''; export class MissionControlComponent { mission: string; constructor(private missionService: MissionService) { missionService.missionAnnounced$.subscribe( mission => { this.mission = mission; }) } announce() { this.missionService.announceMission(''some mission name''); } }

Puede encontrar un ejemplo completo y funcional aquí: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service


Llego un poco tarde a la fiesta, pero creo que mi enfoque tiene la ventaja de que carece del uso de EventEmitters y Asignaturas.

Entonces, aquí está mi enfoque. No podemos escapar de subscribe (), y no queremos hacerlo. En ese sentido, nuestro servicio devolverá un Observable<T> con un observador que tiene nuestra preciosa carga. Desde la persona que llama, inicializaremos una variable, Observable<T> , y obtendrá el Observable<T> . A continuación, nos suscribiremos a este objeto. Finalmente, obtienes tu "T"! de su servicio

Primero, nuestro servicio de personas, pero el suyo no pasa parámetros, eso es más realista:

people(hairColor: string): Observable<People> { this.url = "api/" + hairColor + "/people.json"; return Observable.create(observer => { http.get(this.url) .map(res => res.json()) .subscribe((data) => { this._people = data observer.next(this._people); observer.complete(); }); }); }

Ok, como pueden ver, estamos devolviendo un Observable del tipo "personas". La firma del método, incluso lo dice! _people objeto _people en nuestro observador. A continuación, accederemos a este tipo desde nuestra persona que llama en el Componente.

En el componente:

private _peopleObservable: Observable<people>; constructor(private peopleService: PeopleService){} getPeople(hairColor:string) { this._peopleObservable = this.peopleService.people(hairColor); this._peopleObservable.subscribe((data) => { this.people = data; }); }

Inicializamos nuestro _peopleObservable devolviendo ese Observable<people> de nuestro PeopleService . Luego, nos suscribimos a esta propiedad. Finalmente, configuramos this.people a nuestra respuesta de datos ( people ).

Diseñar el servicio de esta manera tiene una gran ventaja sobre el servicio típico: mapa (...) y componente: patrón "suscribirse (...)". En el mundo real, necesitamos asignar el json a nuestras propiedades en nuestra clase y, a veces, hacemos algunas cosas personalizadas allí. Entonces este mapeo puede ocurrir en nuestro servicio. Y, típicamente, debido a que nuestra llamada de servicio se usará no una vez, sino, probablemente, en otros lugares de nuestro código, no tenemos que realizar esa asignación en algún componente, nuevamente. Además, ¿qué pasa si agregamos un nuevo campo a las personas? ...


Me gustaría agregar que si el objeto que se crea es estático y no llega a través de http, se puede hacer algo así:

public fetchModel(uuid: string = undefined): Observable<string> { if(!uuid) { //static data return Observable.of(new TestModel()).map(o => JSON.stringify(o)); } else { return this.http.get("http://localhost:8080/myapp/api/model/" + uuid) .map(res => res.text()); } }

Editar: para el mapeo Angular 7.xx se debe hacer usando pipe () como se describe aquí ( https://.com/a/54085359/986160 ):

import {of, Observable } from ''rxjs''; import { map } from ''rxjs/operators''; [...] public fetchModel(uuid: string = undefined): Observable<string> { if(!uuid) { //static data return of(new TestModel()); } else { return this.http.get("http://localhost:8080/myapp/api/model/" + uuid) .pipe(map((res:any) => res)) //already contains json } }

de la respuesta a mi pregunta sobre observadores y datos estáticos: https://.com/a/35219772/986160


Observe que está utilizando Map para convertir el objeto de Response sin Response que su Observable base emite en una representación analizada de la respuesta JSON.

Si te entendí correctamente, quieres volver a map . Pero esta vez, convirtiendo ese JSON sin procesar en instancias de su Model . Entonces harías algo como:

http.get(''api/people.json'') .map(res => res.json()) .map(peopleData => peopleData.map(personData => new Person(personData)))

Entonces, comenzaste con un Observable que emite un objeto de Response , lo convertiste en un observable que emite un objeto del JSON analizado de esa respuesta, y luego lo convertiste en otro observable que convirtió ese JSON sin procesar en una matriz de tus modelos.


ACTUALIZACIÓN: 9/24/16 Angular 2.0 Estable

Esta pregunta todavía tiene mucho tráfico, así que quería actualizarla. Con la locura de los cambios de Alpha, Beta y 7 candidatos RC, dejé de actualizar mis respuestas SO hasta que se estabilizaron.

Este es el caso perfecto para usar Subjects y ReplaySubjects

Personalmente, prefiero usar ReplaySubject(1) ya que permite que se pase el último valor almacenado cuando se conectan nuevos suscriptores, incluso cuando llega tarde:

let project = new ReplaySubject(1); //subscribe project.subscribe(result => console.log(''Subscription Streaming:'', result)); http.get(''path/to/whatever/projects/1234'').subscribe(result => { //push onto subject project.next(result)); //add delayed subscription AFTER loaded setTimeout(()=> project.subscribe(result => console.log(''Delayed Stream:'', result)), 3000); }); //Output //Subscription Streaming: 1234 //*After load and delay* //Delayed Stream: 1234

Entonces, incluso si adjunto tarde o necesito cargar más tarde, siempre puedo recibir la última llamada y no preocuparme por perder la devolución de llamada.

Esto también le permite usar la misma secuencia para presionar hacia abajo:

project.next(5678); //output //Subscription Streaming: 5678

Pero, ¿qué sucede si está 100% seguro de que solo necesita hacer la llamada una vez? Dejar temas abiertos y observables no es bueno, pero siempre está ese "¿Qué pasa si?"

Ahí es donde entra AsyncSubject .

let project = new AsyncSubject(); //subscribe project.subscribe(result => console.log(''Subscription Streaming:'', result), err => console.log(err), () => console.log(''Completed'')); http.get(''path/to/whatever/projects/1234'').subscribe(result => { //push onto subject and complete project.next(result)); project.complete(); //add a subscription even though completed setTimeout(() => project.subscribe(project => console.log(''Delayed Sub:'', project)), 2000); }); //Output //Subscription Streaming: 1234 //Completed //*After delay and completed* //Delayed Sub: 1234

¡Increíble! Aunque cerramos el tema, todavía respondió con lo último que cargó.

Otra cosa es cómo nos suscribimos a esa llamada http y manejamos la respuesta. Map es excelente para procesar la respuesta.

public call = http.get(whatever).map(res => res.json())

Pero, ¿y si necesitáramos anidar esas llamadas? Sí, podría usar sujetos con una función especial:

getThing() { resultSubject = new ReplaySubject(1); http.get(''path'').subscribe(result1 => { http.get(''other/path/'' + result1).get.subscribe(response2 => { http.get(''another/'' + response2).subscribe(res3 => resultSubject.next(res3)) }) }) return resultSubject; } var myThing = getThing();

Pero eso es mucho y significa que necesita una función para hacerlo. Ingrese FlatMap :

var myThing = http.get(''path'').flatMap(result1 => http.get(''other/'' + result1).flatMap(response2 => http.get(''another/'' + response2)));

Dulce, el var es un observable que obtiene los datos de la llamada http final.

OK, eso es genial, pero quiero un servicio angular2.

Te tengo:

import { Injectable } from ''@angular/core''; import { Http, Response } from ''@angular/http''; import { ReplaySubject } from ''rxjs''; @Injectable() export class ProjectService { public activeProject:ReplaySubject<any> = new ReplaySubject(1); constructor(private http: Http) {} //load the project public load(projectId) { console.log(''Loading Project:'' + projectId, Date.now()); this.http.get(''/projects/'' + projectId).subscribe(res => this.activeProject.next(res)); return this.activeProject; } } //component @Component({ selector: ''nav'', template: `<div>{{project?.name}}<a (click)="load(''1234'')">Load 1234</a></div>` }) export class navComponent implements OnInit { public project:any; constructor(private projectService:ProjectService) {} ngOnInit() { this.projectService.activeProject.subscribe(active => this.project = active); } public load(projectId:string) { this.projectService.load(projectId); } }

Soy un gran admirador de los observadores y observables, ¡así que espero que esta actualización ayude!

Respuesta original

Creo que este es un caso de uso del uso de un Subjects o en Angular2 el EventEmitter .

En su servicio, crea un EventEmitter que le permite insertar valores en él. En Alpha 45 , debe convertirlo con toRx() , pero sé que estaban trabajando para deshacerse de eso, por lo que en Alpha 46 puede simplemente devolver el EvenEmitter .

class EventService { _emitter: EventEmitter = new EventEmitter(); rxEmitter: any; constructor() { this.rxEmitter = this._emitter.toRx(); } doSomething(data){ this.rxEmitter.next(data); } }

De esta manera tiene el único EventEmitter que ahora pueden empujar sus diferentes funciones de servicio.

Si desea devolver un observable directamente de una llamada, puede hacer algo como esto:

myHttpCall(path) { return Observable.create(observer => { http.get(path).map(res => res.json()).subscribe((result) => { //do something with result. var newResultArray = mySpecialArrayFunction(result); observer.next(newResultArray); //call complete if you want to close this stream (like a promise) observer.complete(); }); }); }

Eso le permitiría hacer esto en el componente: peopleService.myHttpCall(''path'').subscribe(people => this.people = people);

Y meterse con los resultados de la llamada en su servicio.

Me gusta crear la secuencia EventEmitter por sí sola en caso de que necesite acceder a ella desde otros componentes, pero pude ver que ambas formas funcionan ...

Aquí hay un plunker que muestra un servicio básico con un emisor de eventos: Plunkr