Processing an Object During Fetch Returns 'undefined' - javascript

I'm fetching an API of dogs, it returns an object.
I want to make changes in the object before I convert
it to an array and setState() it.
Problem is it returns 'undefined'.
I assume the function is ok because it does work if I run in outside the fetch, or maybe I'm missing something here?
componentDidMount() {
fetch("https://dog.ceo/api/breeds/list/all")
(res => res.json())
.then(res => res.message)
.then(res => this.processReq(res)) // <--- undefined
.then(res => Object.entries(res))
.then(res => this.setState({ allBreeds: res }));
}
processReq = breed =>
Object.keys(breed).forEach(key => {
if (key === "australian") {
breed["shepherd"] = [key];
delete breed[key];
} else if (key === "germanshepherd") {
breed["shepherd"].push("german");
delete breed[key];
}
});
Is there a way to manipulate the object during the fetch?
Or maybe it would be easier to setState() it as an array and then process it?

Actually forEach function doesn't return anything so that's why it's giving undefined, you should change it to:
processReq = breed => {
Object.keys(breed).forEach(key => {
if (key === "australian") {
breed["shepherd"] = [key];
delete breed[key];
} else if (key === "germanshepherd") {
breed["shepherd"].push("german");
delete breed[key];
}
});
return breed;
}

The processReq function doesn't have a return statement, so it just returns undefined. Just put a return breed; on the end of it and you'll be fine.

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 select api response with a condition angular javascript?

I have an api response that gets me a multiple objects and inside that object I have an array called "employes" ,"employes" has an item called "avis" .
I want to select the object when the value inside of employes>recrutments>avis="accepter" .
all the array inside the object have to get the value "avis"="accepter" to select that object.
If one of the employes has a diffrent value of "avis" then the object is decline.
I tried to map on the response and I used every method of JavaScript
getJuction():void{
this.getAlloff.getjuction()
.subscribe(data => {
console.log(data);
this.test = data.map(function(element:any){
return element.employes.map((employe:any)=>employe.recrutements.avis === 'accepter').every((emel:any) => emel === true ) ;
});
console.log(this.test)
var test2 = data.filter((employe:any)=>employe);
console.log(test2)
// var test =data.flat();
// console.log(test)
}, error => console.log(error));
}
This is the result I get.
The only object that has "accepter" for every value gets true
I found the solution, I just changed the method from "map" to "filter" method.
This was the previous code:
getJuction():void{
this.getAlloff.getjuction()
.subscribe(data => {
this.test = data.map(function(element:any){
return element.employes.map((employe:any)=>employe.recrutements.avis === 'accepter').every((emel:any) => emel === true ) ;
});
}, error => console.log(error));
}
This is the new code:
getJuction():void{
this.getAlloff.getjuction()
.subscribe(data => {
this.test = data.filter(function(element:any){
return element.employes.map((employe:any)=>employe.recrutements.avis === 'accepter').every((emel:any) => emel === true ) ;
});
}, error => console.log(error));
}
this.getAlloff.getjuction()
.subscribe(data => {
//this.result some property to store value
this.result = data.map( (item : any) => {
return item.employees.filter((item : any)=> {
return item.recrutements.alves == 'accepter'
})
})
}
try this out if you getting Multiple Object in data

Undefined when i am returning an Object in Javascript

I'm doing a getter in VueX, and when i'm returning an object for another function, i have "undefined".
getId: (state) => (LotofID, id) => {
LotofID.points.map(obj => {
if (obj.id === id)
return (obj);
})
Basically i have a function like that. When i'm showing obj with console.log(obj), i have an object with elements in here. And basically it's working. But when i'm doing a return and i'm trying to get the obj in another function
var test = []
selectedRowKeys.map(obj => {
test.push(this.$store.getters.getId(LotofID, obj))
})
console.log(test)
I have a "undefined" in my variable.
Anyone have an idea of where the problem can be
You should use find method instead of map and return the found item inside your getter:
getId: (state) => (LotofID, id) => {
return LotofID.points.find(obj => obj.id === id)
}

Returning Observable from function

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

JavaScript - ES6 function does not work for some weird reason

I am setting the below function in order to retrieve it after.
However, for some reason, it does not work:
constructor(private nativeStorage: NativeStorage) {
// I am calling it this way:
this.userId = 123;
this.getItem("userId", this.userId);
// If I replace the shortcut by the below it works fine
/* this.nativeStorage.getItem("userId).then(
data => this.userId = data,
error => console.error(error)
); */
}
getItem(itemKey, itemValue) {
return this.nativeStorage.getItem(itemKey).then(
data => itemValue = data,
error => console.error(error)
);
}
I believe that I am missing something here, that's why it doesn't work
You're assigning data to itemValue which is just a copy of this.userId. JS doesn't support pass by reference that could make that possible. Instead you can just use itemKey to assign to the class instance directly like this:
getItem(itemKey) {
return this.nativeStorage.getItem(itemKey).then(
data => this[itemKey] = data, // assign data to this[itemKey] which will be this.userId (in the example above)
error => console.error(error)
);
}
JavaScript is not supporting call by reference. It's only by value arg passing. So values can be updated only by object references only.
In reference to the part/comments where you can't have an async constructor and therefore I extract all the async parts into a factory.
I have no experience yet with ionic, so you should take the following as pseudocode:
import { NativeStorage } from '#ionic-native/native-storage';
function constructor(public userId: String){ }
//and the factory function
//don't know how exactly how to export stuff in that framework
function createById(userId){
return NativeStorage.getItem('userId')
.then(
userId => new YourClass(userId)
error => console.error(error)
)
}
or in the case where you want to assign multiple properties:
//a utility to resolve with { key: Promise<value> } mappings + pretty much everything you throw at it.
//warning: doesn't resolve promises in nested structures (by design),
//stuff like {key: { foo: Promise<value> }}
//ideally you'd put that in a seperate module since it can be handy in many places.
function resolve(obj){
if(Array.isArray(obj)
return Promise.all(obj);
if(typeof obj === "function")
return Promise.resolve().then(obj);
if(!obj || typeof obj !== "object" || "then" in obj && typeof obj.then === "function")
return Promise.resolve(obj);
var keys = Object.keys(obj);
return Promise.all( keys.map(k => obj[k]) )
.then(values => combine(keys, values));
}
//takes two Arrays, a matching set of keys and values and combines that into an object.
function combine(keys, values){
return keys.reduce((acc, key, index) => {
acc[key] = values[index];
return acc;
}, {});
}
const assignTo = target => source => Object.assign(target, source);
//in this case we use assign all async values outside of the constructor
function constructor(){
this.userId = null;
this.userName = null;
}
function createById(userId){
return resolve({
userId: NativeStorage.getItem('userId'),
userName: NativeStorage.getItem('userName'),
//...
}).then(
assignTo( new YourClass() ),
error => console.error(error)
)
}
Or if this is still to much repetition for you:
//a utility to fetch multiple items at once
function getItems(...keys){
return Promise.all( keys.map( key => NativeStorage.getItem(key) ) )
.then(values => combine(keys, values));
}
//and a quick test
getItems("userId", "userName", ...).then(console.log);
//or in the context of the last snippet:
getItems("userId", "userName", ...).then(assignTo( new YourClass() ));
Hope this helps shows you a different approach to your problems.

Categories