format JSON data for chart.js from Angular 4 observable - json

I've been going insane with this and can't figure this one out. I have data from my API formated like this:
"data": [
{
"sr_count": 91,
"month_name": "October",
"month_num": 10,
"year": 2017
},
{
"sr_count": 50,
"month_name": "September",
"month_num": 9,
"year": 2017
}
]
Which I need to take the data from "sr_count" and "month_name" re-format into their own array in order for chart.js to handed the data.
for instance:
["91","50"]
["October", "September"]
I have a reportService which is grabbing the data from my API
getSR(groupBy: string, beginDate:string, endDate:string): Observable<Report[]> {
return this.http.get(`${this.reportUrl}/SR?group_by="${groupBy}"&begin_date="${beginDate}"&end_date="${endDate}"`)
.map(res => res.json().data)
.catch(this.handleError);
}
From my component code I'm figured that I could map all the data from sr_count and month_name into an array, then push it into a local variable so that I could use it in the data for chart.js
export class SrReportsComponent implements OnInit {
monthName: [];
srCount1: [];
srCount2: [];
data: any;
ngOnInit() {
this.reportService.getSRLastMonth()
.subscribe(data => {
srCount= data.map(item => {
return item.sr_count
})
console.log(srCount) // ["October", "September"]
this.srCount2.push(srCount) // [["52", "41"]]
});
this.reportService.getSRThisMonth('Month',lastMonth,today)
.subscribe(data => {
monthName= data.map(item => {
return item.month_name
}
srCount= data.map(item => {
return item.sr_count
}
console.log(monthName) // ["October", "September"]
this.monthName.push(monthName) // [["October", "September"]]
this.srCount1.push(srCount) //[["91","50"]]
});
console.log(this.monthName)// [["October", "September"]]
this.data = {
labels: this.monthName, //returns []
datasets: [
{
label: 'First Dataset',
data: this.srCount1,
fill: false,
borderColor: '#4bc0c0'
},
{
label: 'Second Dataset',
data: this.srCount2,
fill: true,
borderColor: '#4ba0c0'
}
]
}
}
because using the push() method it seems to be nesting my the array which chart.js can't see. I've tried monthName[0] as well and get undefined in the console
What's the best way to get the array from the observable passed into a local variable so that I can get chart.js working?

just move your data inside your observable. You're working with asynchronous operation.
ngOnInit() {
this.reportService.getSR('Month',lastMonth,today)
.subscribe(response => {
this.data = {
labels: response.map(item => { return item.month_name });
datasets: [
{
label: 'First Dataset',
data: this.srCount,
fill: false,
borderColor: '#4bc0c0'
}
]
}
});
}

If all you need is to not "nest" the month name array you can use the array.push.apply(array, array2) approach (see link below).
So for your array:
this.monthName.push.apply(this.monthName, monthName);
https://stackoverflow.com/a/4156156/4219717

Related

next-i18next i18n on array of objects

I have an array of objects called "Options", that I use as a prop to a dropdown/select Material-UI component. I want to use the next-i18next library on the labels. I already implemented with success through all the next app just like the documentation explains. I tried using the {t('key')} and it doesn't allow.
import { useTranslation } from 'next-i18next'
const UsersPage = () => {
const { t } = useTranslation('user');
const Options = [
{ value: 'fullName', label: 'Nome' },
{ value: 'cpf', label: 'CPF' },
{ value: 'id', label: 'PadrĂ£o' },
]
...rest of the component
}
export const getStaticProps = async ({ locale }) => ({
props: {
...await serverSideTranslations(locale, ['user', 'home']),
},
})
export default UsersPage;
The msefer answer is right:
`${t("key")}`
inside JSON or string building in props like
const since = `${t('since')}`;
const until = `${t('until')}`;
...
<ListItemText
primary={value.name}
secondary={since + value.beginDate + until + value.endDate}
/>

React and chart.js with json

I'm very new in React and JS. I'm trying to create a graph from JSON, but I can't pass value to graph with MAP function and PUSH, my result is just numbers that I put manually (2, 3, 5 - Line 45)
dataGraf.push(hit.minutos) //Works well
this.state.items.map((hit) => (dataGraf.push(hit.minutos))) //No erros, but no data add
My JSON:
[
{"indice":1,"minutos":569,"programa":"seg"},
{"indice":2,"minutos":421,"programa":"ter"},
{"indice":3,"minutos":258,"programa":"quar"}
]
import React,{Component} from 'react';
import Chart from "chart.js";
import Config from '../components/config.js';
let dataGraf = []
class GraphChart extends Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
this.state = {
items: [],
error: null
};
}
componentDidMount() {
let url1 = `${Config.FullURL}/progativo`
const ctx = this.ctx;
fetch(url1)
.then(items => items.json())
.then((items) => {
this.setState({ items });
});
this.funDadosGrafico()
new Chart(ctx, {
type: "pie",
data: {
labels: ['blue', 'green','red'],
datasets: [
{
label: "# of Likes",
data: dataGraf
}
]
}
});
} //End of componentDidMount
funDadosGrafico(){
dataGraf.push(2, 5, 3) //Just for test
this.state.items.map((hit) => (
dataGraf.push(hit.minutos)))
}
render() {
return (
<div>
<canvas width='800' height='300' ref={ctx => (this.ctx = ctx)}/>
</div>
)
}
}
export default GraphChart;
try moving the execution this.funDadosGrafico() and Canvas creation to componentDidUpdate.
once you call fetch, fetch wont block the thread, hence this.funDadosGrafico() is executed right aftwards. then blocks are executed only after fetch is resolved.
plus, setState method is also async. it is not going to work as expected even if you remove setState from fetch call like:
this.setState(updateMyState)
this.funDadosGrafico() // not going to work also, setState is async

How to access objects inside an array of JSON object?

I'm trying to access object inside an array of a JSONObject and print its values.
I'm able to print the array as JSONObject using console.log. But i fail to access the values inside the array which are again JSONObject format. Following is my my JSONObject
{
"id": 4,
"meta": {
"type": "pagetype",
"title": "Home"
}
},
"title": "Expose data to frontend",
"subtitle": "We will be exposing the content to the frontend",
"content": [
{
"type": "full_richtext",
"value": "<p><b>Bold body</b></p>"
},
{
"type": "button",
"value": {
"button_text": "Google",
"button_url": "https://google.com"
}
}
]
}
I need to access the values inside the array "content" and print values for
"value" -- Bold body --
"button_text"
"button_url"
I have tried it as follows
class App extends React.Component {
constructor() {
super();
this.state = {
'items': []
}
}
componentDidMount() {
fetch('http://localhost:8000/api/v2/pages/4/')
.then(results => results.json())
.then(results => this.setState({ 'items': results }));
}
render() {
var contents_from_wagtail = this.state.items;
var streamfield_content_array = contents_from_wagtail.content;
console.log(streamfield_content_array); //prints array of objects
return (
<React.Fragment>
<p>{this.state.items.subtitle}</p>
<p>{this.state.items.title}</p>
/* print the values for
"value" -- Bold body --
"button_text"
"button_url"
*/
</React.Fragment>
);
}
}
export default App;
When showing an array of items the .map method can be used to create multiple elements:
class App extends React.Component {
constructor() {
super();
this.state = {
'items': {}
}
}
componentDidMount() {
fetch('http://localhost:8000/api/v2/pages/4/')
.then(results => results.json())
.then(results => this.setState({ 'items': results }));
}
render() {
var contents_from_wagtail = this.state.items;
var streamfield_content_array = contents_from_wagtail.content || [];
console.log(streamfield_content_array); //prints array of objects
return (
<React.Fragment>
<p>{this.state.items.subtitle}</p>
<p>{this.state.items.title}</p>
{streamfield_content_array.map((item, index) => {
return <div key={index}>type: {item.type} <p>{item.value}</p></div>
})}
</React.Fragment>
);
}
}
export default App;
More .map examples: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
To access it within the render you have to access it conditional because it is not set for the first render until the fetch call is Executed
That is why you have to provide some fallback until the array is loaded.just check if the item is undefined and return null for example.
Only if the array is filled render the desires output and it should be fine.
Hope this helps. Happy coding.
You could use a combination of .map() and .filter() to iterate over the items within the content array. It looks like you only want to display items that have a type of button. So try something like this:
class App extends React.Component {
constructor() {
super();
this.state = {
'items': []
}
}
componentDidMount() {
fetch('http://localhost:8000/api/v2/pages/4/')
.then(results => results.json())
.then(results => this.setState({ 'items': results }));
}
render() {
var contents_from_wagtail = this.state.items;
var streamfield_content_array = contents_from_wagtail.content;
var buttonContent = this.state.items ? this.state.items.content.filter((item) => item.type == "button") : null
return (
<React.Fragment>
<p>{this.state.items.subtitle}</p>
<p>{this.state.items.title}</p>
{ buttonContent && buttonContent.map(item => (
<div>
<p>{item.button_text}</p>
<p>{item.button_url}</p>
</div>
))}
</React.Fragment>
);
}
}
export default App;

