VueJS: Properties of array undefined after fetching data with axios - javascript

Currently I try to develope something with VueJS where I fetch data using Axios and push it into an array.
This is my data object
data() {
return {
uid: [], // Each element contains a JSON containing the node and an array containg UID and operator name
timer: null,
tasks: [],
nodes: [
'assembler',
'device'
]
}
In created I call functions for fetching data via axios
created: function() {
// Get current uids and tasks, if there are any
this.fetchUID()
this.fetchTasks()
}
And this are my methods
methods: {
fetchUID() {
var obj = {}
this.nodes.forEach(node =>
axios.get('http://localhost:8080/' + node)
.then(res => res.data.length > 0 ? obj[node] = [res.data[0].id, res.data[0].operator.name] : console.log("No data found for " + node +
". It seems there is no instance of " + node))
.catch(err => console.log(err))
)
this.uid.push(obj)
},
fetchTasks() {
// console log for testing
console.log(this.uid[0].assembler)
}
}
console.log(this.uid[0].assembler) returns undefined though I can see in the VueJS developer console that uid[0].assembler is defined and should return something. Why does it behave like it does and how can I fix this?

fetchUID is async so execute fetchTasks after completing execution of fetchUID
created: function() {
// Get current uids and tasks, if there are any
this.fetchUID()
// this.fetchTasks() to be executed later
},
methods: {
fetchUID() {
var obj = {}
this.nodes.forEach(node =>
axios.get('http://localhost:8080/' + node)
.then(res => res.data.length > 0 ? obj[node] = [res.data[0].id, res.data[0].operator.name] : console.log("No data found for " + node +
". It seems there is no instance of " + node))
.catch(err => console.log(err))
)
this.uid.push(obj);
this.fetchTasks(); // Execute here
},
fetchTasks() {
// console log for testing
console.log(this.uid[0].assembler)
}
}

I've finally found the answer, the issue lies in this part of the code
fetchUID() {
var obj = {}
this.nodes.forEach(node =>
axios.get('http://localhost:8080/' + node)
.then(res => res.data.length > 0 ? obj[node] = [res.data[0].id, res.data[0].operator.name] : console.log("No data found for " + node +
". It seems there is no instance of " + node))
.catch(err => console.log(err))
)
this.uid.push(obj)
}
The problem is the forEach() as it doesn't really work with async/await. This should do the trick
async fetchUID() {
for(let node of this.nodes) {
try {
const { data } = await axios.get(`http://localhost:8080/${node}`);
if(data.length > 0)
this.uid[node] = [data[0].id, data[0].operator.name];
else
console.log(`No data found for ${node}. It seems there is no instance of ${node}`)
} catch (error) {
// error handling
}
}
}

Related

Why is my function returning undefined despite printing out correctly

The code
the function returning
async getData(key, setHook) {
try {
await AsyncStorage.getItem(key).then((response) => {
console.log("getData response: " + response); // prints out correctly
setHook(response); // sets my hook as undefined?
})
} catch(e) {
console.log("AsyncStorage getData: error: " + e);
}
}
the function receiving
const key = 'key';
const Home = ( {navigation} ) => {
...
const [totalBreaks, setTotalBreaks] = useState('0'); // the hook I use in the above function
// on mount setCounter
useEffect(() => {
setCounter();
}, []);
async function setCounter () {
await asyncStorageInterface.getData(key, setTotalBreaks);
console.log("total breaks: " + totalBreaks); // returns undefined on mount... when it shouldn't
if(totalBreaks === null || totalBreaks === undefined) {
await asyncStorageInterface.storeData(key, '0');
await asyncStorageInterface.getData(key, setTotalBreaks);
}
console.log("total breaks: " + totalBreaks);
}
Problem
I have no idea what the problem is... I spent almost 6 hours trying to fix this, can someone please help me out? And please explain what the problem is in depth if that's possible so that I can document it somewhere. Thanks.
your totalBreaks was read before you set it. it's as simple as:
const result = {};
const {val} = result;
result.val = 'foo';
console.log(val); // you will still get undefined.
This is not related to asynchronous

Back4app Parse Server Retrieved ObjectId

hi i wonder why i cannot retrieve an objectId from this json object even i can printout the stringify on console.
I can retrieve all other column with no problem but not objectId. It happen to all table in my back4app Parse server.
i need the objectId in order to update certain column in my program
below is my code
1)
const parseQuery = new Parse.Query("User");
parseQuery.equalTo("username", "Azha");
let queryResult = await parseQuery
.find()
.then((results) => {
results.forEach((prod) => {
//if i change below to prod.get("objectId") error undefined appear
console.log("Product ID Available : " + prod.get("username"));
});
})
.catch((error) => {
console.log(error);
});
const parseQuery = new Parse.Query("User");
parseQuery.equalTo("username", "Azha");
try {
let todos = await parseQuery.find();
if (todos.length > 0) {
//if i change below to todos[0].get("objectId") error undefined appear
console.log("yes Approval : " + todos[0].get("companyname"));
} else {
console.log("No Approval");
}
console.log("- value is : " + JSON.stringify(todos));
console.log("----------------------");
} catch (error) {
Alert.alert("Error!", error.message);
}
below is the json printout
[{"sessionToken":"r:d9166aa9d7143463c46725d095b53946","username":"Azha","createdAt":"2021-09-21T15:27:01.088Z","updatedAt":"2021-10-10T13:01:27.126Z","companyname":"XXX","fullname":"XXX","email":"azha#abc.com.my","emailVerified":true,"accesslevel":"Maintenence","companydivision":"Maintenence","position":"Technician","phonenumber":"999","userteam":"B","useremail":"azha#abc.com.my","ACL":{"*":{"read":true},"IuBGmCtxyu":{"read":true,"write":true}},"objectId":"IuBGmCtxyu"}]
Yes i just found my solution. Using object1 below:
const parseQuery = new Parse.Query("User");
parseQuery.equalTo("username", "Azha");
try {
let todos = await parseQuery.find();
var object1 = JSON.parse(JSON.stringify(todos));
console.log("2- value is : " + object1[0].objectId);
} catch (error) {
Alert.alert("Error!", error.message);
}

How to save thousand data in Parse Platform NodeJS

I am new to the parse platform and i'm trying to insert 81000 rows of data in to the Parse DB, here the code
const uri = "/the.json"
const res = await axios.get(uri)
const dataresult = Object.keys(res.data)
if (dataresult.length > 0) {
res.data.forEach(function (datakp) {
var kp = new Parse.Object("theClass");
kp.save(datakp)
.then((res) => {
console.log('oke ' + res.id)
}),
(error) => {
console.log('err : '+ error.message)
}
})
}
There is no error in console log, and no data is saved in Parse DB, but if I only insert 1000 rows, it will save to the database.
EG:
if (dataresult.length > 0) {
res.data.forEach(function (datakp, index) {
if (index < 1000) {
var kp = new Parse.Object("theClass");
kp.save(datakp)
.then((res) => {
console.log('oke ' + res.id)
}),
(error) => {
console.log('err : '+ error.message)
}
})
}
}
Thank You
UPDATE
I fix this case based on answer #davi-macĂȘdo
here a complete code
const uri = "/the.json"
const res = await axios.get(uri)
const dataresult = Object.keys(res.data)
const objs = [];
const theKP = Parse.Object.extend("theClass")
if (dataresult.length > 0) {
res.data.forEach(function (datakp) {
var thekp = new theKP()
thekp.set(datakp)
objs.push(thekp);
})
}
Parse.Object.saveAll(objs)
.then((res) => {
console.log('oke updated ' + dataresult.length)
}),
(error) => {
console.log('err : '+ error.message)
}
The most efficient way is using Parse.Object.saveAll function. Something like this:
const uri = "/the.json"
const res = await axios.get(uri)
const dataresult = Object.keys(res.data)
const objs = [];
if (dataresult.length > 0) {
res.data.forEach(function (datakp) {
objs.push(new Parse.Object("theClass", datakp));
})
}
Parse.Object.saveAll(objs)
.then((res) => {
console.log('oke ' + res.id)
}),
(error) => {
console.log('err : '+ error.message)
}
Anyways, since you have no error and no data currently being saved, you might be kitting some memory limit. So that's something you also need to be aware about.
You're probably hitting rate limits, I can't imagine saving 81,000 records in one shot is normal behaviour for many applications.
I looked through the documentation and couldn't find anything that might mention a save limit, however sending 1000 requests would trigger most rate limit protection

Unhandled Rejection outside Promise?

So basically I am running some code that queries a graphql api, and checks whether the data field inside is null (meaning there are no hits for the query), like so:
// check if the items have available data.
// if not, throw an error message saying which ones did not have data.
const testIfDataInDB = await Promise.all(objIDs.map(objID => {
return fetch("/api/graphql", {
method: "POST",
headers: headers,
body: JSON.stringify({
query: "query get_object_with_obj_number($objectNumber: String!) { constructionDetail(objectNumber: $objectNumber) { objectNumber } }",
variables: {
objectNumber: objID
}
}
)
}).then(async (res) => {
return {
responseData: await res.json(),
objID: objID
}
}
)
}));
const itemsDataNotFound = testIfDataInDB.filter(o =>
o.responseData?.data?.constructionDetail === null);
let errString = "";
if (itemsDataNotFound.length > 0) {
itemsDataNotFound.forEach(obj => {
errString = errString + `${obj.objID}, `;
});
errString = errString.slice(0, errString.length - 2);
console.log(errString);
throw new Error(errString);
}
// ... do some object transformations ...
// proceed to post some items into another db using fetch.
const response = await Promise.all(objectsArr.map((obj, index) => {
const body = JSON.stringify(obj);
if (update && index === 0) {
const fetchUrl = `${baseFetchUrl}/${parentItemMetadata._id}`
return fetch(
fetchUrl, {
method: "PUT",
headers: headers,
body: body
}
).then(res => res.json())
}
return fetch(
baseFetchUrl, {
method: "POST",
headers: headers,
body: body
}
).then(res => res.json())
}))
console.log(response);
return response;
}
full code for this part
and the way im calling this code inside my react component:
//defined in parent
const saveMultipleItems = async (
objIDs: string[],
update: boolean
) => {
const parentItemMetaData: TypeLabelItemMetaData = {
createdBy: currentItem?.createdBy || "",
createdAt: currentItem?.createdAt || "",
updatedBy: currentItem?.updatedBy || "",
updatedAt: currentItem?.updatedAt || "",
_id: currentItem?._id || "",
collection: currentItem?.collection || ""
}
try {
saveMultiple(
objIDs,
labelType,
values as TypeLabelState,
parentItemMetaData,
user,
update
)
} catch (e) {
console.warn(e.message);
} finally {
fetchItems();
}
// called in child component
onSubmit={(e) => {
e.preventDefault();
console.log("submitting a series")
try {
const pNumbersArray = generateArray(fromObjNumber, toObjNumber);
saveSeriesFn(pNumbersArray, editMode);
} catch (e) {
console.log("catched error")
alert("Saving series failed with message " + e.message);
}
}
}
My plan was to throw an error, and react to this error somewhere where I can show an alert saying that some items are not available to be saved, and abort the saving operation. I kn
I know this may not be the cleanest way to do this (I am also very grateful for sugestions). The problem I am having right now, is that the app crashes with the following:
Unhandled Rejection (Error): P18100405117, P18100405118, P18100405119
saveMultiple
src/app/src/api/savemultiple.ts:70
67 | });
68 | errString = errString.slice(0, errString.length - 2);
69 | console.log(errString);
70 | throw new Error(errString);
| ^ 71 | }
72 |
73 | const objectsArr: SaveTemplateObjType[] = objIDs.map((objID, index) => {
I thought I was not inside a Promise at the moment I threw this Error?
Async/Await is a synthetic sugar for Promises
Your code states: const saveMultiple = async(...
An Async function will always return a Promise. (see refs below)
Your try/catch doesnt take affect in:
try {
saveMultiple(
objIDs,
labelType,
values as TypeLabelState,
parentItemMetaData,
user,
update
)
} catch (e) {
console.warn(e.message);
} finally {
fetchItems();
}
because saveMultiple is async. you need to use:
saveMultiple(
objIDs,
labelType,
values as TypeLabelState,
parentItemMetaData,
user,
update
).catch((e) => {
console.warn(e.message);
}).finally(() => {
fetchItems();
})
From MDN:

multiple http.post in Angular

I am trying to send an http.post request for each element of an array, my method works well, but when I subscribe, it does it for each of the requests, if someone could help me optimize this, I will I would really appreciate it, here I leave the snippets of my code.
component.ts
saveExclusion() {
this.indForm.value.Centers.forEach(element => {
for (const days of this.exclusionDays) {
delete days.horadesde;
delete days.horahasta;
delete days.id;
for (const key in days) {
if (days[key] === true) {
days[key] = true;
}else if (days[key] === false) {
delete days[key];
}
}
}
const valueForm = this.indForm.value;
valueForm.ResourceId = this.idResource;
valueForm.TimeZoneId = 'America/Santiago';
valueForm.CenterId = element;
this.exclusionFunc = false;
this.apiFca.saveNew(valueForm, this.exclusionDays)
.pipe(last()).subscribe((res: any) => {
console.log(res)
if (res === '200') {
this.successMessage = true;
this.exclusionDays = [];
this.indForm.reset();
this.ngOnInit();
setTimeout(() => {
this.successMessage = false;
}, 3000);
}
}, err => {
console.log('error', err);
});
});
}
service.ts
saveNew(exclusionData, daysBlock) {
let reason = '';
const dt = new Date();
const n = dt.getTimezoneOffset();
const tz = new Date(n * 1000).toISOString().substr(14, 5);
if (exclusionData.OtherReason) {
reason = exclusionData.ExclusionReason + ' ' + exclusionData.OtherReason;
} else {
reason = exclusionData.ExclusionReason;
}
if (exclusionData.ExclusionType !== 'Partial' ) {
daysBlock = [];
}
const data = {Exclusion: new ExclusionClass(
[],
reason,
exclusionData.ExclusionType,
exclusionData.Repetition,
exclusionData.CenterId,
exclusionData.ProfessionalName,
exclusionData.ResourceId,
daysBlock,
exclusionData.TimeZoneId,
'Exclude',
exclusionData.Unit,
exclusionData.ValidFrom + 'T' + exclusionData.ValidTimeFrom + ':00-' + tz,
exclusionData.ValidTo + 'T' + exclusionData.ValidTimeUntil + ':59.999-' + tz
)};
if (exclusionData.CenterId === '') {
delete data.Exclusion.CenterId;
}
return this.http
.post("url", data)
.pipe(
map((res: any) => {
return res.code;
})
);
}
greetings, and I look forward to your comments, thanks.
I'm not fully confident in my rxjs knowledge but it looks like, because of .pipe(last()), you are only watching the last request? I'd recommend you only set success if all completed without error, like
this.apiFca.saveNew(valueForm, this.exclusionDelays)
.subscribe(
res => {
console.log(res);
},
err => {
console.log(err);
},
() => {
this.successMessage = true;
// etc. etc. etc.
});
or maybe instead of using this.successMessage use something like this.saveState$ that would be the a BehaviorSubject object initialized with 'idle' (or some enum thereof) that your saveExclusion() function manages. That way, the beginning of your saveExclusion() function could
set const saveState$ = this.saveState$
assert that saveState$.getValue() === 'in process' or if not, do something about it,
saveState$.next('in process');
and you could change your subscribe line to
this.apiFca.saveNew(valueForm, this.exclusionDelays)
.subscribe(
res => {
if (res !== '200') {
saveState$.next('unexpected result')
} },
err => {
console.log(err);
saveState$.next('error');
},
() => {
if (saveState$.getValue() === 'in process') {
saveState$.next('success');
} }
);
And then you can subscribe to your component's saveState$ as well (though outside of the component you'd want to provide saveState$.asObservable() so values can't be injected by outside code). This affords some elegant event-driven code in your component initialization:
saveState$.pipe(filter(val => val === 'error'))
.subscribe(functionToTellYourUserThereWasAnError);
// if successful, we want other code to know, but immediately change it back to 'idle' even if other code errors
saveState$.pipe(filter(val => val === 'success')
.subscribe(val => saveState$.next('idle'));
// upon success, reset me
saveState$.pipe(filter(val => val === 'success'))
.subscribe(
val => {
this.exclusionDays = [];
// etc. etc.
// setTimeout not needed because set to 'idle' in a different thread.
}
)
Plus, I think your template could reflect and change the UI in response to changes in saveState$ as well, so your save button can be enabled/disabled based on whether or not saveState is 'idle', etc.

Categories

Resources