I use angular6, i try get json from server through 5 seconds interval.
JSFIDDLE
Its my service:
getExample(): Observable<any> {
console.log('getExample');
return Observable
.timer(0, 5000)
.flatMap(() => this.httpClient.get('https://jsonplaceholder.typicode.com/posts'))
.map((r) => {
return r;
});
}
Please help fix this code.
PS: more simple service worked without problem
RxJS 6 has updated to use pipeable operators. Also, timer imports from a different path. You should import timer (or interval in this case) directly and use .pipe with the operators that you need. Finally, use mergeMap instead of flatMap.
import { interval } from 'rxjs';
import { mergeMap, map } from 'rxjs/operators';
return interval(5000).pipe(
mergeMap(() => this.httpClient.get('https://jsonplaceholder.typicode.com/posts')),
map((r) => {
console.log(r);
return r;
})
);
Related
I am making two http requests, each return a observable<IProduct>; and I want to combine both into a local object and use the async pipe to bring values from each.
productA$: observable<IProduct>;
productB$: observable<IProduct>;
combinedProds$: ?
this.productA$ = httpCall();
this.productB$ = httpCall();
this.combinedProds$ = combineLatest([
this.productA$,
this.productB$
])
.pipe(
map(([productA, productB]) =>
({ productA, productB}))
);
This issue I'm getting, I don't know what type combinedProds$ should be.
Maybe forkJoin is the one you are looking for ?
forkJoin work best with Http call and I'm using it a lot when dealing with http request
// RxJS v6.5+
import { ajax } from 'rxjs/ajax';
import { forkJoin } from 'rxjs';
/*
when all observables complete, provide the last
emitted value from each as dictionary
*/
forkJoin(
// as of RxJS 6.5+ we can use a dictionary of sources
{
google: ajax.getJSON('https://api.github.com/users/google'),
microsoft: ajax.getJSON('https://api.github.com/users/microsoft'),
users: ajax.getJSON('https://api.github.com/users')
}
)
// { google: object, microsoft: object, users: array }
.subscribe(console.log);
Update
forkJoin return an Observable<any> so you can change your like this
combinedProds$: Observable<any>
I need to write the async validator for the reactive form type in angular.
I have implemented it trough promise. But the issue is the validator triggers for each keystroke it strike the server for every keystroke.For implementing the debounce i have implemented the setTimeout for the promise but the issue i faced is it triggers for after the certain millisecon i have defined.
Finally I have implemented the Observable inside the promise to achive all debounceTime, But the issue i faced here is the debounceTime emits all the events.
For example: If I type 'Prem' from input field the following code triggers the server for four time as timeout works.
If any issue in implemetation of the async validator please clarify me.
//Latest code
static hasDuplicateEmail(formControl: FormControl) {
return new Promise((resolve, reject) => {
return new Observable(observer =>
observer.next(formControl.value)).pipe(
debounceTime(600),
distinctUntilChanged(),
switchMap((value) => {
//server side
return MotUtil.fetch('checkForRegisterEmail', {e: formControl.value});
})
).subscribe((res) => {
return (JSONUtil.isEmpty(res)) ? resolve(null) : resolve({duplicate: true});
});
});
}
The debounceTime should work as mentioned in the Docs.
You are trying to approach it in a difficult way. Validator takes argument - AbstractControl. AbstractControl has property - valueChanges which return stream of changes in your formControl. So here you add debouceTime and later do other operations and finaly return this stream back to FormControl:
hasDuplicateEmail(control: AbstractControl) {
return control.valueChanges.pipe(
debounceTime(600),
switchMap(e =>
this.http.get('checkForRegisterEmail', {e}).pipe(
map((res: any) => JSONUtil.isEmpty(res) ? null : { duplicate: true })
)
)
)
}
As you notice I use HttpClient as it is the way you make HTTP calls in Angular (it is designed to work on streams rather then Promises)
emailValidator(/** params that you need inside switchMap */): AsyncValidatorFn {
return (control: AbstractControl): Observable<ValidationErrors | null> => {
return of(control.value).pipe(
delay(500), //for me works with delay, debounceTime are not working with asyncValidator
filter(email=> !!email), //length or another logic there is not emails with less than 10 characters
distinctUntilChanged(),
switchMap(/** as you need */),
map(exist => (exist ? {duplicate: true} : null)),
catchError(() => of(null))
);
};
}
I am a bit confused with rxjs operators. I have few api calls that return observable:
getCurrentUser(): Observable<any> {
return this.http.get<any>(userUrl);
}
tagsList(): Observable<string[]> {
return this.http.get<string[]>(tagsUrl);
}
timezonesList(): Observable<Timezone[]> {
return this.http.get<Timezone[]>(timezonesUrl);
}
I want to call getCurrentUser() then with result of returning value call action LoadUser(user)
Then after user loads call multiple async requests at the same time:
tagsList(), timezonesList()
And then with results of returning value of them call actions LoadTags(tags), LoadTimezones(timezones)
So it should looks like something like this:
init() {
this.accountsApi.getCurrentUser()
.map((user: User) => this.store.dispatch(new LoadUser({ user })))
.map(
this.commonApi.tagsList(),
this.commonApi.timezonesList(),
this.commonApi.authoriztionServicesList()
)
.map((tags, timezones, authorizationServices) => {
this.store.dispatch(new tagsActions.LoadTags(tags));
this.store.dispatch(new timezonesActions.LoadTimezones(timezones));
this.store.dispatch(new authorizationServicesActions.LoadAuthorizationServices(authorizationServices));
});
}
I know that this operators are wrong. What operators should i use for this? I have already done it with promises, but i am sure that i can do it with rxjs operators in less line of code.
P.S. Also it is interesting for me how i can do this with async / await? Thank you
In your original code you are using map a bit too much, for some use cases you may not need to map.
init() {
return this.accountsApi.getCurrentUser()
.do((user: User) => this.store.dispatch(new LoadUser({ user })))
.forkJoin(
this.commonApi.tagsList(),
this.commonApi.timezonesList(),
this.commonApi.authoriztionServicesList()
)
.do((results) => {
this.store.dispatch(new tagsActions.LoadTags(results[0]));
this.store.dispatch(new timezonesActions.LoadTimezones(results[1]));
this.store.dispatch(new authorizationServicesActions.LoadAuthorizationServices(results[2]));
});
}
forkJoin lets you fire off many observable subscriptions and once all subscriptions produce values you get a single array of observable values back.
The do operator introduces side effects to launch your store actions since you don't want to create any arrays.
In a component, in ngOnInit() I've got two subscriptions to a data service. I want to do some processing once both subscriptions have returned. Whats the best way to do this? I can just process at the end of each, this just seems a little inefficient and won't work for which ever subscription activates first,
Thanks,
Component.TS
ngOnInit()
{
this.dataService.dataA().subscribe((dataAJSON) =>
{
this.dataA= dataAJSON
}
this.dataService.dataB().subscribe((dataBJSON) =>
{
this.dataB= dataBJSON
}
DataService
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class PMDataService
{
constructor(public http : Http)
{
}
dataA()
{
var dataA: any;
var json;
dataA= this.http.get("./assets/dataa.json")
.map(res => res.json());
return dataA
}
dataB()
{
var dataB: any;
var json;
dataB= this.http.get("./assets/datab.json")
.map(res => res.json());
return dataB
}
}
You can use Observable#forkJoin function on the Observables. It emits the last value from each when all observables complete,
Observable.forkJoin(this.dataService.dataA(), this.dataService.dataB())
.subscribe(val => /* val is an array */)
The method used depends on how you want to receive the data:
You can use the zip function. Emits once when all have emitted once. So similar to Promise.all except not on completion.
Observable.zip(obs1, obs2).subscribe((val) => { ... });
You can use the forkJoin function. Emits once when all have completed. So exactly like Promise.all.
Observable.forkJoin(obs1, obs2).subscribe((val) => { ... });
You can use the merge function. Emits in order of emission so could be 1st then 2nd or 2nd then 1st:
obs1.merge(obs2).subscribe((val) => { ... });
You can use concat function. Emits in order 1st then 2nd regardless if 2nd emits first:
obs1.concat(obs2).subscribe((val) => { ... });
It's best practice to split these up into a couple lines for clarity.
const obs1 = Rx.Observable.of(1,2,3);
const obs2 = Rx.Observable.of(1,2,3);
const example = Observable.zip(obs1, obs2);
//const example = Observable.forkJoin(obs1, obs2);
//const example = obs1.merge(obs2);
//const example = obs1.concat(obs2);
example.subscribe(val => { ... });
You could use the operator Zip or CombineLatest from rxjs.
See ReactiveX operators
You could do something like this:
Observable.zip(
this.http.get("./assets/dataa.json"),
this.http.get("./assets/dataa.json")
.take(1)
.map(values => [values[0].json(), values[1].json()])
.subscribe(values => {
// do something with my values
});
You could You can use concat to combine the observables and return a single observable.
Subscribe to observables in order as previous completes, emit values
changed service code
import 'rxjs/add/operator/concat';
export class PMDataService
{
data(){
return this.dataA().concat(this.dataB());
}
// methods dataA and dataB are unchanged, some of the constructor
}
Component code
ngOnInit(){
this.dataService.data().subscribe((dataJSON) =>
{
this.dataA= dataAJSON[0];
this.dataB= dataAJSON[1];
}
}
The function more() is supposed to return an Observable from a get request
export class Collection {
public more = (): Observable<Response> => {
if (this.hasMore()) {
return this.fetch();
} else {
// return empty observable
}
};
private fetch = (): Observable<Response> => {
return this.http.get("some-url").map((res) => {
return res.json();
});
};
}
In this case I can only do a request if hasMore() is true, else I get an error on subscribe() function subscribe is not defined, how can I return an empty Observable?
this.collection.more().subscribe(
(res) => {
console.log(res);
}, (err) => {
console.log(err);
}
);
With the new syntax of RxJS 5.5+, this becomes as the following:
// RxJS 6
import { EMPTY, empty, of } from "rxjs";
// rxjs 5.5+ (<6)
import { empty } from "rxjs/observable/empty";
import { of } from "rxjs/observable/of";
empty(); // deprecated use EMPTY
EMPTY;
of({});
Just one thing to keep in mind, EMPTY completes the observable, so it won't trigger next in your stream, but only completes. So if you have, for instance, tap, they might not get trigger as you wish (see an example below).
Whereas of({}) creates an Observable and emits next with a value of {} and then it completes the Observable.
E.g.:
EMPTY.pipe(
tap(() => console.warn("i will not reach here, as i am complete"))
).subscribe();
of({}).pipe(
tap(() => console.warn("i will reach here and complete"))
).subscribe();
For typescript you can specify generic param of your empty observable like this:
import 'rxjs/add/observable/empty'
Observable.empty<Response>();
RxJS6 (without compatibility package installed)
There's now an EMPTY constant and an empty function.
import { Observable, empty, EMPTY, of } from 'rxjs';
//This is now deprecated
var delay = empty().pipe(delay(1000));
var delay2 = EMPTY.pipe(delay(1000));
Observable.empty() doesn't exist anymore.
Several ways to create an Empty Observable:
They just differ on how you are going to use it further (what events it will emit after: next, complete or do nothing) e.g.:
Observable.never() - emits no events and never ends.
Observable.empty() - emits only complete.
Observable.of({}) - emits both next and complete (Empty object literal passed as an example).
Use it on your exact needs)
In my case with Angular2 and rxjs, it worked with:
import {EmptyObservable} from 'rxjs/observable/EmptyObservable';
...
return new EmptyObservable();
...
Yes, there is am Empty operator
Rx.Observable.empty();
For typescript, you can use from:
Rx.Observable<Response>.from([])
Since all the answers are outdated, I will post the up to date answer here
In RXJS >= 6
import { EMPTY } from 'rxjs'
return EMPTY;
You can return Observable.of(empty_variable), for example
Observable.of('');
// or
Observable.of({});
// etc
Differents way to return empty observable :
Observable.from({});
Observable.of({});
EMPTY
https://www.learnrxjs.io/learn-rxjs/operators/creation/empty
Or you can try ignoreElements() as well
RxJS 6
you can use also from function like below:
return from<string>([""]);
after import:
import {from} from 'rxjs';
Came here with a similar question, the above didn't work for me in: "rxjs": "^6.0.0", in order to generate an observable that emits no data I needed to do:
import {Observable,empty} from 'rxjs';
class ActivatedRouteStub {
params: Observable<any> = empty();
}
Try this
export class Collection{
public more (): Observable<Response> {
if (this.hasMore()) {
return this.fetch();
}
else{
return this.returnEmpty();
}
}
public returnEmpty(): any {
let subscription = source.subscribe(
function (x) {
console.log('Next: %s', x);
},
function (err) {
console.log('Error: %s', err);
},
function () {
console.log('Completed');
});
}
}
let source = Observable.empty();
You can return the empty observable with all different ways but challenge is to to return it with the expected type -
Here is the way to create a empty observable with type -
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(this.setHeaders(req))
.pipe(
catchError((error: HttpErrorResponse) => {
// you write your logic and return empty response if required
return new Observable<HttpEvent<any>>();
}));
}
there is another: EMPTY const
Replaced with the EMPTY constant or scheduled (e.g. scheduled([], scheduler)). Will be removed in v8. (got this form phpstorm hint)