How to make aspecific API call from within a Line Chart class in ReactJS using react-chartjs-2?

I am creating a web app in ReactJS and I am trying to call an API from within my Chart class.
I have a program that takes data from a ML model and writes it to an API in the form of an array. I'm new to using ReactJS and I just want to make a call to the API to return the array into my data variable in react to render in the graph onscreen.
The data in the API is formatted as ..
[
1,
2,
3,
4
]
Currently I have the data hard coded into a separate file and am importing that but I want it to be called from the API directly so it updates.
import React, {Component} from "react"
import {Line} from "react-chartjs-2"
import {popuData, dayLabels} from "./FakeGraphData";
class PlanGraph extends Component{
constructor(props){
super(props);
this.state = {
chartData:{
labels: dayLabels,
datasets: [
{
label:'Predicted Park Crowds',
data: popuData,
borderColor: 'rgba(77, 112, 255, 1)',
backgroundColor: 'rgba(77, 112, 255, 1)'
}
]
}
}
}
render(){
return(
<div className = "chart">
<Line
data={this.state.chartData}
options={{
title: {
display:true,
text:"Predicted Park Crowds",
fontSize:25
},
legend:{
display: true,
position: 'right'
},
scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: 'Anticipated Crowds'
},
ticks: {
beginAtZero: true
}
}],
xAxes: [{
scaleLabel: {
display:true,
labelString: 'Days in the future'
}
}]
}
}}
/>
</div>
)
}
}
export default PlanGraph
Add a container Component & use Props
The component you've shown us here looks like a presentational component (has html structure, cares about how things look). What you should do is create a container component, these components care about things like logic & getting data. You can read about this design methodology here.
The container will render the component you have posted above but will pass some props kind of like this.
Example
class PlanGraphContainer extends Component {
state = {
dataToPass: []
};
async componentDidMount() {
const response = await fetch('https://your-api-request');
const data = await response.json(); // maybe you need this, you have to check your response
this.setState({dataToPass: data});
}
render() {
return <PlanGraph data={this.state.dataToPass} />
}
}
Then inside your PlanGraph use this.props.data to see the data that is being passed. make sure you have some fake data or loading state whilst you wait for the request to be complete. our you can add something like this
render() {
const { dataToPass } = this.state;
return (dataToPass && dataToPass.length)
? <PlanGraph data={this.state.dataToPass} />
: null;
}

