How to extract some data from json in react JS (axios)? - javascript

I'm a ReactJS and axios newbie.
I want to iterate and extract json data if the key is number (like 0, 1, 2....)
and don't know how can I write this piece of code.
(because the server provide the json dynamically, and we don't know how many elements it will have)
Now I can extract the data with key = 0 (assume there exists this element)
class ContentBody extends Component {
constructor(props) {
super(props);
this.state = {
jdata: []
}
}
componentDidMount() {
var self = this;
// read data periodically
setInterval(function() {
axios.get(URL)
.then(function(response) {
self.setState({
jdata: response.data[0].Name
});
})
.catch(function(e) {
console.log("ERROR ", e);
})
}, 1000);
}
}
// below is json data from the server
{
"0": {
"Assigned": false,
"Name": "BebopDrone-Test001.",
"droneID": 0
},
"1": {
"Assigned": false,
"Name": "BebopDrone-B046836",
"droneID": 1
},
"2": {
"Assigned": false,
"Name": "BebopDrone-Test002.",
"droneID": 2
},
"function": "getAllDroneStatus()"
}
// my pseudo code might be
for(int i = 0; i < jsonObject.size(); i++){
if(key is number){
extract corresponding value
}
}

The response that you get from the server is an object, what you should do is loop over the Object and then update data in state where I assume you only need name
componentDidMount() {
var self = this;
// read data periodically
setInterval(function() {
axios.get(URL)
.then(function(response) {
var names=[];
Object.keys(response.data).forEach(function(data) {
names.push(data.Name);
})
self.setState({
jdata: names
});
})
.catch(function(e) {
console.log("ERROR ", e);
})
}, 1000);
}

Your response is an Object not an Array.
You can't access an object using array indexing.
Assuming response.data is the body of your json, you should access your object properties like this: response.data['0'], response.data['1'], response.data['2']
You can iterate over an object using for..in.
Your data model (aside from the reference to 'getAllDroneStatus()') suggests that an array might be more useful.
{
"jdata" : [
{
"Assigned": false,
"Name": "BebopDrone-Test001.",
"droneID": 0
}
// ...
]
}
Then you can iterate, reduce, filter and so on.

Related

How to create new object with limited data from other object in Vue JS

I am trying to create a search app that looks for products. I’ve got a PHP script that returns results in JSON format when a keyword is posted to it. I post to there with axios.
Now if there are 40 results for example the dropdown of results will be too long. So I want to create a new object from the object of 40 results and limit this object to 6.
I tried this by creating a function inside computed like this:
Object(this.responseData) is my full object with all results from my PHP script in a JSON object.
filteredData is my new object that I added in my data.
test(){
var fullResults = Object(this.responseData);
var number = 0;
for (var key in fullResults) {
number++;
if(!number > 6){
this.filteredData[number] += fullResults[key]
}
}
console.log(this.filteredData)
},
But my log just shows: Proxy {}. What am I doing wrong? I need to get all results from the old object, and add them to a new empty object with a limit of 6.
This is my full JS:
let app = Vue.createApp({
data: function(){
return{
// Object to fill with JSON response
responseData:{},
// Object to fill with filtered result (max 6)
filteredData: {},
showResultDiv: false,
totalResults: 0
}
},
methods:{
// Function to show loading dots until json returned
loadDiv(condition, content){
this.showResultDiv = condition
},
async fetchResults(){
await axios.post('includes/searchproducts_json.php', {
// Post data, add value of input to searchterm
searchterm: this.$refs.searchterm.value
})
.then((response)=>{
this.responseData = response.data
// Get length of returned object and add to totalResults
this.totalResults = Object.keys(this.responseData).length
console.log(Object(this.responseData));
})
.catch((error)=>{
console.log(error)
})
}
},
computed: {
filteredObject(){
return this.responseData
},
test(){
var fullResults = Object(this.responseData);
var number = 0;
for (var key in fullResults) {
number++;
if(!number > 6){
this.filteredData[number] += fullResults[key]
}
}
console.log(this.filteredData)
},
// Set totalResults with matching string
resultString(){
if(this.totalResults == 1){
return this.totalResults + ' resultaat'
}else{
return this.totalResults + ' resultaten'
}
}
}
})
app.mount('#v_search');
Your search result set should really be an array (of result objects).
Something like:
[
{"id": 1, "text": "foo"},
{"id": 2, "text": "bar"},
{"id": 3, "text": "baz"},
...
]
Or, more elegant:
{
"searchterm": "input value"
"total_results": 31,
"limit": 10,
"page": 2,
"results": [
{"id": 1, "text": "foo"},
{"id": 2, "text": "bar"},
{"id": 3, "text": "baz"},
...
]
}
Then, the computed should be as simple as:
data() {
return {
results: []
}
},
computed: {
resultsToShow() {
return this.results.slice(0, 6)
}
},
methods:{
fetchResults() {
axios.post('includes/searchproducts_json.php', {
// Post data, add value of input to searchterm
searchterm: this.$refs.searchterm.value
})
.then((response) => {
if (response.status === 200 && response.data.length) {
this.results = response.data
}
})
.catch(console.error)
}
}
See a working demo: https://codesandbox.io/s/thirsty-germain-i6w4w?file=/src/App.vue
And because it's just a simple slice, you could even remove (the overhead of) the computed property and just write it into the template inline expression:
<ol>
<li v-for="(result, index) in results.slice(0, 6)" :key="index">
{{ result.text }}
</li>
</ol>
Object.keys() returns an array of the object keys, which could be the thing you are looking for if i understand correctly. Then you could create a computed property something like this:
test() {
return Object.keys(this.responseData).map((key) => this.responseData[key]).slice(0,6);
}
This transforms the object to an an array after which you can use a simple slice method to get the first 6 elements.

Assignment of Nuxt Axios response to variable changes response data content

async fetch() {
try {
console.log(await this.$api.events.all(-1, false)); // <-- First log statement
const res = await this.$api.events.all(-1, false); // <-- Assignment
console.log(res); // <-- Second log statement
if (!this.events) {
this.events = []
}
res.data.forEach((event, index) => {
const id = event.hashid;
const existingIndex = this.events.findIndex((other) => {
return other.hashid = id;
});
if (existingIndex == -1) {
this.events.push(events);
} else {
this.events[existingIndex] = event;
}
});
for (var i = this.events.length - 1; i >= 0; --i) {
const id = this.events[i].hashid
const wasRemoved =
res.data.findIndex((event) => {
return event.hashid == id
}) == -1
if (wasRemoved) {
this.events.splice(i, 1)
}
}
this.$store.commit('cache/updateEventData', {
updated_at: new Date(Date.now()),
data: this.events
});
} catch (err) {
console.log(err)
}
}
// The other functions, maybe this somehow helps
async function refreshTokenFirstThen(adminApi, func) {
await adminApi.refreshAsync();
return func();
}
all(count = -1, description = true) {
const func = () => {
return $axios.get(`${baseURL}/admin/event`, {
'params': {
'count': count,
'description': description ? 1 : 0
},
'headers': {
'Authorization': `Bearer ${store.state.admin.token}`
}
});
}
if (store.getters["admin/isTokenExpired"]) {
return refreshTokenFirstThen(adminApi, func);
}
return func();
},
Both log statements are giving slightly different results even though the same result is expected. But this only happens when is use the function in this specific component. When using the same function in other components, everything works as expected.
First data output:
[
{
"name": "First Name",
"hashid": "VQW9xg7j",
// some more correct attributes
},
{
"name": "Second name",
"hashid": "zlWvEgxQ",
// some more correct attributes
}
]
While the second console.log gives the following output:
[
{
"name": "First Name",
"hashid": "zlWvEgxQ",
// some more correct attributes, but this time with reactiveGetter and reactiveSetter
<get hashid()>: reactiveGetter()
​​ length: 0
​​​​ name: "reactiveGetter"
​​​​ prototype: Object { … }
​​​​<prototype>: function ()
​​​<set hashid()>: reactiveSetter(newVal)
​​​​length: 1
​​​​name: "reactiveSetter"
​​​​prototype: Object { … }
​​​​<prototype>: function ()
},
{
"name": "Second name",
"hashid": "zlWvEgxQ",
// some more correct attributes and still without reactiveGetter and reactiveSetter
}
]
As it can be seen, somehow the value of my hashid attribute changes, when assigning the response of the function call.
The next weird behavior happening here, is that the first object where the hashid field changes also gets reactiveGetter and reactiveSetter (but the second object in the array does not get these).
So it looks to me like something is happening with the assignment that I don't know about. Another guess would be that this has something to do with the Vuex store, because I do not change the Vuex tore in the other place where I use the same function.
It is verified that the backend always sends the correct data, as this is dummy data, consisting of an array with two objects with some attributes. So no other data except this two objects is expected.
Can someone explain to me why this behavior occurs?
There are few problems...
Do not use console.log with objects. Browsers tend to show "live view" of object - reference
this.events.findIndex((other) => { return other.hashid = id; }); is wrong, you are using assignment operator (=) instead of identity operator (===). That's why the hashid of the first element changes...

Print data onto html from within json using 'for' loop based on 'if' condition

I have a json file:
"courses":[{
"code":"101000",
"name":"Bachelor of Education (Primary)"
}, {
"code":"101001",
"name":"Bachelor of Education (Secondary)"
}]
I have managed to get the json data into the page via
$.getJSON('unminified.json', function (data) {
courses = data["courses"];
});
and can access data via chrome console like this
courses[0].name
which returns "Bachelor of Education (Primary)" which is fine.
MY PROBLEM
Is that I want to access name properties based on what the code property is. I've tried below but I keep getting undefined (in chrome console):
function myFunction() {
for(var i = 0; i < courses.length; i++)
{
if(courses[i].code == '101000')
{
return courses[i].name;
};
}
};
Your json is not valid. You need curly braces enclosing the whole thing, and you need commas after the "code" properties:
{
"courses":[
{
"code":"101000",
"name":"Bachelor of Education (Primary)"
},
{
"code":"101001",
"name":"Bachelor of Education (Secondary)"
}
]
}
With corrected json data, myFunction appears to work as expected. I've updated it to take a courses argument instead of referencing a global or parent scope variable.
// mock $.getJSON
const fakeRequest = (callback) => {
const data = {
"courses": [{
"code": "101000",
"name": "Bachelor of Education (Primary)"
}, {
"code": "101001",
"name": "Bachelor of Education (Secondary)"
}]
}
setTimeout(() => callback(data), 200);
}
// invoke the request and handle the response
fakeRequest((response) => {
const {courses} = response;
// pass courses to myFunction, because it
// doesn't exist outside this function scope
const c = myFunction(courses);
// insert into the document
document.querySelector('.name').innerHTML = c;
})
// takes a courses argument to eliminate the
// bad practice of referencing an external variable
function myFunction(courses) {
for (var i = 0; i < courses.length; i++) {
if (courses[i].code == '101000') {
return courses[i].name;
};
}
};
<div class="name"></div>

Is their any better way to set duplicate array data instead of use data[0]

What is the best way to refactoring code and best performance Here Is what I do In getData function I query get Data from databae using async/await then I got some ugly data I try to map and delete element that duplicate data
async getData({req,res}) {
let data = await this.getData()
data = [
{
"id": 3,
"employee_id": 2290,
"getId": {
"id": 9070
},
"getName": {
"name": "test"
},
},
{
"id": 4,
"employee_id": 2291,
"getId": {
"id": 9070
},
"getName": {
"name": "test"
},
}
] //example I await call database get data look like this
//before I remove them I want to keep duplicate data I set new variable for keep them
//which part is the most ugly is their anyway to do something about this ?
const getId = data[0].getId
const getName = data[0].getName
// in this part I map and delete element that duplicate which is data.getName and data.getId
// I create seperate function for code clean
data = await this.removeElement(data)
//after that I return response data
return response.status(200).json({
status: 200,
success: true,
getId: getId,
getName: getName,
data: data
});
}
async removeElement(data) {
// im not sure is their any beeter way to do something like this ?
return Promise.all(
data.map(async item => {
await delete item.getId;
await delete item.getName;
return item;
})
);
}
so my output response will look like this :
getId : {
id : 9070
}
getName : {
name : 'test'
}
data : [
{
"id": 3,
"employee_id": 2290,
},
{
"id": 4,
"employee_id": 2291,
}
]
I really appreciate for your help thanks
Removing properties from an object is not an asynchronous process. There's no need to await it or have a Promise.all around such a loop.
To extract the two common properties from the first item of the array concisely, you can destructure:
const { getId, getName } = data[0];
Shorthand property names will help too. In full:
const data = await this.getData();
const { getId, getName } = data[0];
const trimmedData = data.map(({ id, employee_id }) => ({ id, employee_id }));
return response.status(200).json({
status: 200,
success: true,
getId,
getName,
data: trimmedData
});
The data.map(({ id, employee_id }) => ({ id, employee_id })) takes the array and constructs a new array of objects which contain only the id and employee_id properties in the original objects.
If you need to blacklist properties rather than extract the desired properties, then you can do something similar to the above with rest syntax:
const trimmedData = data.map(({ getId, getName, ...rest }) => rest);

PouchDB emit object from an array of objects

I would like to search trough an array of objects (that are encapsulated in one big object), and emit only the one of the internal objects. So let's suppose I have a JSON inserted into PouchDB that is looks like this:
{
"_id": "5eaa6d20-2019-44e9-8aba-88cfaf8e02542",
"data": [
{
"id": 1452,
"language": "java"
},
{
"id": 18787453,
"language": "javascript"
},
{
"id": 145389721,
"language": "perl"
}
]
}
How to get PouchDB to return the following result when searching for a language with an id = 145389721:
{
"id": 145389721,
"language": "perl"
}
Thanks!
In the scenario above the easiest way, using typescript, is to write a temp query:
db.query((doc, emit) => {
for (let element of doc.data) {
if (element.id === 145389721) {
emit(element);
}
}
}).then((result) => {
for (let row of result.rows) {
console.log(row.key);
}
})
Using permanent queries it would have looked like this:
let index = {
_id: '_design/my_index',
views: {
"by_id": {
"map": "function(doc) {for (let element of doc.data) {emit(element.id, element); }}"
}
}
};
// save it
this.db.put(index).catch(error => {
console.log('Error while inserting index', error);
});
//query it
this.db.query('my_index/by_id', { startkey: 145389721, endkey: 145389721}).then(result => {
for (let row of result.rows) {
console.log(row.value);
}
}).catch(error => {
console.log('Error while querying the database with an index', error);
});

Categories

Resources