I am working with React.js and YouTube API. I get a collection of objects from the API but I want to add a 'check' field to every object. I used the below code -
await axios.get('https://youtube.googleapis.com/youtube/v3/search', {
params: {
part: 'snippet',
q: sTerm,
type: 'video',
key: KEY
},
})
.then(response => {
let i=0;
response.data.items.forEach(item=>{
response.data.items[i]['check']=true
i++;
})
console.log(response.data.items) //gives correct output with check field
console.log(response.data.items[0].check) //gives undefined instead of true
console.log(response.data.items[0]['check']) //gives undefined instead of true
})
What should I do to access the 'check' field value?
Update: This is my response
Finally what worked for me is creating a new array as suggested by a now deleted answer.
.then((response) => {
myItems=response.data.items.map(
item => ({...item, check: true})
);
console.log(myItems);
You can use javascripts Array.prototype.map instead of forEach to transform every value in your items array:
.then(response =>
response.data.items.map(
item => ({...item, check: true})
)
)
This should return on the top line where you are awaiting the axios call the array of items where each item.check equals true.
Related
I could display the result of my pagination query (FaunaDB,FQL) in the console and it appears as a javascript object. Yet, I cannot access the properties of said object and even less can I convert it to an array using the spread operator. How could I do that?
I am aware there exists a pagination helper but could not make it work, as explained above. Here is the latest code I am trying:
var array=[]
qu(q.Map(
q.Paginate(q.Match(q.Index('FeesByIndex'))),
q.Lambda(x => q.Get(x))
)).then(res => { console.log(res); array=[...res] })//the log really looks like a js object and res is said to be one
It says type object is not an array type. Also, property data is said not to exist on res, although it clearly does in the console
You missed to specify the index term and the Lambda has syntax errors.
The response object has a data property, which is a list.
In my repositories I use this snippet if the query returns multiple object:
const result: Fee[] = [];
await CLIENT.query(
q.Map(
q.Paginate(
q.Match(
q.Index('FeesByIndex'),
'index term',
),
),
q.Lambda('fees', q.Get(q.Var('fees'))),
)
)
.then(faunaResponse => {
const dataArray = faunaResponse.data;
dataArray.forEach(s => {
const data = s.data;
result.push({
id: data.id,
yourProp1: data.yourProp1,
yourProp2: data.yourProp2,
});
});
})
.catch(e => logger.error(e));
would you try this way?
var array=[]
qu(q.Select(['data'],
q.Map(
q.Paginate(q.Match(q.Index('FeesByIndex'))),
q.Lambda(x => q.Get(x))
)
)
).then(res => { console.log(res); array=[...res] })
How to add value to a specific object to the array by the index?
I wrote this, but of course, it creates a new object in the array, but I want to insert "errors" to an existing object with index (on screen it 0 index)
ipcRenderer.on('fileData', (event, data) => {
this.setState({jobs: [...this.state.jobs, {errors: data}]})
});
Then i wrote this:
ipcRenderer.on('fileData', (event, data) => {
this.state.jobs.forEach((item, index) => {
this.setState({jobs: [...this.state.jobs, {errors: item[index] = data}]
})
console.log(this.state)
})
});
It inserts a value into the object, but without a name and it still creates a new element in the array
I want the result to be like this:
jobs: [
0: {errors: 10, fileName:...}
]
If you know the index, you can just do
const jobs = this.state.jobs.slice(0);
jobs[index].errors = data;
this.setState({jobs});
Might have to do more than slice the array, might have to make a deep copy, but yeah, that should work.
Firstly you can make a copy of your array like
let jobsCopy = this.state.jobs
Then if you know the index you could just do like
jobsCopy[index].errors = 10
this.setState({
jobs: jobsCopy
})
You would need to know the index of the object you want to change. For example if you know it is the first item in the array you can do this:
const indexToChange = 0
this.setState(prevState => prevState.map((obj, i) => {
if(i === indexToChange) {
return {
...obj,
errors: data
}
} else {
return obj
}
}))
I am trying to learn the map method. If I use this syntax response.data.map(d => I am able to iterate data array and see the results, but if I use this syntax response.data.map(([label, CustomStep]) => {, I am getting the error below:
Unhandled Rejection (TypeError): Invalid attempt to destructure non-iterable instance
Can you tell me how to fix it, so that in future I will fix it myself?
Providing my code snippet below:
axios
.get('http://world/sports/values')
.then(response => {
console.log("sports--->", response.data.map(d => d.customFieldValueName));
//this.setState({ playerRanks: response.data.map(d => d.customFieldValueName) });
// es6 map
//Unhandled Rejection (TypeError): Invalid attempt to destructure non-iterable instance
this.setState({
playerRanks: response.data.map(([label, CustomStep]) => {
label.customFieldValueName
})
})
})
update 1:
hey, I saw in console, data is an array inside that there are so many objects
data: Array(19)
[
{
"customFieldValueCode": "player1",
"customFieldValueName": "player1",
"isActive": "Y"
},
{
"customFieldValueCode": "player 2",
"customFieldValueName": "player 2",
"isActive": "Y"
}
]
EDIT:
Based off the data structure provided you could modify your code to...
axios
.get('http://world/sports/values')
.then(response => {
this.setState({
playerRanks: response.data.map(obj => {
return obj.customFieldValueName
})
})
})
OR
...
response.data.map(({customFieldValueName}) => {
return customFieldValueName;
})
...
OR even...
...
response.data.map(({customFieldValueName}) => customFieldValueName)
...
But this would be my recommended solution to provide type checking on you data and proper error handling...
axios
.get('http://world/sports/values')
.catch(err=> console.log(err))
.then(({data}) => { // Axios always returns an Object, so I can safely 'attempt' to destructure 'data' property
if (data && data.length) { // making sure 'data' does exist, it is an Array and has > 0 elements
this.setState({
playerRanks: data.map(obj => { // Not destructuring here in case obj isn't actually an Object
if (obj && obj.customFieldValueName) return customFieldValueName;
return null;
}).filter(elem=> elem) // BIG-O notation: This sequence is O(2N), as in iterates over the entire Array first with .map(), then iterates over the entire Array again with .filter() to clear out 'null' values
})
}
})
In order to prevent your returned Array above from having a bunch of null elements when they don't conform to our assertions, you can use an Array.reduce() method to 'filter' out any nulls...
axios
.get('http://world/sports/values')
.catch(err=> console.log(err))
.then(({data}) => { // Axios always returns an Object, so I can safely 'attempt' to destructure 'data' property
if (data && data.length) { // making sure 'data' does exist, it is an Array and has > 0 elements
this.setState({
playerRanks: data.reduce((acc,obj) => { // Not destructuring here in case obj isn't actually an Object
if (!obj || !obj.customFieldValueName) return acc; // If it doesn't meet assertions just return the existing accumulator (don't add another element .ie 'null')
return [
...acc, // If it conforms to the assertions the return a new accumulator, by first spreading in all existing elements and the adding the new one (customFieldValueName)
customFieldValueName
]
},[]) // BIG-O notation: This is O(1N) or O(N), as in it will only iterate over the Array one time and the reduce() function will filter out 'null' values at the same time
})
}
})
NOTE:
I also just added .filter(elem=> elem) to the end of my first example, which does the same thing as the new .reduce() functionality, but does this in 1N not 2N operations.
PRE-logged data
Here's how the Array.map() method works...
[1,2].map(element=> {
// element === 1, first iteration,
// element === 2, second iteration
})
Here's how Array destructuring works...
[one, two, ...theRest] = [1,2,3,4,5]
// one === 1 and two === 2 and theRest = [3,4,5]
Here's how Object destructuring works...
{one, three, ...theRest} = {one: 1, two: 2, three: 3, four: 4, five: 5}
// one === 1 and three === 3 and theRest === {two: 2, four: 4, five: 5}
// notice order doesn't matter here (three vs two), but you need to access valid properties from the object you're deetructuring from
So based on the way you function is structured you are making the assumption that the data structure of response.data is...
response.data === [
[
{ customFieldValueName: 'any value' }, // label
{} // CustomStep (this could be any value, not necessarily an Object)
],
[
{ customFieldValueName: 'any value' }, // label
'any value' // CustomStep
]
]
I hope this helps conceptually, but if you'd like a workable solution we will need...
Data structure of response.data. Can you provide result of console.log( JSON.stringify( response.data, null, 5) )
Specific values you are trying to assign to the new this.state.playerRanks Array.
PS: A good way to see Object destructuring in action with your current code is to change...
.then( response => {
To
.then( ({data}) => {
In this case, you should be certain that response.data is an array of arrays, because for each iteration of response.data.map, the function you are providing to the map must receive an array to be able to successfully pull the label and CustomStep values, due to the syntax with which you are destructuring the function parameter.
Imagine data in the following example is the response.data and the parseData function is the function you are passing to the map:
let data = [
[{ customFieldValueName: 'field name' }, { stepData: {} }],
[{ customFieldValueName: 'another field name' }, { stepData: {} }]
];
let parseData = ([label, CustomStep]) => console.log(label.customFieldValueName);
parseData(data[0]); // prints out 'field name'
Otherwise, if response.data is an array of objects, which it seems like it is due to you successfully being able to run response.data.map(d => d.customFieldValueName), you could update your map to this (if you simply want to pull the customFieldValueName value out of the object):
response.data.map(({ customFieldValueName }) => customFieldValueName)
I have a program that uses Axios to get data with API calls. I want to store the result as a object in my this.state.matrixDictionary variable. but everytime i make another API call the previous object gets overwritten. I want to create something like this
this.setState({
matrixDictionary: {
[0]: result,
}
})
Then next time i make another api call to get other result i want it to be like this:
this.setState({
matrixDictionary: {
[0]: result,
[1]: result,
}
})
But i dont want to add the [1] manually, i want it to be created depending on how many times i make the API call to store the objects. If i make 5 calls then the object should be now [0],[1],[2],[3],[4] so i can easily keep track of the objects and change their values later.
How is this best achieved?
fetchDataAPI(APIUrl){
this.setState({ isLoading: true });
console.log("Fetching from: " + APIUrl);
return axios.get(APIUrl,{
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
}
})
.then(result => {
this.setState({isLoading: false});
console.log(result.data);
return result.data;
})
.catch(error => {
this.setState({error, isLoading: false })});
}
UPDATE
I used the fix from Roman Batsenko, Next question is how do I then change a property in that object and put it back in setState.
I guess good practice is to use JS Spread syntax for that like ...state.
It depends on the format of answer from your API but I think it would be not so hard to achieve this with:
axios.get(APIUrl,{
/* ... */
})
.then(result => {
this.setState({
isLoading: false,
matrixDictionary: [...this.state.matrixDictionary, result.data]
});
})
make an array of object in your intial state like
this.state = {
matrixDictionary: []
}
and when you call your api push your response object in array so that will store always in another index and finally you make array of objects.
this.setState({ matrixDictionary: result.data});
it may help you.
Why not save the objects in an array, so you can have them in order:
in the constructor:
this.state = {
matrixDictionary: []
}
in your API call:
this.setState(prevState => ({
values: prevState.matrixDictionary.concat(result.data),
}));
You can access them like this:
this.state.matrixDictionary[0] // your first api call
this.state.matrixDictionary[1] // your second api call
this.state.matrixDictionary[2] // your third api call
I'm receiving data with axios like this:
getData() {
Axios.get(
'/vue/get-data/',
{
params: {
categories: this.category,
activeFilters: this.activeFilters,
}
}
).then((response) => {
this.banners = response.data;
this.setBanner();
})
},
Then I get this:
When I try console.log(response.data.length) I get undefined. What could
be going on here very weird!
When I look in my vue-devtools banners has 2 objects:
So how can response.data.length be undefined?
You are getting object not array that why .length is not working, and you are getting as undefined
this.banners = response.data[0];// for first
Or loop over this, to get each object's data
for(var i in response.data){
console.log(response.data[i]);
}
If to get each value is not your purpose , and you want to just size check this answer