Can not map over a response json array - json

I have the Json response from an api in the below format
[
{
id: 1,
class: '10',
section: 'A',
subject: 'Social'
},
{
id: 2,
class: '8',
section: 'C',
subject: 'Social'
},
{
id: 3,
class: '9',
section: 'A',
subject: 'Social'
}
]
I am storing the json response in a state variable and able to print the above json array successfully.
async ListAllTodaysClasses() {
try {
let data = new FormData();
data.append('id', this.state.id)
data.append('year',this.state.year)
data.append('month',this.state.month)
data.append('day', this.state.day)
var url = this.state.url;
console.log(url);
let response = await fetch(url, {
method: 'POST',
body: data
});
let res = await response.json();
this.setState({
subjects: res
})
console.log(this.state.subjects)
} catch(error) {
this.setState({error: error});
console.log("error " + error);
}
}
Here I am trying to loop over an json response array.
this.state.subjects.map((item, key) => (
<TouchableOpacity key={key}>
<View>
{
<Text style={styles.textColor2}>{item.class}th-{item.section}/ {item.subject}</Text>
}
</View>
</TouchableOpacity>
))
But I am getting Typeerror: undefined is not a function

Your question has nothing to do with JSON. You're storing the result of calling response.json(), which parses the JSON in the response and returns the parsed result.
Your code to store it is correct:
this.setState({
subjects: res
})
so I suspect the problem is in your constructor where you set your initial state. The correct initial state for subjects would be like this:
// In your constructor
this.state = {
/*...any other state you have...*/,
subjects: []
};
Notice that subjects is an empty array. I suspect you're setting it to {} (an empty object) or "" (an empty string) or similar. (You're clearly not failing to initialize it, and not using null, since that would produce a different error.)
Side note: Although your setState call is correct, what follows it is not:
this.setState({
subjects: res
})
console.log(this.state.subjects) // <=== Will not see the updated state
Remember that state updates are asynchronous.

You probably need to init your state.subjects:
class YourClassName extends React.Component {
constructor() {
this.state = {
subjects: []
}
}
}

Related

Access String array in Json