TypeError: items.map is not a function , how to solve this error

Everytime i run the code it shows the same error. Can anyone explain what is wrong with this code and how to rectify it? Items are in an array,you can check it in the url 'https://api.myjson.com/bins/8pyl4'.
import React, { Component } from 'react';
import '../Stylesheet/bootstrap.min.css';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
isLoaded: false
}
}
componentDidMount() {
fetch('https://api.myjson.com/bins/8pyl4')
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json
})
});
}
render() {
var { isLoaded, items } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
}
return (
<div>
<ul>
{items.map(item => (
<li key="{item.ibn}">
Name: {item.name} , Author: {item.author}
</li>
))}
</ul>
</div>
);
}
}
You're setting your state[items] to json, but it's an object, not an array! Go ahead and change:
this.setState({isLoaded: true, items: json});
to this:
this.setState({isLoaded: true, items: **json.items**});
Try
componentDidMount() {
fetch('https://api.myjson.com/bins/8pyl4')
.then(res => this.setState({
isLoaded: true,
items: res.data.items
})
});
}
Your res.data will be
{
"items":[
{
"ibn":123,
"name":"Harry Potter",
"author":"J K Rowling",
"genre":"fantasy",
"publisher":"bloomsbury",
"ebook":"yes",
"audiobook":"yes",
"summary":"the chosen one and he who must not be named",
"rating":"5/5",
"price":"500"
},
{
"ibn":456,
"name":"Artemis Fowl",
"author":"Eoin Colfer",
"genre":"fantasy",
"publisher":"viking press",
"ebook":"yes",
"audiobook":"yes",
"summary":"the rich child theif and fairies",
"rating":"5/5",
"price":"540"
},
{
"ibn":789,
"name":"war and Peace",
"author":"Leo Tolstoy",
"genre":"drama",
"publisher":"wordsworth",
"ebook":"yes",
"audiobook":"yes",
"summary":"the russian epic on war and peace after it",
"rating":"5/5",
"price":"700"
},
{
"ibn":135,
"name":"metamorphosis",
"author":"Franz Kafka",
"genre":"absurdist fiction",
"publisher":"kurt wolff",
"ebook":"yes",
"audiobook":"no",
"summary":"a salesman turns into an insect",
"rating":"4/5",
"price":"400"
},
{
"ibn":791,
"name":"coraline",
"author":"Neil Gaiman",
"genre":"dark fantasy",
"publisher":"harper collins",
"ebook":"yes",
"audiobook":"yes",
"summary":"the most adventurous person ever",
"rating":"4.5/5",
"price":"560"
}
]
}
now you need to get the items from the JSON.
You should write:
{items.map(item => {
<li key={item.ibn}>
Name: {item.name} , Author: {item.author}
</li>
})}
All Json data are not array. Just check the data that you are trying to pass to the map function. Map functions take array data.