How to use static combineLatest correctly - rxjs

Since RxJS v.6.5, the static combineLatest syntax
combined$ = combineLatest(a$,b$,c$); is deprecated.
Instead you should use following syntax:
combined$ = combineLatest([a$,b$,c$]);
Where they are: a$: Observable<T>, b$: Observable<U>, c$: Observable<V>
This declaration although gives me several linting errors:
Argument type [Observable<ObservableValueOf<Observable<T>>>,
Observable<ObservableValueOf<Observable<U>>>,
Observable<ObservableValueOf<Observable<V>>>] is not assignable to
parameter type [Observable<ObservableValueOf<Observable<T>>>]
So, where is my error?
Thanks a lot.

You should import combineLatest from rxjs instead of rxjs/operators like this:
import { of, combineLatest } from 'rxjs';
const a$ = of(true);
const b$ = of(false);
combineLatest([a$, b$]).pipe(
tap(console.log)
).subscribe();
Hope it helps.

Related

Where is RxJS 6 static merge?

In RxJS 6, how do I import a static merge function for merging a list of Observables?
I want to be able to do:
const merged$ = merge(
obs1$,
obs2$,
obs3$
);
I've tried:
import { merge } from 'rxjs/observable/merge'; and
import { merge } from 'rxjs/operators';
but neither seems to give me what I want.
Importing has been made easy in RxJS 6:
import { merge } from 'rxjs';
You may want to read the official migration guide.
Another useful resource regarding importing in RxJS 6 is this talk by Ben Lesh who is the RxJS lead.
RxJS 7.X
In RxJS v7.X the merge() method is depricated and will be removed un RxJs v8.X, use mergeWith() instead.
See:
https://rxjs.dev/api/operators/mergeWith
https://rxjs.dev/api/operators/merge (depricated)
import { fromEvent } from 'rxjs';
import { map, mergeWith } from 'rxjs/operators';
const clicks$ = fromEvent(document, 'click').pipe(map(() => 'click'));
const mousemoves$ = fromEvent(document, 'mousemove').pipe(map(() => 'mousemove'));
const dblclicks$ = fromEvent(document, 'dblclick').pipe(map(() => 'dblclick'));
mousemoves$.pipe(
mergeWith(clicks$, dblclicks$),
)
.subscribe(x => console.log(x));
// result (assuming user interactions)
// "mousemove"
// "mousemove"
// "mousemove"
// "click"
// "click"
// "dblclick"
(example from api docs)
I believe now when the "creation" classes were removed the recommended way is importing directly from 'rxjs':
import { merge as mergeStatic } from 'rxjs';
Previous alpha version of RxJS 6 used to have 'rxjs/create' file but this has been removed already: https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md#600-alpha3-2018-02-06
However this expects you to use path maps correctly otherwise you'll import a lot of things you don't need. If you don't use path maps or the build process hidden from you you can import directly the correct file:
import { merge as mergeStatic } from 'rxjs/internal/observable/merge';
As of RXJS 6. The merge is in the rxjs/operators
import { map, take, merge, switchMap, filter } from 'rxjs/operators';

I would like to have an observable behaving like a promise

var promise = http.get().toPromise(); gives a promise which executes once.
So no matter how much times promise.then() is called the http request is done only once.
How can I achieve the same with an observable?: var observable = http.get().??? so that obversable.subscribe() only performs the http request one time?
you can use the following rxjs operator 'take' like this
import the operators
import { take } from 'rxjs/operators';
and use it like this
this.http.get(`${this.url}/${agentId}/intents/${intentId}`)
.pipe(take(1),
catchError(error => Observable.throw(error)));
but this will only emit a single value once, the latest value, not stop the Observable from calling the request if you call this function again.
The following code did it:
import { shareReplay } from 'rxjs/operators';
this.http.get("xxx").pipe(shareReplay(1));

Importing a single rxjs operator not working with react and webpack

I am using redux-observable for react app and webpack for bundling.
When I include a specific operator from rxjs like
import 'rxjs/add/operator/mapTo';
it doesn't work and throws error
TypeError: action$.ofType(...).mapTo is not a function.
But when I include complete rxjs library, it works
import 'rxjs';
When importing specific operator, my js bundle does contain mapTo code but the methods are not getting included in Observable prototype. I am using webpack for bundling. Do we have to do anything special for importing specific operator in webpack?
Code:
import { combineEpics } from 'redux-observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/mapTo';
const PING = 'PING';
const PONG = 'PONG';
const pingEpic = action$ => {
const obser = action$.ofType(PING);
return obser.mapTo({ type: PONG });
}
export const epic$ = new BehaviorSubject(combineEpics(pingEpic));
export const createRootEpic = (action$, store) =>
epic$.mergeMap(epic =>
epic(action$, store)
);
Update:
mapTo method is available to BehaviorSubject object (epic$.mapTo is available) but not to ActionsObservable object (action$.mapTo is not a function).
The issue is highly likely to be that you accidentally have two copies of RxJS. This can happen in several situations, but in your specific case it sounds highly likely to a recently reported issue in rxjs. That particular issue was fixed started in 5.5.1 (5.5.2 is now the latest).
Make sure you have RxJS 5.5.1 or above installed--you may need to remove your node_modules and reinstall to get a newer version locally if your semver range is broad. You can also triple check by looking at node_modules/rxjs/package.json the "version" field, usually at the bottom

