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;
Related
In this code I am unable to clear both the text fields even though I'm setting their states to blank after clicking on filter via this.Search function.
import React from 'react' import Axios from './Axios' import
'./index.css' export default class Practise extends React.Component {
constructor(props) {
super(props)
this.state = {
lists: [],
names: '',
emails: '',
arr: [],
}
this.Search = (names, emails) => {
const arr = this.state.lists.filter(item => {
if (item.name.includes(this.state.names) && item.email.includes(this.state.emails)) {
return true
} else {
return false
}
})
this.setState({names:''})
this.setState({emails:''})
console.log(arr)
}
}
componentDidMount() {
Axios.get('/comments').then(response => {
// console.log(response.data, 'data')
this.setState({ lists: response.data })
}).catch(response => {
console.log(response, 'Errored!!!')
this.setState({ errored: 'Error has Occured' })
})
}
render() {
const { lists, arr, names, emails } = this.state
return (
<>
<div >
<input type='text' onChange={(e) => this.setState({ names: e.target.value })} />
<input type='text' onChange={(p) => this.setState({ emails: p.target.value })} />
<button onClick={()=>this.Search()}>Filter</button>
</div>
<div>
{lists.length ? lists.map(item =>
<div className='divone' key={item.id}>
Id:- {item.id} <br />
Name:- {item.name} <br />
Email:- {item.email}</div>) : null}
</div>
</>
)
}
};
You have to add the value prop to both of the inputs.After that,
if you change the state to a blank string, the value of inputs will also get blank.Here is an example -
<input type='text' value={this.state.names} onChange={(e) => this.setState({ names: e.target.value })} />
<input type='text' value={this.state.emails} onChange={(p) => this.setState({ emails: p.target.value })} />
It should work.
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)
}
I am making a request to axios and receiving some data, which then I setState to my component's state:
componentDidMount() {
instance
.get("https://bartering-application.firebaseio.com/myitems.json")
.then(response => {
var obj = Object.values(response.data);
console.log("parsed", obj);
this.setState({ addedItem: obj });
})
.catch(error => {
console.log(error);
});
}
So my state, which had state property addedItem now gets objs as value.
Then, in my render() method I am rendering a child component, which receives props from my state(whose properties updated through componentDidMount):
render() {
const items = this.state.addedItem.map(item => {
return (
<MyItem
title={item.Title}
description={item.Description}
condition={item.Condition}
url={item.URL}
/>
)
})
}
This works fine, however I can see the result of child component displayed, only if I reload the browser. How can I make the app reload automatically whenever a state property (in my case addedItem) changes ? Which lifecycle method should I use to rerender the DOM immidiately when the state property changes ?
The full component code is below:
class MyItems extends Component {
constructor(props) {
super(props);
const initial_state = {
image: null,
url: "",
uploadStatus: false,
itemTitle: "",
itemDescription: "",
barteringCondition: "",
addedItem: []
};
this.state = initial_state;
this.handleChange = this.handleChange.bind(this);
this.handleUpload = this.handleUpload.bind(this);
}
componentDidMount() {
instance
.get("https://bartering-application.firebaseio.com/myitems.json")
.then(response => {
var obj = Object.values(response.data);
console.log("parsed", obj);
this.setState({ addedItem: obj });
})
.catch(error => {
console.log(error);
});
}
// componentDidUpdate(prevState){
// if (prevState !== this.state){
// window.location.reload();
// }
// }
handleChange = e => {
if (e.target.files[0]) {
const image = e.target.files[0];
this.setState(
() => ({ image, uploadStatus: true }),
() => console.log(this.state.image.name)
);
}
};
handleUpload = () => {
if (!this.state.uploadStatus) {
alert("No item image was uploaded.");
return null;
}
const { image } = this.state;
const uploadTask = storage.ref(`images/${image.name}`).put(image);
uploadTask.on(
"state_changed",
snapshot => {
// demonstrate the image upload progress
},
error => {
// error function
console.log(error);
},
() => {
//complete function
storage
.ref(`images`)
.child(image.name)
.getDownloadURL()
.then(url => {
console.log(url);
alert("uploaded!");
this.setState({ url });
// When uploadded image url is received, collect all item data into myNewItem object and post this record to Firebase Database
const myNewItem = {
Title: this.state.itemTitle,
Description: this.state.itemDescription,
URL: this.state.url,
Condition: this.state.barteringCondition
};
instance.post("/myitems.json", myNewItem).then(error => {
console.log(error);
});
});
}
);
};
titleChangeHandler = event => {
this.setState({ itemTitle: event.target.value });
};
descriptionChangeHandler = event => {
this.setState({ itemDescription: event.target.value });
};
render() {
const items = this.state.addedItem.map(item => {
return (
<MyItem
title={item.Title}
description={item.Description}
condition={item.Condition}
url={item.URL}
/>
);
});
return (
<Auxiliary>
<div className={classes.MyItems}>
<div className={classes.container}>
<div className={classes.MyItems__left__container}>
<div className={classes.Items__Upload}>
{" "}
<p>Upload your barter item picture below:</p>
<br />
<input type="file" onChange={this.handleChange} />
<br />
<p style={{ padding: "0px", margin: "10px" }}>
Title of the item:
</p>
<input type="text" onChange={this.titleChangeHandler} />
</div>
<div className={classes.Items__Info}>
<div className={classes.Items_Description}>
<p>Describe your item:</p>
<textarea
rows="15"
cols="30"
onChange={this.descriptionChangeHandler}
/>
</div>
<div className={classes.Items_Bartering__Condition}>
<p>Bartering condition:</p>
<br />
<div className={classes.Items__Bartering_Condition_Options}>
<fieldset id="barter-options">
<input type="radio" name="with-similar" />
With a similar item <br />
<input type="radio" name="with-similar-with-extra" />
With a similar item with extra payment <br />
<input type="radio" name="with" />
With
<input
style={{ height: "11px", maxWidth: "240px" }}
type="text"
name="special-item"
placeholder="e.g. Rolex Watch model 16233"
/>
<br />
<input type="radio" name="as-gift" />I give this item as
gift! <br />
<input type="radio" name="as-gift" />I give this item as
gift to
<input
style={{ height: "11px", maxWidth: "120px" }}
type="text"
placeholder="e.g. students"
/>
<br />
</fieldset>
<div className={classes.Items_addButton}>
<button onClick={this.handleUpload}>+ADD</button>
</div>
</div>
</div>
</div>
</div>
<div className={classes.MyItems__right__container}>
<div className={classes.MyItems__right__container__header}>
<p>My items</p>
</div>
<div className={classes.MyItems__right__container__block}>
{/* <MyItem title={this.state.itemTitle} description={this.state.itemDescription} condition={this.state.barteringCondition} url={this.state.url} /> */}
{items}
</div>
</div>
</div>
</div>
</Auxiliary>
);
}
}
export default MyItems;
the child MyItem component:
import React, { useEffect } from "react";
import Auxiliary from "../hoc/Auxiliary";
import { storage } from "../Firebase/Fire";
import classes from "../MyItem/MyItem.module.css";
const MyItem = props => {
return (
<Auxiliary>
<div className={classes.MyItem}>
<h4>Item: {props.title}</h4>
<img
src={props.url || "https://via.placeholder.com/140x100"}
height="100"
width="140"
/>
<p>Description: {props.description}</p>
<p>Bartering condition: {props.condition}</p>
</div>
</Auxiliary>
);
};
export default MyItem;
I solved this by adding window.location.reload() method, which triggers the rerendering of DOM immediately after the user image was successfully uploaded to the FIrebase Database. So here is the code:
instance.post('/myitems.json', myNewItem)
.then(response => {window.location.reload();} )
.then(error => {
console.log(error);
})
Firebase will gives you the response in the form of object. We need to convert this to array and use it. Try the below logic at the start of your render function:
const fetchedItems = [];
for(let key in this.state.addedItem) {
fetchedItems.push({
...this.state.addedItem[key],
id: key
});
}
const items = fetchedItems.map(item => {
return (
<MyItem
title={item.Title}
description={item.Description}
condition={item.Condition}
url={item.URL}
/>
);
});
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.
Given a react form with multiple radio buttons and a text input that is visible only when the other option radio button is selected, I currently have the submit button disabled until a radio button is selected. However, if the other option is selected, the submit button will still work even if there is no text in the input field associated with it. How can I check the length of the input box if and only if the other option is selected?
class CancelSurvey extends React.Component {
constructor (props) {
super(props)
this.state = {
reasons: [],
reason: {},
otherReasonText: undefined,
submitting: false
}
this.processData = this.processData.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
this.setReason = this.setReason.bind(this)
this.setOtherReasonText = this.setOtherReasonText.bind(this)
this.otherReason = {
reason_id: 70,
client_reason: 'other'
}
}
componentDidMount () {
this.fetchSurvey()
}
/**
* Fetch reasons
*/
fetchSurvey (cb) {
superagent
.get('/api/user/survey')
.then(this.processData)
}
processData (data) {
this.setState({ reasons: data.body })
}
async handleSubmit (e) {
e.preventDefault()
await this.setState({ submitting: true })
const { reason, otherReasonText } = this.state
superagent
.post('/api/user/survey')
.send({
optionId: reason.reason_id,
optionText: reason.client_reason,
otherReasonText
})
.then(async (data) => {
await this.setState({ submitting: false })
if (data.body.success) {
this.props.setStep(OFFER)
}
})
}
setOtherReasonText (e) {
this.setState({ otherReasonText: e.target.value })
}
setReason (reason) {
this.setState({ reason })
}
/**
* render
*/
render (props) {
const content = this.props.config.contentStrings
const reasons = this.state.reasons.map((reason, i) => {
return (
<div
className='form-row'
key={i}>
<input type='radio'
id={reason.reason_id}
value={reason.client_reason}
name='reason'
checked={this.state.reason.reason_id === reason.reason_id}
onChange={() => this.setReason(reason)} />
<label htmlFor={reason.reason_id}>{reason.client_reason}</label>
</div>
)
})
return (
<div className='cancel-survey'>
<form className='cancel-survey-form'>
{ reasons }
<div className='form-row'>
<input
type='radio'
id='other-option'
name='reason'
onChange={() => this.setReason(this.otherReason)} />
<label htmlFor='other-option'>
Other reason
</label>
</div>
{ this.state.reason.reason_id === 70 &&
<div>
<input
className='valid'
type='text'
id='other-option'
name='other-text'
placeholder="placeholder"
onChange={this.setOtherReasonText} />
</div>
}
<div className='button-row'>
<button
disabled={!this.state.reason.client_reason}
className={btnClassList}
onClick={this.handleSubmit}>
<span>Submit</span>
</button>
</div>
</form>
</div>
)
}
}
export default CancelSurvey
disabled={
!this.state.reason.client_reason
||
(this.state.reason.client_reason === 'other' && !this.state.otherReasonText)
}
If you want to make sure otherReasonText is not just empty spaces, use otherReasonText: '' as initial state then check !this.state.otherReasonText.trim().
Do some conditional logic before like:
const reasonId = this.state.reason.reason_id;
const otherReasonText = this.state.otherReasonText;
const clientReason = this.state.reason.client_reason;
const shouldDisableButton = !clientReason || (reasonId === 70 && otherReasonText.length === 0)
...
<div className='button-row'>
<button
disabled={shouldDisableButton}
className={btnClassList}
onClick={this.handleSubmit}>
<span>Submit</span>
</button>
</div>