Bootstrap Radio Buttons in React - Not Showing Loaded Value - reactjs

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>
)
}

Related

Display loader before a react-apexchart is displayed

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.

react - this = undefined, how to pass the prop into my function

I have passed my user ID into my 'OrderMessages' component but in my function says undefined. When my user submits a messages using the form in the handleFormSubmit function I need the UserID and the datetime of the message. I have managed to get the date and time but when trying to console log to get the UserID I keep getting an error. I have tried this.props.... and this.state but both say undefined, can you please help. In my constructor I have tested using const UserId = props.location.state.UserID; and in debug I can see this has correctly got the UserID so im not sure how to get it into my hadleFormSubmit function.
import React from "react";
import Moment from "moment";
import { Form, Button } from "react-bootstrap";
class OrderMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: false,
checkboxes: [],
selectedId: [],
formLableSelected: "",
formSelectedSubject: "",
formSelectedSubjectId: "",
formNewSubject: "",
formChainID: "",
formMessageBody: "",
userId: '',
};
const UserId = props.location.state.UserID;
}
componentDidMount() {
this.setState({ isLoading: true });
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url =
"myURL" +
this.props.location.state.orderNumber;
fetch(proxyurl + url)
.then((res) => res.json())
.then((data) => this.setState({ data: data, isLoading: false }));
}
handleClick = (id) => {
if (this.state.selectedId !== id) {
this.setState({ selectedId: id });
} else {
this.setState({ selectedId: null });
}
};
setformSubjectID(messageSubject) {
if (messageSubject.subject === this.state.formSelectedSubject) {
this.setState({ formSelectedSubjectId: messageSubject.messageSubjectId });
}
}
handleChangeSubject = (event) => {
this.setState({ formSelectedSubject: event.target.value });
this.state.data.message_Subjects.map((ms) => this.setformSubjectID(ms));
};
handleFormSubmit(e) {
e.preventDefault();
// get current time
let submit_time = Moment().format("ddd DD MMM YYYY HH:mm:ss");
console.log("messageDatetime", submit_time);
// get user id THIS IS WHAT DOESN’T WORK
console.log("messageSentFrom", this.state.userId);
console.log("messageSentFrom", this.props.location.state.UserID);
}
render() {
const { data, isLoading } = this.state;
if (isLoading) {
return <p>Loading ...</p>;
}
if (data.length === 0) {
return <p> no data found</p>;
}
console.log("mess: ", data);
return (
<div>
<div className="sendMessageContent">
<Form className="sendMessageForm" onSubmit={this.handleFormSubmit}>
<Form.Group className="formRadio">
<Form.Check
className="formRadiob"
type="radio"
label="New chat"
value="new"
name="neworexisitng"
id="New Message"
onChange={this.onFormMessageChanged}
defaultChecked
/>
<Form.Check
className="formRadiob"
type="radio"
label="Reply to exisiting chat"
value="reply"
name="neworexisitng"
id="exisiting Message"
onChange={this.onFormMessageChanged}
/>
</Form.Group>
{this.returnCorrectFormFields(data)}
<Form.Group>
<Form.Label>Message Body</Form.Label>
<Form.Control as="textarea" rows={3} />
</Form.Group>
<Button variant="primary" type="submit">
Send Message
</Button>
</Form>
</div>
</div>
);
}
returnCorrectFormFields(data) {
if (this.state.formLableSelected === "new") {
return this.newMessageSubject(data);
} else {
return this.choseMessageSubject(data);
}
}
choseMessageSubject(data) {
return (
<Form.Group>
<Form.Label>Select the message subject</Form.Label>
<Form.Control as="select" onChange={this.handleChangeSubject}>
<option value="0">Choose...</option>
{data.message_Subjects.map((ms) => (
<option value={ms.subject}>{ms.subject}</option>
))}
</Form.Control>
</Form.Group>
);
}
newMessageSubject(data) {
return (
<Form.Group>
<Form.Label>Enter Message Subject</Form.Label>
<Form.Control type="text" placeholder="Enter message subject" />
</Form.Group>
);
}
onFormMessageChanged = (event) => {
this.setState({
formLableSelected: event.target.value,
});
};
getAllMessageInChain(messageChain) {
return (
<div className="messageHistory">
<div className="messageHistoryHeader">
<div className="innerMS-history-body">Message</div>
<div className="innerMS">Date and Time</div>
<div className="innerMS">Message sent by</div>
</div>
{messageChain.map((ms) => (
<div className="messageHistoryBody">
<div className="innerMS-history-body">{ms.messageBody}</div>
<div className="innerMS">
{Moment(ms.dateTime).format("ddd DD MMM YYYY hh:mm:ss")}
</div>
<div className="innerMS">{ms.sentFromId}</div>
</div>
))}
</div>
);
}
getLatestMessageDateTime(messageChain) {
const lastmessage = messageChain.length - 1;
Moment.locale("en");
var dt = messageChain[lastmessage].dateTime;
return Moment(dt).format("ddd DD MMM YYYY hh:mm:ss");
}
}
export default OrderMessages;
The scope of this isn't the component in the function you're using.
Either change handleFormSubmit to this to bind this automatically.
handleFormSubmit = (e) => {
// .. your code
}
or bind this manually in the constructor
constructor() {
// ..other code
this.handleFormSubmit = this.handleFormSubmit.bind(this)
}

React Loader - Trying to get a loader when api request is made and to stop it when response is fetched

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

formik not changing value of input on event

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;

typeError: cannot read property 'users' of null in React

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.

Resources