Como criar um observável a partir de dados estáticos semelhante ao http no Angular?

121

Estou tendo um serviço que tem 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());
        }
    }
}

no construtor do componente, estou me inscrevendo assim:

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

Isso funciona se um objeto vem do servidor, mas estou tentando criar um observável que funcione com a subscribe()chamada fornecida para uma string estática (isso acontece quando testModelService.fetchModel()não recebe um uuid), portanto, há um tratamento perfeito em ambos os casos.

Michail Michailidis
fonte

Respostas:

151

Talvez você possa tentar usar o ofmétodo da Observableclasse:

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
fonte
2
Isso foi incrível! Funcionou! Eu estava tentando muitas coisas como Observable.from () etc. A documentação da API para Observable não é a mais limpa / amigável neste ponto! Obrigado :)
Michail Michailidis
45
Uma coisa se você estiver usando a versão 6, você deve import { of } from 'rxjs';e usar of, em vez de Observable.of.
VIP
2
Para Angular v7.xx não há nenhum .map()resultado de get, então você precisa fazer .pipe(map((res:any) => res.json())). Veja aqui: stackoverflow.com/a/35220045/986160
Michail Michailidis
64

A partir de julho de 2018 e do lançamento de RxJS 6, a nova maneira de obter um Observable de um valor é importar o ofoperador da seguinte maneira:

import { of } from 'rxjs';

e crie o observável a partir do valor, assim:

of(someValue);

Observe que você costumava fazer Observable.of(someValue)like na resposta aceita atualmente. Há um bom artigo sobre as outras alterações do RxJS 6 aqui .

VSO
fonte
Muito obrigada, isso funciona
Sarah
19

As coisas parecem ter mudado 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());
  }
}

A .next()função será chamada em seu assinante.

Niel de Wet
fonte
2
Eu migrei para o Angular 2.1.2 .. O método antigo parece ainda ser suportado .. Você poderia explicar por que essa é a melhor solução ou é a convenção? Em seguida, vou alterá-lo em todos os lugares do meu código e vou aceitar novamente
Michail Michailidis
7
@MichailMichailidis, com um mês de retrospecto, parece-me que ambos são igualmente válidos, a principal diferença é que a solução de Thierry requer que você importe a offunção de rxjs, comoimport 'rxjs/add/observable/of'
Niel de Wet
12

É assim que você pode criar um observável simples para dados 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 resposta seja útil. Podemos usar uma chamada HTTP em vez de dados estáticos.

Balwant Padwal
fonte
você pode atualizar o erro de digitação de observable.subscripe para observable.subscribe
Sudharshan
3

Desta forma, você pode criar observáveis ​​a partir de dados, no meu caso, preciso manter o carrinho 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
fonte