Returning Observable from function - javascript

I have the following function in typescript:
getConfigurations() {
let sessionConfig = sessionStorage.getItem('config');
if(config)
return of(sessionConfig);
else {
this.dataService.getRoute('configurations').subscribe(
route => this.http.get<any[]>(route.ToString()).subscribe(
result => {
sessionStorage.setItem('config', result);
return of(result);
},
error => {
alert(error);
}),
error => {
alert(error);
}
);
}
}
The function should return a string if the sessionStorage key is already existent or use dataService to retrieve the value from back end and then set the value in the session. I'd like to return the value set in sessionStorage too (result), but I couldn't find a way to do it.
The function getRoute from dataService is:
getRoute(service: string){
return this.http.get('urlToMyBackendWebApi');
}
Where http is the Angular HttpClient.
How could I get the value returned from getConfigurations() ?
I tried to subscribe to getConfigurations. I have no problems with the if condition (the string sessionConfig is returned) but how to get the result from the else condition? Should I return an observable of the entire part? In this case, how could I read the return?

Don't subscribe to the observable, return it, and use the tap operator to store the response:
getConfigurations() {
let sessionConfig = sessionStorage.getItem('config');
if(config)
return of(sessionConfig);
else {
return this.dataService.getRoute('configurations').pipe(
mergeMap(route => this.http.get<any[]>(route.ToString()),
tap(result => sessionStorage.setItem('config', result))
);
}
}

Related

Proper way of dealing with returning from a fetch

I'm a bit new to coding in a JS/TS way and I just wanted to know the best practice when it comes to returning and handling void and values that come from a fetch. In short, I'd like to use fetch to retrieve a JSON file somewhere, extract some relevant info, and return a dict.
async function doSomething() {
const response = fetch(...)
.then(response =>
response.json().then(data => ({
data: data,
response: response.ok
}))
)
.then(data => {
if (!data.response) {
console.warn("Response was not ok...")
return null
} else if (data.data["results"] == 0) {
console.info("Returned no results")
return null
} else {
const returned = {
name: data.data["stuff"],
thing: data.data["other"]
}
return returned
}
})
.catch(error => console.error(`${error}`))
return response
TS returns an error saying that Property 'name' does not exist on type 'void | {...} when I want to use the values of the dict. The error, I completely understand. When using the function I try to do type checking to handle when it returns void, but it still raises an error for something like this:
const request = await getQuery("movie", query)
if (request === undefined || request === null) return "I wasn't able to find your query."
const data = {
name: request.name
}
}
I'm just wondering what's the best way to write and handle void, and using the dict values.
I wouldn't have the function do too much. Have it concentrate on returning some data, and let the function that calls it deal with how that data is going to be used.
If you're going to use async/await you should be consistent. Mixing async with then doesn't make a lot of sense. This way you're either going to return some data, or throw an error.
async function getData(endpoint) {
try {
const response = await fetch(endpoint);
if (response.ok) {
const { data } = await response.json();
return data;
} else {
throw new Error('Response error.');
return undefined;
}
} catch (err) {
console.warn(err);
}
}
async function main() {
const endpoint = 'http://example.com';
const data = await getData(endpoint);
if (data && data.results) {
console.log(data.results.name);
} else {
console.warn('No results');
}
}
main();

How to use results from asynchronous function in Angular

I'm trying to use the results from my asynchronous function inside another function, but it keeps saying the result is undefined.
This is my structure of my calling function:
async callingFn() {
let value = await calledFn();
console.log(value);
}
This is the structure of the function I'm calling:
calledFn() {
this.myService.getHttpResponse().subscribe(
(resp: any) => {
var values = JSON.parse(resp);
console.log(values);
return values;
},
error => {
console.error(error);
}
);
}
When I log values in calledFn, the result is as expected. However, when I log the return value of calledFn in callingFn, it returns undefined.
What am I doing wrong?
You are not returning from the calledFn. The subscription method is returning though.return the http service call
calledFn() {
return this.myService.getHttpResponse().subscribe(
(resp: any) => {
var values = JSON.parse(resp);
console.log(values);
return values;
},
error => {
console.error(error);
}
);
}

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

Not able to use array.every() correctly and getting wrong result

I am trying to validate an array of Ids, for validation I am using custom validator in nestjs project. I am passing the array of ids in a callback function to my service class to query from the database whether id exists in the table or not and returns a boolean value. Every time I am receiving boolean true even if I am passing the wrong id.
Here is the validation function in a custom validator
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments, registerDecorator, ValidationOptions } from "class-validator";
import { DeviceService } from "../device/device.service";
import { Injectable } from "#nestjs/common";
#ValidatorConstraint({ async: true })
#Injectable()
export class DevicesArrayValidatorConstraint implements ValidatorConstraintInterface {
constructor(private deviceService: DeviceService) { }
async validate(devices: Array<number>, args: ValidationArguments) {
let result = devices.every(async (deviceId) => await this.deviceService.validateDevice(deviceId));
if(result){
return true;
}
else{
return false;
}
}
defaultMessage(args: ValidationArguments) { // here you can provide default error message if validation failed
return "Here is an error";
}
}
export function ValidDevices(validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
registerDecorator({
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: DevicesArrayValidatorConstraint
});
};
}
Its the function from Service Class
async validateDevice(deviceId: number) {
try {
let result = await this.deviceRepository.findOneOrFail(deviceId)
if(result){
console.log(`In try block,This is id ${ deviceId}`)
}
} catch (error) {
return false;
}
return true;
}
If I am passing an array of devices: [1,4], where 1 is valid and 4 is invalid. I am getting a double boolean result if I console.log() the return value.
attaching the console message
every doesn't understand async functions. It just sees the promise that's returned as a truthy value.
You have a couple of options:
If you want to validate all of the devices in parallel, then check the result:
const validityFlags = await Promise.all(devices.map(deviceId => this.deviceService.validateDevice(deviceId)));
let result = validityFlags.every(Boolean);
Or if you want to validate each device in series, not bothering with later ones if you know an earlier one is invalid:
let result = true;
for (const deviceId of devices) {
const valid = await this.deviceService.validateDevice(deviceId);
if (!valid) {
result = false;
break;
}
}

declare promise type in typescript of a function

I saw this code somewhere, just curious, why need to specify Promise in the return type? isn't the function return data which is an object? and what's the | null for?
const getSomething = async (
id: string
): Promise<UserData | null> => {
try {
const { data } = await axios.get(
`${API}/user?id=${id}`
);
return data;
} catch (err) {
if (err.response) {
return err.response.data;
}
return null;
}
};
Async functions always return Promises - that way, the asynchronous awaits can be waited for inside the function, and the result can be used outside the function.
Here, the getSomething tries to retrieve data from an axios call. If the call succeeds, the data is just returned:
return data;
But if the call doesn't succeed, it'll return one of the following instead:
if (err.response) {
return err.response.data;
}
return null;
If the axios call throws, and there is no err.response property, then null will be returned. If you left out the | null, the getSomething function wouldn't be typed properly.

Categories