Redux Observable / RxJS: How to create custom observable?

I'm trying to do websocket setup in an redux-observable epic, and i'm going with an approach similar to this guy: https://github.com/MichalZalecki/connect-rxjs-to-react/issues/1
However, it looks like my first stab at wiring things up isn't working, even though it looks the same as the guy above:
import 'rxjs';
import Observable from 'rxjs';
import * as scheduleActions from '../ducks/schedule';
export default function connectSocket(action$, store) {
return action$.ofType(scheduleActions.CANCEL_RSVP)
.map(action => {
new Observable(observer => {
// do websocket stuff here
observer.next('message text');
});
})
.map(text => {
console.log("xxxxxxxxxxxxx: ", text);
return scheduleActions.rsvpCancelled(1);
});
};
However, I'm getting a Object is not a constructor error:
=== UPDATE ===
Looks like the suggestion to destructure the { Observable } export worked!
Not the only issue is that text doesn't seem to cross over to the next method...
import 'rxjs';
import { Observable } from 'rxjs';
import * as scheduleActions from '../ducks/schedule';
export default function connectSocket(action$, store) {
return action$.ofType(scheduleActions.CANCEL_RSVP)
.map(action => {
new Observable(observer => {
// do websocket stuff here
observer.next('message text');
});
})
.map(text => {
console.log("xxxxxxxxxxxxx: ", text); // prints undefined
return scheduleActions.rsvpCancelled(1);
});
};
In RxJS v5, the Observable class is available as named export, not the default export.
import { Observable } from 'rxjs';
Importing from regular rxjs will also import all of RxJS (adding all operators to the Observable prototype). This is described in the docs here. If you'd prefer to be more explicit and only import Observable itself you can import it directly at rxjs/Observable:
import { Observable } from 'rxjs/Observable';
Separately, you have a couple issues with the way you're mapping your custom Observable.
First Issue
You're not actually returning it. hehe. You're missing a return statement (or you can remove the curly braces and use arrow function implicit returns).
Second Issue
The regular .map() operator does not do anything special when you return an Observable. If you want the custom Observable to be subscribed to and flattened you'll need to use an operator that does flattening of some kind.
The most common two are mergeMap (aka flatMap) or switchMap.
action$.ofType(scheduleActions.CANCEL_RSVP)
.mergeMap(action => {
return new Observable(observer => {
// do websocket stuff here
observer.next('message text');
});
})
Which operator you need depends on your desired behavior. If you're not yet familiar, you can check out the documentation on the various operators or jump straight to the mergeMap and switchMap docs.
If you're adventurous, RxJS v5 does have WebSocket support out of box you can try with Observable.webSocket(). It's not documented very well, but you could also take a look at the unit tests, and for simple read-only unidirectional streaming it's pretty self explanatory--provide the URL and subscribe. It's actually incredibly powerful, if you can figure out how to use it, that is. Supports bi-directional, multiplex aka complex multiple input/output channels through a single socket. We use it at Netflix for several internal tools with thousands of rps.
You can take a look at Demo. Visit at Create Custom Observable

RxJs subscribe works but map does not

I have an ngrx store like this:
export default compose(storeLogger(), combineReducers) ({
auth: authReducer,
users: userReducer
});
In a service I try to do the following:
import 'rxjs/add/operator/do';
#Injectable()
export class ApiService {
constructor(private _http: Http, private _store: Store<AppState>, private _updates$: StateUpdates<AppState>) {
_store.select<Auth>('auth').do(_ => {console.log("token:" +_.token)});
}
No operator works except subscribe. Why?
If you are asking in general why this occurs then here is an explanation by Andre Stalz on his blog.
http://staltz.com/how-to-debug-rxjs-code.html
Because Observables are lazy until you subscribe, a subscription triggers the operator chain to execute. If you have the console.log inside a do and no subscription, the console.log will not happen at all.
So basically this is the typical behavior of operators.
In your example you have attached a "do" operator. With no subscription to the observable that the "do" operator returns it will not fire. Most operators won't fire until there is at least one subscription on the observable the operator returns. Map is one of those.
http://jsbin.com/bosobuj/edit?html,js,console,output
var source = new Rx.BehaviorSubject(3);
source.do(x=>console.log(x));
var source2 = new Rx.BehaviorSubject(5);
source2.do(x=>console.log(x)).subscribe(x=> x);
the output is 5 because only source2 "do" is executed.

Resources