The API I am using has a nested string array it seems, I need to extract the path from it, but I cannot figure out how....
This is a break down of what I need to access.
the productimage is wrapped in quotes...
[
{title: "Item 1",
productimage: "[{"1":{"size":"75x75","path":"/10000/img.jpg"}]"
},
{title: "Item 2",
productimage: "[{"1":{"size":"75x75","path":"/20000/img.jpg"}]"
}
]
I am trying to access the image path...
The problem seems to be reading the string, I have attempted to treat it like an array, and a string and get mixed results..
Edited:
here is the entire productimages object, it is coming from an apache database that i have no control over.
productimages: "[{"1":{"size":"75x75","path":"/100000/101819-75x75-A.jpg"}},{"2":{"size":"222x222","path":"/100000/101819-600x600-A.jpg"}},{"3":{"size":"328x328","path":"/100000/101819-600x600-A.jpg"}}]"
my current axios call looks like this.
async function handleSubmit(searchData) {
if (searchData) {
const payload = searchData;
try {
const response = await axios({
url: `${baseUrl}q=*:*&fq=title:${payload}&fq=storeid:1234
method: "get",
});
//Set Hook
setData(response.data.response.docs);
} catch (error) {
console.error(error);
}
}
}
Here is the response data that is being set..
{productid: 1234, itemups: 1234, title: "productname", productimages: "[{"1":{"size":"75x75","path":"/100000/101819-75x75-A.jpg"}},{"2":{"size":"222x222","path":"/100000/101819-600x600-A.jpg"}},{"3":{"size":"328x328","path":"/100000/101819-600x600-A.jpg"}}]", productcount: 7}
I can get everything out of this, except the image.
You've to parse productimage:
const parsedArray = array.map(obj => {
let path = '';
try {
const productimage = JSON.parse(`${obj.productimage}`);
path = productimage[0].path
} catch(err) {
console.error(err)
}
return { ...obj, path }
});
[EDIT]
Axios response:
axios() // some axios call
.then(res => res.data)
.then(array => {
// ... here you can transform your array
})
Also make sure your json is properly formatted.
{
[
{"title": "Item 1",
"productimage": "[{"1":{"size":"75x75","path":"/10000/img.jpg"}]"
]
}

display data from json object on HTML in angular 5

hello i want to display the data that i got from a mongodb using a backend api (nodejs)
this is the code for event model
const mongoose = require('mongoose');
const config = require('../config/database');
// Events Schema
const EventSchema = mongoose.Schema({
eventname: {
type: String,
required: true
},
eventstartdate: {
type: String,
required: true
},
eventenddate: {
type: String,
required: true
},
eventcategorie: {
type: String
},
eventdescription: {
type: String
},
eventimage: {
type: String
}
});
const Event = module.exports = mongoose.model('Event', EventSchema);
this is the code from the router
const express = require('express');
const router = express.Router();
const passport = require('passport');
const jwt = require('jsonwebtoken');
const config = require ('../config/database');
const User = require('../models/user');
const Event = require('../models/event');
//get event by id
router.get('/event/:eventid', (req,res) => {
Event.findById(req.params.eventid, (err, event) =>{
if (err){
return res.status(500).send({message:err.message});
}
if(!event){
return res.status(400).send({message:'Event not found'});
}
res.json({
event: {
id: event._id,
eventname: event.eventname,
eventstartdate: event.eventstartdate,
eventenddate: event.eventenddate,
eventcategorie: event.eventcategorie,
eventdescription: event.eventdescription,
eventimage: event.eventimage
}
});
});
});
and this is the code from the service in the angular
// GET an event by ID
displayEvent$(id: string) {
return this.http.get(`http://localhost:3000/users/event/${id}`)
.map(response => response.json());
}
then i created a simple method that is triggered by a button
and i passed an id of an event that i konw is in the database just to test it out
onclickeventpage(){
this.authService.displayEvent$('5ae0c8e96b40a71cd3b772cc').subscribe(event => {
console.log(event)
});
}
this gives me back at the console the event i need with every aribute
but whene i change this
console.log(event)
to this so i can get evey atribute separetly and then i an put them in the html
console.log(event.eventname)
i get undefined
i just want to know how to get every event atribute so i can display them in my html page
First you dont have to call .json() witn angular5
displayEvent$(id: string) {
return this.http.get(`http://localhost:3000/users/event/${id}`)
.map(response => response.json());
}
also you need to access
console.log(event.event.eventname);
HttpModule is deprecated and the new HttpClientModule by default formats the response to JSON so we no longer need to parse it using response.json():
I just want to know how to get every event attribute so that I can
display them on my HTML page
You can tell HttpClient the type of the response to make consuming the output easier and more obvious.
Typechecking of response can be done by using type parameter
export interface Ievent {
id:string
eventname: string
eventstartdate: string
eventenddate: string
eventcategorie: string
eventdescription: string
eventimage: string
}
Http returns an observable and We can tell the HttpClient.get to return response as Ievent type When we use http.get<Ievent>(...) then it returns the instance of Observable<Ievent> type.
In your service
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import {Ievent} from './eventModel'
#Injectable()
export class authService()
{
constructor(private http:HttpClient){}
displayEvent$(id: string)Observable<Ievent> {
return this.http.get<Ievent>(`http://localhost:3000/users/event/${id}`);
}
}
In your component subscribe to Observable<Ievent> to get instance of Ievent
onclickeventpage(){
this.authService.displayEvent$('5ae0c8e96b40a71cd3b772cc').subscribe(event => {
console.log(event);
console.log(event.eventname)});
}

React/Redux - Issue iterating json from mapStateToProps

I have a React Native app on which I'm trying to apply Redux. It's the first time I try to use Redux, so I think I'm not seeing the elephant in the room.
The problem is that I can't access my props data (generated with mapStateToProps). Here's my code:
reducer.js (in the console log I see the json objects just fine)
const INITIAL_STATE = {
etiquetas: []
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case FETCH_ETIQUETAS_SUCCESS:
//console.log("payload: "+action.payload);
return { ...state, etiquetas: action.payload };
default:
return state;
}
};
component.js (in the console.log I see my data, BUT it seems that it's all in one object now, this is probably what I'm not seeing).
class EtiquetasList extends Component {
componentDidMount() {
this.props.FetchEtiquetas();
}
renderEtiquetas() {
//console.log("etq: "+JSON.stringify(this.props.etiquetas));
if ( this.props.etiquetas.length == 0 ) {
return <ActivityIndicator size="large" color="#00ff00" />
} else {
return this.props.map(etiqueta =>
<EtiquetaDetail key={etiqueta.id} etiqueta={etiqueta} />
);
}
}
render() {
return (
<ScrollView>
{this.renderEtiquetas()}
</ScrollView>
);
}
}
const mapStateToProps = (state) => {
return {
etiquetas: state.etiquetas
};
};
export default connect(mapStateToProps, { FetchEtiquetas })(EtiquetasList);
The map function is for Arrays, not Objects, I know. That's part of my old code.
action.js
import axios from 'axios';
import { FETCH_ETIQUETAS, FETCH_ETIQUETAS_SUCCESS, FETCH_ETIQUETAS_FAILURE } from './types';
const url= 'https://e.dgyd.com.ar/wp-json/wp/v2/etiquetas?_embed&per_page=7';
const fetchSuccess = (dispatch, data)=> {
dispatch({
type: FETCH_ETIQUETAS_SUCCESS,
payload: data
});
}
export function FetchEtiquetas() {
return function (dispatch) {
axios.get( url )
.then(response => {
dispatch({ type: FETCH_ETIQUETAS_SUCCESS, payload: response.data })
} );
}
}
reducers/index.js
import { combineReducers } from 'redux';
import DataReducer from './DataReducer';
export default combineReducers({
etiquetas: DataReducer
});
So, my questions are:
Why is is this always returning undefined?
this.props.etiquetas.length == 0
Why mapStateToProps seems to convert my array of objects into a single object? is this why I have to use JSON.stringify in the console log?
and finally, how do I access my data in the component?
Thank you much in advance!
The problem here, is just the way that you structured your reducer.
const INITIAL_STATE = {
etiquetas: []
};
The code above means that you are creating an object, with a property named "etiquetas" that holds an empty array initially.
In your root reducer file, you import that object, and assign it the name, "etiquetas". So really what your reducer is returning is this:
etiquetas: {
etiquetas: [your array of data]
}
This would explain why you complained about receiving an object. There are two ways to rectify this,
One: Change the mapStateToProps function to this,
const mapStateToProps = (state) => {
return {
etiquetas: state.etiquetas.etiquetas
};
};
Two: Change your reducer to look like this,
export default (state = [], action) => {
switch (action.type) {
case FETCH_ETIQUETAS_SUCCESS:
//console.log("payload: "+action.payload);
return action.payload;
default:
return state;
}
};
This will make sure your reducer returns just an array, not an object with an array inside of it stored in a property. Its up to you to decide which you like better.

Take elements from Json to input in Picker

I'm new in react native. I'm trying to fecth a webservice and input some element from response to a Picker (I use native-base). My problem is I don't know how to take an element (here it's LIBELLE) what I need in my Json.
see the code :
getSurfaces(){
fetch('yourWebservice')
.then((response) => response.text())
.then((responseText) => {
parseString(responseText, function (err, result) {
responseText = result;
});
console.log(JSON.stringify(responseText));
this.setState({
surfaces: responseText.Surfaces.surface
}).catch(err => console.log(err));
console.log(this.state.surfaces);
}
})
.catch((err) => {
console.log('Error fetching the feed: ', err)
})
}
componentDidMount(){
this.getSurfaces();
}
My constructor:
constructor (){
super();
this.state = {
date: '',
surface: '',
surfaces: [],
start: '',
hours : [],
};
this.valueChangeSurface = this.valueChangeSurface.bind(this);
}
valueChangeSurface(value: String){
this.setState({
surface: value
});
}
My renderSurfaces method:
renderSurface(){
if(this.state.surfaces){
return this.state.surfaces.map((surface) => {
return <Picker.Item label={surface.LIBELLE} value={surface}/>
})
}
}
The render of Picker:
<ListItem>
<Left>
<Text>Surface</Text>
</Left>
<Body>
<Picker
note
inlineLabel={true}
mode={"dropdown"}
style={{width: 175}}
selectedValue={this.state.surface}
onValueChange={this.valueChangeSurface}>
{
this.renderSurface()
}
</Picker>
</Body>
<Right/>
</ListItem>
The error returned by this.setStatein getSurfaces():
Error fetching the feed: [TypeError: undefined is not an object (evaluating '_this2.setState({
surfaces: responseText.Surfaces.surface
}).catch')]
I don't really know if I take the good way to do this, I would really appreciate your help
JSON.stringify() turns a JS object to a json string. And also, you dont need of interacting over the object to set the state.
this.setState({
surfaces: responseText.Surfaces.surface;
});
You've already the surface has an JS Object.
In your code you are interacting over a JSON string object when you are rendering the component, and giving to the result the last JSON object,
{"ID":["4"],"LIBELLE":["Quicks"],"CODE":["QUICKS"],"ORDRE":["4"]}
into a JSON String object,
'{"ID":["4"],"LIBELLE":["Quicks"],"CODE":["QUICKS"],"ORDRE":["4"]}'
Before rendering the component, you can render surfaces e.g.
renderSurfaces() {
if (this.state.surfaces) {
return this.state.surfaces.map((surface) => {
return (
<Text>
{surface.LIBELLE}
</Text>
);
});
}
}
I finally find a solution :
The problem it was simple and the most part of it come from a syntaxe erreur, I replace :
responseText.Surfaces.surface.LIBELLE
by this :
responseText.Surfaces.surface[i].LIBELLE
See the entire code of getSurfaces():
getSurfaces(){ // Input the surfaces values (ID and LIBELLE) who come from WebService in the this.state.surfaces
fetch('url')
.then((response) => response.text())
.then((responseText) => {
parseString(responseText, function (err, result) {
responseText = result;
});
let sf = []; // Create a table who gonna content the value of this.state.surfaces
for(i = 0; i<responseText.Surfaces.surface.length; i++){
sf.push(responseText.Surfaces.surface[i].LIBELLE.toString());
}
this.setState({
surfaces: sf //inject the table sf who contain the table surfaces
});
})
.catch((err) => {
console.log('Error fetching the feed: ', err)
})
}
You have to provide an object for your Picker. Now you're converting your object to a string, use this instead:
surfaces.forEach(result => {
this.setState({
surfaces: result
});
console.log(this.state.surfaces);
}
The surfaces.forEach(e => {}) is the same as your loop there just a little bit simpler. Keep in mind that you don't need to use can use this kind of loops (forEach, map) almost always in JS.
If this doesn't help, please post the html snippet of you Picker.

Can I return raw json response in angular2

Is it possible for angular2 to return raw json response? Ex.
Component
getrawJson(){
this.someservice.searchJson()
.subscribe( somelist => this.somelist = somelist,
error => this.errorMsg = <any>error);
}
For service
searchJson(num: number, somestring: string, somestring2: string): Observable<stringDataObj> {
let body = JSON.stringify({"someJsonData"[{num, somestring, somestring2}]});
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post(URL, body, options)
.map(this.jsonObj)
.catch(this.handleError);
}
private jsonObj(res: Response) {
let body;
return body{ };
}
The above implementation returns Array . Will there be a way for me to get the raw json data returned by the service? I'm expecting to have json response like below
{
"dataParam": [ {
"num": "08",
"somestring": "2016-10-03",
"somestring2": "2016-10-03"
}],
"someDatalist": [ {
"one": "08",
"two": 1,
"three": "2016-10-03"
}]
}
Thanks!
Yes off course you can !!
Actually angualar2 returns Response in the form of Observable instead of promise Like in angular1.x , so in order to convert that observable into raw Json format we have to use the default method of angular2 i.e
res.json()
There are no of method apart from .json() provided by angular which can be described here for more info.
methods include
res.text()
res.status
res.statusText
etc
https://angular.io/docs/ts/latest/api/http/index/Response-class.html
update
use your code like this
return this.http.post(URL, body, options)
.map(res => {return res.json()})
.catch(this.handleError);
}
private jsonObj(res: Response) {
return res.json() || {} ;
}