I want to display a loader till my chart is displayed.I have implemented the following code but it doesn't work.The loader should display as soon as "compare" button is clicked:
import React, { Component, Fragment,useState,useRef,createRef} from "react";
import Loader from "react-loader-spinner";
import RestAPI from "services/api";
import axios from "axios";
import Select from 'react-select';
import "d3-transition";
import {
Button,
Label,
FormGroup,
Form,
} from "reactstrap";
import ReactApexChart from "react-apexcharts";
import "tippy.js/dist/tippy.css";
import "tippy.js/animations/scale.css";
class StackedAreaChart extends Component {
constructor(props) {
super(props);
this.selectInputRef = React.createRef();
this.selectInputRef1 = React.createRef();
this.selectValue=this.selectValue.bind(this)
this.clickEvent=this.clickEvent.bind(this)
this.handleChange=this.handleChange.bind(this)
this.onClear=this.onClear.bind(this)
this.checkIfMounted=this.checkIfMounted.bind(this)
this.state = {
soptions:[],
weights:[],
years:[],
loader:false,
selectOptions: [],
selectedValues:[],
combinedList:[],
yearsList:[],
isLoaded:false,
selectValue:"",
series: []
};
}
checkIfMounted() {
console.log("mount")
return this.selectInputRef1.current != null;
}
componentDidMount(){
fetch("http://127.0.0.1:8000/api/getallvals/")
.then(response => response.json())
.then(json => {
this.setState({
soptions:json.topics,
})
});
}
handleChange=(e)=>{
const value = Array.isArray(e) ? e.map(s => s.value) : []
this.state.selectedValues=value
console.log("value is:",this.state.selectedValues)
}
selectValue(e){
var selectValue=this.state.selectValue;
var isDisplayed=this.state.isDisplayed;
console.log("the val is:",e);
console.log("the val is:",e.length);
console.log("the val is:",e[0].value);
this.setState({
selectedValues:e,
loader:false
});
console.log(this.state.selectedValues)
}
onClear() {
//window.location.reload(false);
//console.log(this.selectInputRef1.current)
this.selectInputRef.current.select.clearValue();
}
//this.selectInputRef1.current.chart.destroy();}
clickEvent(){
console.log("in click event",this.state.selectedValues)
var selectedValues=this.state.selectedValues;
var {series}=this.state;
fetch("http://127.0.0.1:8000/api/getallvals/"+'?'+selectedValues.join('&'))
.then(response => response.json())
.then(json => {
series=[]
for(let i=0;i<json.weights.length;i++){
series=series.concat([{name:selectedValues[i],data:json.weights[i]}])
//selectInputRef1.current.chart.publicMethods.updateOptions({})
}
this.setState({
series: series,
datalabels:{
enabled:true
},
options:{
stroke:{
curve:'smooth'
},
xaxis:{
categories:json.years
},
},
isLoaded:true,
loader:false
})
});
console.log("this state",series)
}
render() {
const checkmount=this.checkIfMounted;
var {options,isLoaded,loader,series,yeardata,soptions,weights,years}=this.state;
if(isLoaded){
return (
<div id="chart" className="box" >
<Form role="form" method="POST" >
<FormGroup>
<h2>Evolution of a value over Time
</h2>
<Label>Select a value</Label>
<Select ref={this.selectInputRef} name="selectOptions" isClearable isMulti placeholder="Select Option" options={soptions}
onChange={this.handleChange}/>
<br></br>
<Button onClick={ this.clickEvent }
>Compare</Button>
<Button onClick={this.onClear}>Reset</Button>
<Loader type="puff" visible={loader} color="#00BFFF" height={100} width={100}></Loader>
</FormGroup>
</Form>
{checkmount?(
<ReactApexChart ref={this.selectInputRef1} options={this.state.options} series={this.state.series} type="area" height={350} />):
(<div>not yet loaded</div>)}
</div>)
}
else{
return (
<div id="chart">
<Form role="form" method="POST" >
<FormGroup>
<h2>Evolution of a values over time
</h2>
<Label>Select a value</Label>
<br></br>
<Select ref={this.selectInputRef} name="selectOptions" isClearable isMulti placeholder="Select Option" options={soptions}
onChange={this.handleChange}/>
<br></br>
<Button onClick={this.clickEvent}>Compare</Button>
<Button onClick={this.onClear}>Reset</Button>
<Loader type="puff" visible={false} color="#00BFFF" height={100} width={100}></Loader>
</FormGroup>
</Form>
</div>)
}
}
}
export default StackedAreaChart;
loader is the flag I have kept to decide whether or not to display loader but it still doesn't show up.Also I am disabling the loader when the page is not loaded
So what you want to do is, while you are fetching the data, the loader will be true. Once you fetch the data, the loader will be false.
So, inside clickEvent you can change
fetch("http://127.0.0.1:8000/api/getallvals/"+'?'+selectedValues.join('&'))
.then(response => response.json())
.then(json => {
to this:
this.setState({loader: true})
fetch("http://127.0.0.1:8000/api/getallvals/"+'?'+selectedValues.join('&'))
.then(response => {
this.setState({loader: false})
response.json()
})
.then(json => {
...
React apexcharts has a mounted event that you can use, it is part of the chart-options:
https://apexcharts.com/docs/options/chart/events/
You could have your own isLoaded state set to false initially, and when the apex-chart mounted event is fired you set your isLoaded state to true.
This way you can chose to display the loader when isLoaded is false, and hide it when it turns to true.
Related
I have some radio buttons which are setting the rate type that I use with clients. This works as far as choosing one, and it sets that value. However, the next time I load this data, it does not render the button that was previously chosen as selected. It looks to me like I have it setup exactly the same way as I have it working in other code. So I'm sure it's something simple, but I can't seem to find it.
Once I click the buttons, they do render the correct one as selected and change the value in the database as expected. But as I said, when I load this again, it does bring in the data and set the state with the correct value through the function getRateType().
It just doesn't show which button is selected. My assumption is it's something to do with that I set the state initially to "", but why doesn't it update when I change the state to the correct value?
import React, { Component } from 'react';
import { Row, Col, Form, Modal, Button, Jumbotron, Table} from 'react-bootstrap';
import { config } from '../../Config/Constants';
import debounce from 'lodash.debounce';
const API_URL = config.url.API_URL;
class Project extends Component {
constructor(props) {
super(props);
this.state = {
rateType: ""
}
}
componentDidMount() {
this.getRateType(this.props.billProjId);
}
getRateType = (projId) => {
fetch(API_URL + `/billingcalculator/projects/${projId}`)
.then((res) => {
if (!res.ok) {
throw new Error()
}
return res.json()
})
.then((result) => {
this.setState({ rateType: result[0].project_type });
console.log(this.state.rateType); <-- this shows the correct value
})
.catch((error) => {
console.log(error);
})
}
handleCheck = (e) => {
this.setState({ [e.target.name]: e.target.value },
() => this.updateDB())
}
updateDB = debounce(() => {
let data = {
rateType: this.state.rateType
};
this.updateRateType(data);
}, 1500);
updateRateType(data) {
fetch(API_URL + `/billingcalculator/project/update`, {
method: "PUT",
body: JSON.stringify({
projectId: this.props.billProjId,
data: data,
}),
headers: { "Content-Type": "application/json" },
})
.then((res) => {
if (!res.ok) {
throw new Error();
}
return res.json();
})
.catch((err) => console.log(err))
.then(this.renderAgain());
}
render() {
return (
<div>
<Jumbotron className="mt-3">
<h1 className='display-4'>Project: {this.props.projectName}</h1>
<p>Project ID:{this.props.billProjId}</p>
<Form>
<Form.Group
as={Row}
name="rateType"
controlId="rateType"
onChange={this.handleCheck}
>
<Form.Check
inline
label="profit"
name="rateType"
type="radio"
id="rateType-profit"
value="profit"
defaultChecked={this.state.rateType === "profit"}
/>
<Form.Check
inline
label="non-profit"
name="rateType"
type="radio"
id="rateType-non-profit"
value="non-profit"
defaultChecked={this.state.rateType === "non-profit"}
/>
<Form.Check
inline
label="existing-client"
name="rateType"
type="radio"
id="rateType-existing"
value="existing"
defaultChecked={this.state.rateType === "existing"}
/>
</Form.Group>
</Form>
</Jumbotron>
</div>
)
}
}
export default Project;
Use checked instead of defaultChecked if your checkbox is going to be updated after a component re-render
render() {
return (
<div>
<Jumbotron className="mt-3">
<h1 className='display-4'>Project: {this.props.projectName}</h1>
<p>Project ID:{this.props.billProjId}</p>
<Form>
<Form.Group
as={Row}
name="rateType"
controlId="rateType"
onChange={this.handleCheck}
>
<Form.Check
inline
label="profit"
name="rateType"
type="radio"
id="rateType-profit"
value="profit"
checked={this.state.rateType === "profit"}
/>
<Form.Check
inline
label="non-profit"
name="rateType"
type="radio"
id="rateType-non-profit"
value="non-profit"
checked={this.state.rateType === "non-profit"}
/>
<Form.Check
inline
label="existing-client"
name="rateType"
type="radio"
id="rateType-existing"
value="existing"
checked={this.state.rateType === "existing"}
/>
</Form.Group>
</Form>
</Jumbotron>
</div>
)
}
What I want is that, when I click on search button, then a loader/spinner should appear on screen until the data is fetched, when the data is fetched it should disappear.
Container.jsx
import React from 'react';
import './container.css'
import Weather from './weather';
var Loader = require('react-loader');
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
location: "",
weather: [],
loaded:false
};
}
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
componentDidMount() {
this.setState.loaded=false;
}
continue = (e) => {
this.setState({loaded:true});
const { location } = this.state;
const rawurl = 'http://api.weatherstack.com/current?access_key=d8fefab56305f5a343b0eab4f837fec1&query=' + location;
const url = rawurl;
e.preventDefault();
if (location.length < 1) {
return alert('Enter the details');
}
else {
fetch(url)
.then(response => response.json())
.then(data =>{
this.setState({weather:[data],loaded:false});
})
.catch(err => console.log("error ",err))
}
};
render() {
console.log(this.state.weather);
const weather =
this.state.weather.length> 0 ?
this.state.weather.map(item => (<Weather location={item.location.name} temperature={item.current.temperature} weather={item.current.weather_descriptions[0]} windSpeed={item.current.wind_speed} windDegree={item.current.wind_degree} windDir={item.current.wind_dir} humidity={item.current.humidity} visibility={item.current.visibility} />
))
:<span></span>
return (
<div id="container">
<div class="searchicon">
<input type="search" placeholder="Enter City !!" type="text" name="location" value={this.state.location} onChange={this.handleChange}></input>
<label class="icon">
<button onClick={this.continue} id="btn"><span class="fa fa-search"></span></button>
</label>
</div>
<div>
<Loader loaded={this.state.loaded}>
{weather}
</Loader>
</div>
</div>
);
}
}
export default Container;
What I am using here is react-loader
But right now,its not happening in the way I want, sometime before clicking the serach button it appears and when data is fetched it stops, i want to start it when the api req is made after click on search button and to stop when data is fetched.
first of all you should in the setState after fetching the data to make
this.setState({weather:[data],loaded:true});
second there's another way to do it you can separate the code in the return function like
{ !this.state.loaded ? <Loader loaded={false} options={options} className="spinner" />:{weather}}
as per the Doc in npm you can check it react-loader
I cant seem to figure this out.
I have a form that is validated by formik.
When i click the search button, I make an api call to get a list of addresses.
When i click on one of those addresses, I want to populate the inputs with the data from the clicked address.
I can do all of the above except for the last part. I have tried using document.getElementById.innerHTML, setting it in state and having the input controlled by that state object, but i cant seem to get it to populate with any data.
import React, { Component } from 'react';
import { Formik, Form, Field } from 'formik';
import Axios from 'axios';
class CharityAgreement extends Component {
constructor(props) {
super(props);
this.state = {
response: [],
visible: true,
address: ''
}
}
postcodeChange = (e) => {
console.log(e.target.value);
this.setState({ 'postcode': e.target.value })
}
searchPostcode = () => {
this.setState({ 'visible': true });
if (this.state.postcode.length > 0) {
Axios.get('post code api lookup here')
.then(response => {
this.setState({ 'response': response.data });
console.log('response data:', response.data);
})
} else {
}
}
addressClick = (e) => {
console.log('CLICKED ADDRESS:', e.target.innerHTML);
this.setState({ 'visible': false });
}
render() {
const result = this.state.response.map((item) => {
if (this.state.visible === true) {
return (
<p key={item.Id} onClick={this.addressClick} className='lookup-data'>{item.address1Field} {item.address2Field} {item.townField} {item.countyField}</p>
)
} else {
}
})
return (
<div className='body-wrapper'>
<main id='mainContent' className='container'>
<div className='page-content-wrapper'>
<div className='raised-bordered-wrapper'>
<div className='raised-bordered quiz form'>
<Formik
initialValues={{
address_1:'',
}}
validate={(values) => {
const errors = {};
if (!values.address_1) errors.address_1 = 'Required';
return errors;
}}
onSubmit={this.handleSubmit}
render={({
touched,
errors,
values,
handleChange,
handleBlur,
handleSubmit
}) => (
<Form>
<div className='form-row'>
<span className='form-cell-wrapper'>
<label>Postcode Lookup</label>
<Field
name='postcode-lookup'
type='text'
onChange={this.postcodeChange}
/>
<button className='btn' onClick={this.searchPostcode}>Search</button>
</span>
</div>
{result}
<div className='form-row'>
<h5>License Code and Area</h5>
<span className='form-cell-wrapper'>
<label>Address Line 1</label>
<Field
name='address_1'
value={values.address_1}
onChange={handleChange}
id='address'
type='text'
style={{
borderColor:
errors.address_1 && touched.address_1 && "tomato"
}}
/>
</span>
</div>
</Form>
)}
/>
</div>
</div>
</div>
</main>
</div>
)
}
}
export default CharityAgreement;
I'm trying to create a change password page in react and i'm getting typeError: cannot read property 'users' of null. The code works for other form pages(where i'm doing PUT and CREATE) but not this one
I tried binding the submit handler to the this keyword but that didn't work.
Also tried binding the handlePasswordChange to the this keyword
./formchange
import React from "react";
import { Link } from "react-router-dom";
var createReactClass = require("create-react-class");
var FormChange = createReactClass({
//setting initial state
getInitialState() {
return {
password: {}
};
},
handlePasswordChange(e) {
this.setState({
password: e.target.value
});
},
handleSubmit(e) {
e.preventDefault();
this.props.onSubmit(this.state);
this.props.history.push("/");
},
render() {
return (
<form
name="categories_post"
className="form-horizontal"
onSubmit={this.handleSubmit}
>
<div id="change_password">
<div className="form-group">
<label
className="col-sm-2 control-label required"
htmlFor="password"
>
Password
</label>
<div className="col-sm-10">
<input
type="text"
value={this.state.password}
onChange={this.handlePasswordChange}
id="password"
className="form-control"
/>
</div>
</div>
<button
type="submit"
id="formChangeSubmit"
className="btn btn-default"
>
Submit
</button>
</div>
</form>
);
}
});
export default FormChange;
./passwordupdate
import React from "react";
import { updateUsers, fetchUsers } from "./actions/appactions";
import FormChange from "./formchange";
var createReactClass = require("create-react-class");
const Update = createReactClass({
getIntitialState() {
return {
users: {}
};
},
componentWillReceiveProps(props) {
this.setState(props);
},
componentDidMount() {
fetchUsers(this.props.match.params.usersId)
.then(data => {
this.setState(state => {
state.users = data;
return state;
});
})
.catch(err => {
console.error("error", err);
});
},
handleSubmit(data) {
updateUsers(this.state.users.id, data);
},
render() {
return (
<div>
<FormChange
onSubmit={this.handleSubmit.bind}
password={this.state.users.password}
/>
</div>
);
}
});
export default Update;
//fetchusers function
export function fetchUsers(id) {
return fetch("https://localhost:44341/api/users/" + id, {
method: "GET",
mode: "cors"
})
.then(res => res.json())
.catch(err => err);
}
<FormChange
onSubmit={this.handleSubmit.bind(this)}
password={this.state.users.password}
/>
make this change and check
I'm not sure but you have data in handleSubmit as parameter but you don't pass it.
try this
You can call function like this:
handleSubmit=(data)=> {
updateUsers(this.state.users.id, data);
},
and call it
onSubmit={(data)=> this.handleSubmit(data)}
The problem was in ComponentDidMount(). The state was always null, had to change it to this
componentDidMount() {
fetchTheUsers(this.props.match.params.usersId)
.then(data => {
this.setState({
users: data
});
})
I did it that way initially because that's how it worked for my other update files. Hope this is useful to someone else.
import React from 'react';
import fetch from 'isomorphic-fetch';
import { lookup } from 'dns';
export default class Pagination extends React.Component {
constructor(props){
super(props);
this.state = {
contacts : [],
per:5,
page:1,
totalPages:null,
country:null
}
}
componentDidMount(){
document.getElementById('us').click()
}
handleCountry = (country=null) => {
const {per, page, contacts} = this.state;
if (country === null){
country = 'United States'
}
const url = `http://127.0.0.1:8000/api/users/?limit=${per}&page=${page}&country=${country}`
fetch(url)
.then(response => response.json())
.then(
json => {
this.setState({
contacts:json.data
})
}
)
}
loadMore = (country) => {
this.setState(prevState => ({
page: prevState.page + 1,
}), this.loadContacts(country))
}
handleCountry = (event) => {
this.setState({
country:event.target.value,
page:1
})
this.loadContacts(event.target.value);
}
render(){
return (
<div>
<div>
<label class="radio-inline">
<input type="radio" id="us" name="country" value="United States" onClick={this.handleCountry} />United States
</label>
<label class="radio-inline">
<input type="radio" id="india" name="country" value="India" onClick={this.handleCountry} />India
</label>
<label class="radio-inline">
<input type="radio" id="canada" name="country" value="Canada" onClick={this.handleCountry} />Canada
</label>
</div>
<ul className="contacts" style={{ width:'300px' }}>
{
this.state.contacts.map(contact =>
<li key={contact.id} style={{ padding:'5px 5px 5px 5px' }}>
<div className="contact" style={{ background:'#0099ff', padding:'10px', color:'white' }}>
<div>{ contact.id }</div>
<div>{ contact.country }</div>
<div>{ contact.name }</div>
</div>
</li>
)
}
</ul>
<button onClick={() => this.loadMore(this.state.country)}>Load More</button>
</div>
)
}
}
Here I am stuck with a issue in reactjs.
When i am clicking any radio button its calling handleCountry() method and passing event.
Then i am storing the event in state. Then calling handleCountry() function to fetch api.
But in handleCountry() method first loadContacts() method calling then it storing the data in state.
So I am not getting correct result.
I can i make call loadContacts() after successfully storing data in state inside loadContacts() method.
Please have a look.
Use callback method with setState to achieve the expected result, it will be executed after successful state update.
Like this:
handleCountry = (event) => {
let { value } = event.target;
this.setState({
country: value,
page:1
}, () => {
this.loadContacts(value);
})
}
Check React Doc for more detail about setState.