¿Cómo crear un observable a partir de datos estáticos similar a http uno en Angular?

121

Tengo un servicio que tiene este método:

export class TestModelService {

    public testModel: TestModel;

    constructor( @Inject(Http) public http: Http) {
    }

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

en el constructor del componente me suscribo así:

export class MyComponent {
   testModel: TestModel;
   testModelService: TestModelService;

   constructor(@Inject(TestModelService) testModelService) {
      this.testModelService = testModelService;

      testService.fetchModel("29f4fddc-155a-4f26-9db6-5a431ecd5d44").subscribe(
          data => { this.testModel = FactModel.fromJson(JSON.parse(data)); },
          err => console.log(err)
      );
   }
}

Esto funciona si un objeto proviene del servidor, pero estoy tratando de crear un observable que funcione con la subscribe()llamada dada para una cadena estática (esto sucede cuando testModelService.fetchModel()no recibe un uuid), por lo que hay un manejo perfecto en ambos casos.

Michail Michailidis
fuente

Respuestas:

151

Quizás podrías intentar usar el ofmétodo de la Observableclase:

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

public fetchModel(uuid: string = undefined): Observable<string> {
  if(!uuid) {
    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());
  }
}
Thierry Templier
fuente
2
¡Eso fue asombroso! ¡Funcionó! Estaba probando muchas cosas como Observable.from (), etc. ¡La documentación de la API para Observable no es la más limpia / fácil de usar en este momento! Gracias :)
Michail Michailidis
45
Una cosa si está usando la versión 6, debe import { of } from 'rxjs';usar y usar of, en lugar de Observable.of.
vip
2
Para Angular v7.xx no hay .map()un resultado de get, por lo que debe hacerlo .pipe(map((res:any) => res.json())). Vea aquí: stackoverflow.com/a/35220045/986160
Michail Michailidis
64

A partir de julio de 2018 y el lanzamiento de RxJS 6, la nueva forma de obtener un Observable a partir de un valor es importar el ofoperador así:

import { of } from 'rxjs';

y luego crea lo observable a partir del valor, así:

of(someValue);

Tenga en cuenta que solía tener que hacer Observable.of(someValue)como en la respuesta actualmente aceptada. Hay un buen artículo sobre los otros cambios de RxJS 6 aquí .

VSO
fuente
Muchas gracias, esto funciona
Sarah
19

Las cosas parecen haber cambiado desde Angular 2.0.0

import { Observable } from 'rxjs/Observable';
import { Subscriber } from 'rxjs/Subscriber';
// ...
public fetchModel(uuid: string = undefined): Observable<string> {
  if(!uuid) {
    return new Observable<TestModel>((subscriber: Subscriber<TestModel>) => subscriber.next(new TestModel())).map(o => JSON.stringify(o));
  }
  else {
    return this.http.get("http://localhost:8080/myapp/api/model/" + uuid)
            .map(res => res.text());
  }
}

La .next()función se llamará a su suscriptor.

Niel de Wet
fuente
2
He migrado a Angular 2.1.2 .. La forma antigua parece que todavía se admite .. ¿Podría explicar por qué esta es una mejor solución o es la convención? Luego lo cambiaré en todos los lugares de mi código y lo volveré a aceptar .. Gracias
Michail Michailidis
7
@MichailMichailidis, con un mes de retrospectiva, me parece que ambos son igualmente válidos, la principal diferencia es que la solución de Thierry requiere que importe la offunción de rxjs, comoimport 'rxjs/add/observable/of'
Niel de Wet
12

Así es como puede crear un observable simple para datos estáticos.

let observable = Observable.create(observer => {
  setTimeout(() => {
    let users = [
      {username:"balwant.padwal",city:"pune"},
      {username:"test",city:"mumbai"}]

    observer.next(users); // This method same as resolve() method from Angular 1
    console.log("am done");
    observer.complete();//to show we are done with our processing
    // observer.error(new Error("error message"));
  }, 2000);

})

to subscribe to it is very easy

observable.subscribe((data)=>{
  console.log(data); // users array display
});

Espero que esta respuesta sea de ayuda. Podemos usar una llamada HTTP en lugar de datos estáticos.

Balwant Padwal
fuente
¿Puede actualizar el error tipográfico de observable.subscripe a observable.subscribe
Sudharshan
3

De esta manera puede crear Observable a partir de datos, en mi caso necesito mantener el carrito de compras:

service.ts

export class OrderService {
    cartItems: BehaviorSubject<Array<any>> = new BehaviorSubject([]);
    cartItems$ = this.cartItems.asObservable();

    // I need to maintain cart, so add items in cart

    addCartData(data) {
        const currentValue = this.cartItems.value; // get current items in cart
        const updatedValue = [...currentValue, data]; // push new item in cart

        if(updatedValue.length) {
          this.cartItems.next(updatedValue); // notify to all subscribers
        }
      }
}

Component.ts

export class CartViewComponent implements OnInit {
    cartProductList: any = [];
    constructor(
        private order: OrderService
    ) { }

    ngOnInit() {
        this.order.cartItems$.subscribe(items => {
            this.cartProductList = items;
        });
    }
}
Rahul Dadhich
fuente