I am not into javascript and angular, currently working on some UI task and has workable/little knowledge of javascript
what i want, base on a key field filter out the objects.
currently what code is doing, hitting a api, which is storing some result in an array. this array result are in object (promise object) i guess, and i need to set out a filter condition on this object base on some value.
but for me issue is, object does not have key same as response, it store. data like this
Array(5) [ {…}, {…}, {…}, {…}, {…} ]
0: Object { _isScalar: false, source: {…}, operator: {…} }
1: Object { _isScalar: false, source: {…}, operator: {…} }
2: Object { _isScalar: false, source: {…}, operator: {…} }
3: Object { _isScalar: false, source: {…}, operator: {…} }
4: Object { _isScalar: false, source: {…}, operator: {…} }
length: 5
so even if i iterate through each object i cant find the key which is my filter criteria.
below is code related to this
getSomeThing(
name: string,
dcId: any
): Promise<any[]> {
const url = `<url>`;
return this.http.get(url, { headers: this.sharedService.getHeaders() })
.toPromise()
.then(response => this.getSomeThingOneByOne(name, dcId, response.json()))
.catch(error => this.sharedService.handleError(error));
}
private getSomeThingOneByOne(name, dcId, someIds): Promise<any> {
const someObservables = [];
someIds.forEach(some => someObservables.push(this.getsomethingObservable(name, dcid, some)));
return Observable.forkJoin(someObservables)
.toPromise()
.catch(error => this.sharedService.handleError(error));
}
getsomethingObservable(
name: string,
dcId: any,
someId: any
): Observable<any> {
const url = `<url>`;
return this.http.get(url, { headers: this.sharedService.getHeaders() })
.map((response: Response) => {
const vm = response.json();
return vm;
})
.catch((error: any) => Observable.throw(this.sharedService.handleError(error)));
}
note i have change the name of function and variable.,
now here, getsomeThing call an api which return a list of ids and pass it to getSomethingOneByOne as array ie [1,2,3,4,5] , and this function getSomethingOneByOne call getsomethingObservable to get the data related to that id.
what i want is once i recied the data i should check a certain value in it or in getsomethingObservable check the value it self for that key and filter out the result.
but due since i am not able to read the data in array someObservables in function getSomeThingOneByOne raw i cant add filter condition there.
need help here as it requires knowledge of promise, obserable, angular and typescript which i lack.
just solved this by taking reference from #sonusindhu suggestion and taking reference from here too.
i had made changes on getSomeThingOneByOne as below and it worked
private getSomeThingOneByOne(name, dcId, someIds): Promise<any> {
const someObservables = [];
someIds.forEach(some => someObservables.push(this.getsomethingObservable(name, dcid, some)));
return Observable.forkJoin(someObservables)
.toPromise()
.then(response => {
var data = response.filter(val=>val[<somekey>]!='<a certain value>');
return data;
})
.catch(error => this.sharedService.handleError(error));
}
Related
I'm using autoCompletejs and want to fetch my list of keys from my backend, but am getting the following error:
autoComplete.js:119 Uncaught (in promise) TypeError: Invalid attempt to iterate non-iterable instance. In order to be iterable, non-array objects must have a Symbol.iterator method.
My "data" code:
data: {
src: async () => {
try {
// Loading placeholder text
document.getElementById("autoComplete").setAttribute("placeholder", "Loading...");
// Fetch External Data Source
const source = await fetch("/suppliers");
const data = await source.json();
console.log(data)
// Post Loading placeholder text
document.getElementById("autoComplete").setAttribute("placeholder", autoCompleteJS.placeHolder);
// Returns Fetched data
return data;
} catch (error) {
return error;
}
},
keys: fetch("/keys").then(response => response.json()) //.then(jsonData => console.log(jsonData)
),
cache:true
},
Values logged:
jsonData:
(10) ['263897', '186000', '146294', '278717', '189906', '246548', '130111', '157960', '947854', '138753']
0: "263897"
1: "186000"
2: "146294"
3: "278717"
4: "189906"
5: "246548"
6: "130111"
7: "157960"
8: "947854"
9: "138753"
length: 10
[[Prototype]]: Array(0)
data:
0: {100058: 'Supplier1', 100211: 'Supplier2', 100476: 'Supplier3', 100986: 'Supplier4' …}
length: 1
[[Prototype]]: Array(0)
Looks like your /suppliers endpoint returns a singleton array (an array with only one item in it) with an object of id / label pairs.
First, singleton arrays are useless. I'd change the backend to return an array of objects but in the meantime, you could map the result to something more useful
data: {
src: async (query) => {
const res = await fetch("/suppliers");
if (!res.ok) {
throw new Error(`${res.status}: ${await res.text()}`);
}
// get the first / only array item
const [data] = await res.json();
// map to an array of objects with id & label properties
return Object.entries(data).map(([ id, label ]) => ({ id, label }));
},
keys: ["label"],
}
How do I change the values of my object to use the fixed values as I have done with my console.log?
fetchData = () => {
axios.get(fullAPI).then(res => {
const apiResponse = res.data
apiResponse.forEach(employee => console.log('test', employee.value.toFixed(2)))
apiResponse.forEach(employee => employee.value.toFixed(2))
console.log('raw data', apiResponse)
this.setState({
employeeData: apiResponse,
})
})
}
test 4.41
test 5.00
test 6.16
test 0.79
raw data
(10) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
0: {name: "Animals", value: 4.41361634}
1: {name: "Environment", value: 5.004498622999998}
The error with your code is that you are just formatting the value number and returning it to forEach (that does nothing with this information).
You must modify the original object.
fetchData = () => {
axios.get(fullAPI).then(res => {
const apiResponse = res.data;
apiResponse.forEach(employee => {
employee.value = employee.value.toFixed(2); // Note we are attributing the fixed value to the value itself, modifying the object
});
console.log('raw data', apiResponse)
this.setState({
employeeData: apiResponse
})
})
}
Note that this works because JavaScript always use a reference for objects (like a pointer in C), so even without returning the object, you are changing it properties and it will reflect on the original array.
IMO is more readable for non experienced (and experienced as well) programmers using Array.map() instead, since it will make clear that you are modifying the object and updating the array:
fetchData = () => {
axios.get(fullAPI).then(res => {
const apiResponse = res.data;
apiResponse.map(employee => {
employee.value = employee.value.toFixed(2)
return employee;
});
console.log('raw data', apiResponse)
this.setState({
employeeData: apiResponse
})
})
}
Both codes will do the same, probably no performance differences, just different readability.
You need to set employee.value to the desired value. Additionally, I recommend not using the implicit return syntax and use braces for readability.
apiResponse.forEach(employee => {
employee.value = employee.value.toFixed(2);
});
I passed Array but got Observer here's my code:
In Component1
data() {
return {
myWords: [],
}
}
//...
await axios.post(this.serverUrl + router, {
voca: text,
category: this.buttonGroup.category.text
})
.then(res => {
this.myWords.push({
voca: this.voca,
vocaHeader: this.vocaHeader,
category: res.data.savedVoca.category,
date: res.data.savedVoca.date,
id: res.data.savedVoca._id
})
this.myWords.push({voca:"test"})
})
.catch(err => {
console.log(err)
})
In Component2
props: {
myWordsProp: {
type: Array,
default: () => ([])
},
},
mounted() {
console.log(this.myWordsProp)
console.log(this.myWordsProp[0]) //returns undefined
},
And I expected an Array but I get Observer so I can't get values from this.myWordsProp[0] why?
//this.myWordsProp
[__ob__: Observer]
0: {
category: "ETC"
date: "2018-11-21T15:31:28.648Z"
id: "5bf57a503edf4e0016800cde"
voca: Array(1)
vocaHeader: Array(1)
...
}
1: {__ob__: Observer}
length: 2
__ob__: Observer {value: Array(2), dep: Dep, vmCount: 0}
__proto__: Array
//this.myWordsProp[0]
undefined
I found a clue that when I test it outside of axios it worked as I expected.
Vue wraps data and props into reactive objects. Use vue-devtools plugin in your browser as an alternative to viewing the ugly observer in the console.
In your code, the object behaves correctly. It’s only in the console that it ‘looks’ different.
Anyway, you can also click on the ... to expand the node and get the value from the console.
https://github.com/vuejs/vue-devtools
I found a solution It's because of sending props before get data from server.
This is my whole of postVocas function It returns promise
postVocas: function (voca) {
if (!voca || voca.length < 1) return
let router = "/api/voca"
let text = ""
text += `${this.vocaHeader[0].english}, ${this.vocaHeader[0].korean}\n`
voca.forEach((x, index) => {
text += `${voca[index].english}, ${voca[index].korean}\n`
})
return axios.post(this.serverUrl + router, {
voca: text,
category: this.buttonGroup.category.text
}).then(res => {
this.myWords.push({
voca: this.voca,
vocaHeader: this.vocaHeader,
category: res.data.savedVoca.category,
date: res.data.savedVoca.date,
id: res.data.savedVoca._id
})
}).catch(err => {
console.log(err)
})
},
And await till get data from server.
This one is function where execute My postVocas function.
sendVocaToTable: async function () {
let reformedText = this.reformText(this.text)
this.voca = this.formatTextToVoca(reformedText)
await this.postVocas(this.voca)
this.$router.push({
name: 'Table',
params: {
vocaProp: this.voca,
tableHeaderProp: this.vocaHeader
}
})
},
I am trying to use JS to query DynamoDB and parse the returned data. I must admit that I am new to JavaScript but I am having some weird behaviours.
In the following function I am passing an array of dates and I am retrieving objects from my table
var queryDynamo = function(dateArray){
console.log(dateArray)
for (var i = 0; i < dateArray.length; i++) {
var params = {
TableName : "myTable",
KeyConditionExpression: "#day = :st ",
ExpressionAttributeNames:{
"#day": "day"
},
ExpressionAttributeValues: {
':st': dateArray[i]
}
};
var resp = docClient.query(params, function(err, data) {
if (err) {
console.log("ERR:"+JSON.stringify(err, undefined, 2))
} else {
data.Items.forEach(function(element) {
console.log(element)
});
}
});
}
console.log(resp.response)
return;
}
--> The following is the output
constructor {request: constructor, data: null, error: null, retryCount: 0, redirectCount: 0, …}
data:
Count: 4
Items: (4) [{…}, {…}, {…}, {…}]
ScannedCount: 4
__proto__: Object
error: null
httpResponse: constructor {statusCode: 200, headers: {…}, body: Uint8Array(1134), streaming: false, stream: i, …}
maxRedirects: 10
maxRetries: 10
nextPage: ƒ (e)
redirectCount: 0
request: constructor {domain: undefined, service: t.c…r.t.constructor, operation: "query", params: {…}, httpRequest: constructor, …}
retryCount: 0
__proto__: Object
The query succeeds but the result is kind of weird.
resp.response correctly contains the data object but I cannot access it. It says that it's null while it clearly is not since it has 4 Items.
Any thoughts?
You are attempting to print the response data before it exists. Your console.log(resp.response) line is executing before the DynamoDB query has completed and its results have been unmarshalled. This is a common gotcha in asynchronous JavaScript.
One way to see the response data in the AWS.Request object is to wait for it, like this (though you would never typically do this in JavaScript):
var req = docClient.query(params, function(err, data) {
// as before: handle err, data
)};
setTimeout(function () {
console.log('Response data:', JSON.stringify(req.response.data));
}, 2000);
A more common pattern is to use the promise variants of the SDK methods, like this:
docClient.query(params).promise()
.then(data => doSomething(data))
.catch(err => logError(err));
I do a http call to get an Array with objs. And now I want to call for each objs that return me an ID another http call. After all I want to have one observable result.
So far I managed to get for each index a http call. The problem instead of one result I got multiple.
getStats(tag: string) {
return this.service.getClanByClanTag(tag)
.map(clan => {
return clan.memberList; //the arr that return the ID's
})
.switchMap((member: PlayerByMemberListType[]) => {
return member; // singleObj of the arr
})
.concatMap((singleMember) => {
return this.service.getPlayerData(singleMember.tag).map(player => {
//push data to the new arr which should return only one time
this.newArr.push({
tag: singleMember.tag,
name: singleMember.name,
warStars: player.warStars,
trophiesNightBase: singleMember.versusTrophies
});
return this.newArr;
});
});
}
This is what the console prints out after subscribing to it:
Array [ {…} ]
Array [ {…}, {…} ]
Array(3) [ {…}, {…}, {…} ]
Array(4) [ {…}, {…}, {…}, {…} ]
Array(5) [ {…}, {…}, {…}, {…}, {…} ]
...
I know I need some kind of Observable.forkJoin but I don't know how integrate it in the code.
Try something like this:
this.service.getClanByClanTag(tag)
.mergeMap(clan => clan.memberList)
.mergeMap(
member => this.service.getPlayerData(member.tag), // supposedly this returns an observable
(member, player) => ({
tag: member.tag,
name: member.name,
warStars: player.warStars,
trophiesNightBase: member.versusTrophies
})
)
.toArray()
So basically what you want to achieve is this.
Get the clan info
Using clan info from step 1, get the memberList in the clan
For each member inside the memberList, get the players
You will need to think of a way to preserve the info at step2 when before switchMap in step3. Usually we will use a Subject, but in the case if you do not want to, simply map the Observable to preserve the data:
getStats(tag: string) {
return this.service.getClanByClanTag(tag)
.map(clan => {
return clan.memberList; //the arr that return the ID's
})
.switchMap((memberList: PlayerByMemberListType[]) => {
//note that the following map is a function of javascript array, not Observable
//it returns an array
let arrayOfObservables = memberList.map(singleMember => {
this.service.getPlayerData(singleMember.tag)
//map the data so as to preserve the data of singleMember
//by creating a new object, using Object.assign
.map(playerData => {
return Object.assign({memberData: singleMember}, playerData,)
});
})
return Observable.forkJoin(arrayOfObservables);
})
.map(players => {
//players is an array of Object that is the format of {memberData:singleMember, playerData:player)
//perform Object destructuring method
return players.map(({memberData,playerData}) => {
return {
tag: memberData.tag,
name: memberData.name,
warStars: playerData.warStars,
trophiesNightBase: memberData.versusTrophies
}
})
})
}