Jak utworzyć Observable z danych statycznych, podobnie jak http w Angular?

121

Mam usługę, która ma tę metodę:

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

w konstruktorze komponentu subskrybuję w ten sposób:

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

Działa to, jeśli obiekt pochodzi z serwera, ale próbuję utworzyć obserwowalny, który będzie działał z podanym subscribe()wywołaniem statycznego ciągu (dzieje się tak, gdy testModelService.fetchModel()nie otrzymuje uuid), więc w obu przypadkach jest bezproblemowa obsługa.

Michail Michailidis
źródło

Odpowiedzi:

151

Być może mógłbyś spróbować użyć ofmetody Observableklasy:

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
źródło
2
To było niesamowite! Zadziałało! Próbowałem wielu rzeczy, takich jak Observable.from () itp. Dokumentacja API dla Observable nie jest obecnie najczystsza / najbardziej przyjazna dla użytkownika! Dzięki :)
Michail Michailidis
45
Jedna rzecz, jeśli używasz wersji 6, musisz import { of } from 'rxjs';i używać ofzamiast Observable.of.
vip
2
W przypadku Angular v7.xx nie ma .map()wyniku get, więc musisz to zrobić .pipe(map((res:any) => res.json())). Zobacz tutaj: stackoverflow.com/a/35220045/986160
Michail Michailidis
64

Od lipca 2018 r. I premiery RxJS 6nowego sposobu uzyskania Observable z wartości jest zaimportowanie ofoperatora w następujący sposób:

import { of } from 'rxjs';

a następnie utwórz obserwowalne z wartości, na przykład:

of(someValue);

Zwróć uwagę, że Observable.of(someValue)w aktualnie zaakceptowanej odpowiedzi musiałeś postępować podobnie. Jest dobry artykuł na innych RxJS 6 zmian tutaj .

VSO
źródło
Dziękuję bardzo, to działa
Sarah
19

Wydaje się, że sytuacja uległa zmianie od czasu 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());
  }
}

.next()Funkcja zostanie wywołana na abonenta.

Niel de Wet
źródło
2
Migrowałem do Angulara 2.1.2. Wydaje się, że stary sposób jest nadal obsługiwany .. Czy mógłbyś wyjaśnić, dlaczego jest to lepsze rozwiązanie, czy jest to konwencja? Następnie zmienię to we wszystkich miejscach w moim kodzie i ponownie zaakceptuję .. Dzięki
Michail Michailidis
7
@MichailMichailidis, z miesięczną retrospekcją, wydaje mi się, że oba są równie ważne, główna różnica polega na tym, że rozwiązanie Thierry'ego wymaga zaimportowania offunkcji rxjs, na przykładimport 'rxjs/add/observable/of'
Niel de Wet
12

W ten sposób można utworzyć proste obserwowalne dla danych statycznych.

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

Mam nadzieję, że ta odpowiedź jest pomocna. Zamiast danych statycznych możemy użyć wywołania HTTP.

Balwant Padwal
źródło
czy możesz zaktualizować literówkę z
observable.subscripe
3

W ten sposób możesz stworzyć Observable z danych, w moim przypadku muszę prowadzić koszyk:

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
źródło