Use Observable instead of Promise - javascript

I got this function in one of my servlets:
private setValues() {
this.config.socket.on('config.weather', (values:any) => {
console.log(values);
}
I want to outsource so I get something like this:
private setValues() {
this.config.load('weather').then((values:any) => {
console.log(values);
}
any in the socket Service:
public load(key: string) {
return new Promise(resolve => {
this.socket.on('config.' + key, values => resolve(values));
});
This works for the first call, but when the socket fires again it wont be send to the setValues() function because a Promise only works once.
I think I have to use an Observable, but I have no Idea where to place it.

I used a subject and now everything works fine:
public load(key: string) {
let sub = new Subject();
this.socket.on('config.' + key, values => {
sub.next(values);
});
return sub;
}
and
private setValues() {
this.config.load('weather').subscribe((values:any) => {
console.log(values);
}

Related

How to make sequential service call on success of first service response in Angular

I need to make multiple service call in angular one after other. need to pass the first
service call respose as input to another service.
Here is my component:
Demo(): any {
if (fileToUpload) {
this._voiceboxService.upload(fileToUpload)
.subscribe((res: any) => {
this.text=res.prediction
console.log(res);
});
}
else
console.log("FileToUpload was null or undefined.");
}
}
Here is my Service: i need to call all three service on success of one service and need to
pass first service resposnse as input for next service
upload(fileToUpload: any) {
let input = new FormData();
input.append("file", fileToUpload);
return this.http.post<any>('https://localhost:5001/', input)
language(data: any) {
return this.http.post<any>('https://localhost:5002', data)
}
getDetails(data: any) {
return this.http.post<any>('https://localhost:5003', data)
}
Use mergeMap.
I assume you want to do this in your component:
this._voiceboxService.upload(fileToUpload).pipe(mergeMap(upload =>
this._voiceboxService.language(upload)
.pipe(mergeMap(language => this._voiceboxService.getDetails(language))
))).subscribe((res: any) => {
this.text=res.prediction
console.log(res);
});
You can use map in the end organize your final value result.
You could use any of the RxJS higher order mapping operators like switchMap to map from one observable to another. You could find differences between different mapping operators here.
Service
upload(fileToUpload: any) {
let input = new FormData();
input.append("file", fileToUpload);
return this.http.post<any>('https://localhost:5001/', input).pipe(
switchMap(res => this.language(res)), // <-- `res` = response from previous request
switchMap(res => this.getDetails(res)) // <-- `res` = response from `this.language()`
);
}
language(data: any) {
return this.http.post<any>('https://localhost:5002', data)
}
getDetails(data: any) {
return this.http.post<any>('https://localhost:5003', data)
}
Component
Demo(): any {
if (fileToUpload) {
this._voiceboxService.upload(fileToUpload).subscribe({
next: (res: any) => { // <-- `res` = response from `getDetails()`
this.text = res.prediction
console.log(res);
},
error: (error: any) => {
// handle errors
}
});
} else {
console.log("FileToUpload was null or undefined.");
}
}

How do I unsubscribe correctly from angular service results?

I have a method in the component that calls a service which returns an observable
Component Method code
public upload(file) {
this.Service.ToBase64(files[0])
.subscribe(data => (this.convertedFile = data));
}
This works fine but when I chain unsubscribe to it, it stops working.
With Unsubscribe - This does not work
public upload(file) {
this.Service.ToBase64(files[0])
.subscribe(data => (this.convertedFile = data)).Unsubscribe();
}
Service Code method
convertedFile$: Subject<string> = new Subject<string>();
ToBase64(file: any) {
const myReader = new FileReader();
myReader.onloadend = e => {
this.convertedFile$.next(myReader.result.toString().split(',')[1]);
};
myReader.readAsDataURL(file);
return this.convertedFile$.asObservable();
}
As this a subject, I would like to unsubscribe. How can I do that correctly?
You must declare a Subscription property
First in your component
import { Subscription } from 'rxjs';
Then
fileSubscription: Subscription;
And in your method
public upload(file) {
this.fileSubscription = this.Service.ToBase64(files[0])
.subscribe(data => (this.convertedFile = data));
}
In ngOnDestroy method
ngOnDestroy() {
if (this.fileSubscription) {
this.fileSubscription.unsubscribe();
}
}
Regards
The method is unsubscribe() not Unsubscribe(). But a more elegant way to get a value of observable and destroy the subscription is use the first operator like that:
import { first } from 'rxjs/operators';
public upload(file) {
this.Service.ToBase64(files[0]).pipe(first())
.subscribe(data => (this.convertedFile = data));
}

RXJS6 - return an Observable from a Promise function which returns an Observable?

I have a method getData which returns an Observable<SupportingDocument>.
(code and return value can't be changed as it's an external API).
getData(): Observable<SupportingDocument> {
return of(new SupportingDocument());
}
When a user clicks a button , we actually show him a Modal page . When that modal is closed ( Promise api) - we should call getData() and return the value :
public dialogShow(): Promise<Observable<SupportingDocument>> {
return Promise.resolve(1).then(() => { //modal was closed
return this.getData();
})
}
At the end , I should provide a method show() which should return the value(and errors) that returned from return this.getData(); ( shows()'s return value doesn't have to be an Observable , it can be a promise too).
So I did this :
public show(): Observable<SupportingDocument> {
return new Observable<SupportingDocument>((obs) => {
this.dialogShow().then((res: Observable<SupportingDocument>) => obs.next(res), (res) => obs.error(res));
})
}
Complete code :
//user starts here
public show(): Observable<SupportingDocument> {
return new Observable<SupportingDocument>((obs) => {
this.dialogShow().then((res: Observable<SupportingDocument>) => obs.next(res), (res) => obs.error(res));
})
}
public dialogShow(): Promise<Observable<SupportingDocument>> {
return Promise.resolve(1).then(() => {
return this.getData();
})
}
getData(): Observable<SupportingDocument> {
return of(new SupportingDocument());
}
Question
I think I've over-complicated such a simple task. More - I really don't like the new Observable constructor approach.
Can this problem be solved without using the observable constructor ( including error handling) solution ?
Full demo code
Why don't just wrap the Promise into an Observable (so that you can use all the operators an Observable can provide), and then use a switchMap()?
public dialogShow(): Observable<SupportingDocument> {
return from(Promise.resolve(1)).pipe(switchMap(() => this.getData()));
}
Working StackBlitz

make search in Observable sync

I want to check, if given clientName is present in Observable Collection, but in cause of async run, i don't get "false" return at all. How to transform my function to sync - i would like not to use callbacks - just return true/false
checkIfClientNameIsUnique(clientName: string): boolean {
var isUnique = true;
this.getAll()
.subscribe(clients => {
clients.forEach(client => {
if (clientName == client.name) {
isUnique = false
}
})
});
return isUnique
}
I see three options:
make checkIfClientNameIsUnique to return Promise then you
can use it like checkIfClientNameIsUnique(name).then(isUnique =>
{...})
Load all clients to array on initial state. I suppose you have ClientsService there you can put clients array, then your
checkIfClientNameIsUnique method can be sync and use already loaded
clients array.
3.If you emit to ES6 you can use async await keywords and it will look like this.
checkIfClientNameIsUnique(clientName: string): Promise<boolean> {
return new Promise((resolve, reject) => {
this.getAll()
.subscribe(clients => {
for (let client of clients) {
if (clientName == client.name) {
resolve(false);
break;
}
}
resolve(true);
});
});
}
// ...
async main() {
let isUnique = await checkIfClientNameIsUnique(name);
}

angular2 work with Observable(Http) without reloading

I have a PartnersService that in constructor load list of partners array from server.
this.partners = this._http.get('/app/partners/partners.data.json')
.map(this.extractData)
.catch(this.handleError);
When I get a list of partners, everything OK.
But I need to get partner by ID.
In this case, I use function with callback
getPartner(id:number, callback:(partner:Partner)=>void):void {
this.partners.subscribe(partners=> {
for (let partner of partners) {
if (partner.id == id) {
callback(partner);
}
}
});
}
In browser console, I see that any time when I call subscribe, angular2 send request to server. Can I do something, to not send request any time? And maybe exist better way to create getPartner() function(without callback)?
You could try something like that:
getPartners() {
if (this.partners) {
return Observable.of(this.partners);
} else {
return this._http.get('/app/partners/partners.data.json')
.map(this.extractData)
.catch(this.handleError)
.do(partners => {
this.partners = partners;
});
}
}
getPartner(id:number):Observable<partner> {
this.getPartners().map(partners => {
return partners.find(partner => (partner.id == id));
});
}
And execute the method this way:
this.service.getPartner('some id').subscribe(partner => {
console.log(partner);
});
You could use publishLast() as well to capture the event.
constructor() {
this.partners = this._http.get('/app/partners/partners.data.json')
.map(this.extractData)
.catch(this.handleError)
//shares the subscription with all observers so you don't get repeated
//calls and caches the result.
.publishLast();
//Initiates the http call
this.connection = this.partners.connect();
}
getPartner(id:number):Observable<partner> {
return this.partners
//Convert Observable<partner[]> to Observable<partner>
.flatMap(x => x)
.filter(p => p.id === id);
}

Categories