I'm just starting my adventure in react.
I just want to do the number validation.
I found many solutions but none work. from here I took the solution Only numbers. Input number in React
I don't know further this is happening
this is the code with the added solution I found.
import React, { Component } from 'react';
import validator from 'validator';
export default class GetApp extends Component {
state = {
// creditId: '',
err: false,
name: '',
firstName: '',
lastName: '',
pesel: '',
productName: '',
value: ''
}
constructor(props) {
super(props);
this.state = {
creditId: ''
}
}
onChange = (e) => {
//this.setState({ creditId: e.target.value });
}
handleChange(evt) {
const creditId = (evt.target.validity.valid) ? evt.target.value : this.state.creditId;
this.setState({ creditId });
}
handleSubmit = event => {
event.preventDefault();
fetch(`http://localhost:8200/credit/getCredit/${this.state.creditId}`)
.then(res => {
if (res.ok) {
return res
}
}).then(res => res.json())
.then(data => {
this.setState({
err: false,
name: data.credit.name,
firstName: data.customer.firstName,
lastName: data.customer.lastName,
pesel: data.customer.pesel,
productName: data.product.productName,
value: data.product.value
})
})
.catch(err => {
console.log(err);
this.setState({
err: true
})
})
}
render() {
let content = null;
if (!this.state.err && this.state.creditId) {
content = (
<div>
<p>Name: {this.state.name}</p>
<p>First Name: {this.state.firstName}</p>
<p>Last Name: {this.state.lastName}</p>
<p>PESEL: {this.state.pesel}</p>
<p>Product Name: {this.state.productName}</p>
<p>Value: {this.state.value}</p>
</div>
)
}
return (
<form onSubmit={this.handleSubmit}>
<div className="container">
<h2>Get Credit</h2>
<label>Credit Number:</label>
<input type='text' name="creditId" value={this.state.creditId} pattern="[0-9]*" onInput={this.handleChange.bind(this)} />
<div>
<button type="submit">Submit</button>
<p>{this.state.err ? `Dont search: ${this.state.creditId}` : content}</p>
<div>
</div>
</div>
</div>
</form>
)
}
}
Thanks for help
You could also change the input type to number https://www.w3schools.com/tags/att_input_type_number.asp . This won't allow users to set anything else but numeric (0-9) characters and is a bit more strict.
Related
I'm learning React with Strapi.
I made a form to add data to the database. I manage to send my img in the upload api and the text data in the Animals api, however, I can't manage to link the two. Ie to make sure that the image also goes on the animal that I add.
Thank you all for your future help.
import React from "react";
import { useForm } from "react-hook-form";
import axios from "axios";
import React from "react";
import { useForm } from "react-hook-form";
import axios from "axios";
class AddAnimal extends React.Component {
constructor(props) {
super(props);
this.state = {
modifiedData: {
nom: '',
description: '',
image : '',
races: [],
images :[],
},
allRaces: [],
error: null,
};
}
onImageChange = event => {
console.log(event.target.files);
this.setState({
images: event.target.files,
});
};
componentDidMount = async () => {
try {
const response = await axios.get('http://localhost:1337/api/races');
this.setState({ allRaces: response.data.data });
} catch (error) {
this.setState({ error });
}
};
handleInputChange = ({ target: { name, value } }) => {
this.setState(prev => ({
...prev,
modifiedData: {
...prev.modifiedData,
[name]: value,
},
}));
};
handleSubmit = async e => {
e.preventDefault();
const formData = new FormData();
Array.from(this.state.images).forEach(image => {
formData.append('files', image);
});
try {
const response = await axios.post('http://localhost:1337/api/animaux?populate=*',
{
"data": {
nom: this.state.modifiedData.nom,
Description: this.state.modifiedData.description,
image : this.images,
races: this.state.modifiedData.races
}
})
axios
.post(`http://localhost:1337/api/upload`, formData, {
headers: { 'Content-Type': 'multipart/form-data' },
})
console.log(response);
} catch (error) {
this.setState({ error });
}
};
renderCheckbox = race => {
const {
modifiedData: { races },
} = this.state;
const isChecked = races.includes(race.id);
const handleChange = () => {
if (!races.includes(race.id)) {
this.handleInputChange({
target: { name: 'races', value: races.concat(race.id) },
});
} else {
this.handleInputChange({
target: {
name: 'races',
value: races.filter(v => v !== race.id),
},
});
}
};
return (
<div key={race.id}>
<label htmlFor={race.id}>{race.attributes.nom}</label>
<input
type="checkbox"
checked={isChecked}
onChange={handleChange}
name="races"
id={race.id}
/>
</div>
);
};
render() {
const { error, allRaces, modifiedData } = this.state;
if (error) {
return <div>An error occured: {error.message}</div>;
}
return (
<div className="App">
<form onSubmit={this.handleSubmit}>
<h3>Ajouter un animal</h3>
<br />
<label>
Name:
<input
type="text"
name="nom"
onChange={this.handleInputChange}
value={modifiedData.name}
/>
</label>
<label>
Description:
<input
type="text"
name="description"
onChange={this.handleInputChange}
value={modifiedData.description}
/>
</label>
<input type="file" name="images" value={this.images} onChange={this.onImageChange}/>
<div>
<br />
<b>Select races</b>
{allRaces.map(this.renderCheckbox)}
</div>
<br />
<button type="submit">Ajouter</button>
</form>
</div>
);
}
}
export default AddAnimal;
there are similiar questions in stackoverflow but I I did not find what I was looking for.
I have a donorDonationForm which is a class componenet that connected to the redux state. The porpuse of that componenet is to collect inormation about a person that want to donate electronics items. At this point, I want to save those items in an array (maybe with an object in the future).
my redux state save the donor info and the reducer looks like this:
import {CHANGE_INPUT_FIELD} from '../utils/constants';
const initialStateInputs = {
// update the state
donorFields: {
name: '',
phone: '',
area: '',
yeshuv: '',
address: ''
// dateOfOffer: ''
},
donationFields: {
// donorID: '',
// vulonteerID: '',
type: [],
quantity: 1,
status: 'NOT_HANDLED',
comments: ''
// lastDateHandled: ''
}
// }, items: [ //need to add quantity
// {id: 1, name: "LAPTOP", isChecked: false, label: 'מחשב'},
// {id: 2, name: "HEADPHONES", isChecked: false, label: 'אוזניות'},
// {id: 3, name: "OTHER", isChecked: false, label: 'אחר'},
// ]
}
export const donorDonationInputsReducer = ( state = initialStateInputs, action={} ) => {
switch(action.type) {
case CHANGE_INPUT_FIELD:
return Object.assign( {}, state,
{
donorFields : {...state.donorFields,...action.payload},
donationFields: {...state.donationFields,...action.payload},
// items : {...state.items,...action.payload},
// isChecked: action.payload
})
default:
return state;
}
}
As you can see the items is commented by now, and I am managing the state of the item in a local state, and that how the comp looks like:
import React, {Component} from 'react';
import { connect } from 'react-redux';
import { setInputField } from '../actions/formAction';
import CheckBox from '../components/CheckBox/CheckBox';
import FormInput from '../components/FormInput/FormInput';
import {selectAreasOptions_2} from '../utils/constants';
import "./form.css";
const mapStateToProps = (state) => {
return {
donorFields: state.donorDonationInputsReducer.donorFields,
donationFields: state.donorDonationInputsReducer.donationFields
}
}
const mapDispatchToProps = dispatch => {
return {
onInputChange: event => {
const {name, value} = event.target;
dispatch(setInputField( { [name]:value} ) )
}
}
}
class donorDonationForm extends Component {
constructor() {
super();
this.state = {
items: [
{id: 1, name: "LAPTOP", isChecked: false, label: 'מחשב'},
{id: 2, name: "HEADPHONES", isChecked: false, label: 'אוזניות'},
{id: 3, name: "OTHER", isChecked: false, label: 'אחר'},
]
,
type: []
}
}
handleCheckChieldElement = (event) => {
let {items, type} = this.state;
let arr = [];
items.forEach(item => {
if (item.name === event.target.value) {
item.isChecked = event.target.checked;
// console.log(`item.name :${item.name }`);
// console.log(`event.target.value :${event.target.value}`);
// console.log(`event.target.checked :${event.target.checked}`);
}
})
items.map(item => item.isChecked ? arr.push(item.name) : null)
this.setState({items: [...items], type: [...arr]});
}
onButtonSubmit = (event) => {
console.log(this.props.donorFields);
event.preventDefault();
fetch('http://localhost:8000/api/donor', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
...this.props.donorFields
})
})
.then(response => response.json())
.then(resp => console.log(resp))
.catch( err => console.log(err) )
}
// componentDidUpdate(prevProps, prevState) {
// const {items, type} = this.state;
// // const type = [];
// if (prevState.items !== items) {
// console.log('items state has changed');
// items.map (item => item.isChecked ?
// this.setState({type: [...type,item.name]}) : null)
// // if (item.isChecked) { type.push(item.name) } ;
// console.log(type);
// }
// }
render() {
console.log(this.state.items);
console.log(this.state.type);
const { onInputChange } = this.props;
return (
<div>
<h1 className="pt4"> פרטי תורם</h1>
<form className=" black-80 pt2" >
<section className=" grid-container">
<FormInput
id="name"
name="name"
type="text"
onInputChange={onInputChange}
label="שם "
required
/>
<FormInput
id="phone"
name="phone"
type="tel"
onInputChange={onInputChange}
label="מספר טלפון "
required
/>
<FormInput
id="address"
name="address"
type="text"
onInputChange={onInputChange}
label="כתובת "
required
/>
<FormInput
id="yeshuv"
name="yeshuv"
type="text"
onInputChange={onInputChange}
label="עיר "
required
/>
<FormInput
id="comments"
name="comments"
onInputChange={onInputChange}
label="הערות "
required
/>
<FormInput
id="area"
name="area"
onInputChange={onInputChange}
label="איזור "
select={selectAreasOptions_2}
/>
{/* type */}
<div className="measure-narrow">
<label htmlFor="type" className="f5 b db mb2">מעוניין לתרום
<span className="normal black-60"> *</span>
</label>
{
this.state.items.map( (item, i) => {
return (
<CheckBox
key={i}
onChange={this.handleCheckChieldElement}
checked={ item.isChecked }
value= {item.name}
label = {item.label}
/>
);
})
}
</div>
</section>
<input type="submit" value="שלח"
className="b bg-light-blue pa2 hover pointer"
onClick={this.onButtonSubmit}
/>
</form>
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(donorDonationForm);
My main goal is that the type array - the final donation, will update the redux state before submitting this form. I tried with componentDidUpdate but didn't make it. What is the best way for tracking the checked items, updating the array and then update the type array which is the final donation in the redux state? should I do that in the onButtonSubmit method - before sending the data to the server (and thats way saving the looping over the items array for searching the checked elements) ?
Better approach would be do inside onButtonSubmit
Let me briefly explain the tasks:
inputChangeHandler to update this.state.items
Go with the final this.state.items value Array of items inside onButtonSubmit
After getting API response update the application level Redux state with Array of items.
Note: Dispatch the action. Reducer will update the Redux state. Following code will do this:
// Action
export const setItems = (data) => (dispatch) => {
dispatch({type: 'SET_ITEMS', payload: data})
}
// mapDispatchToProps
const mapDispatchToProps = (dispatch) =>
bindActionCreators(
{
setItems,
...others
},
dispatch
)
// onSubmitButton
onButtonSubmit = (event) => {
console.log(this.props.donorFields);
event.preventDefault();
fetch('http://localhost:8000/api/donor', {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
...this.props.donorFields
})
})
.then(response => this.props.setItems(response.json())) // will update the state.
.then(resp => console.log(resp))
.catch( err => console.log(err) )
}
// Reducer
export const donorDonationInputsReducer = ( state = initialStateInputs, action={} ) => {
switch(action.type) {
case CHANGE_INPUT_FIELD:
return Object.assign( {}, state,
{
donorFields : {...state.donorFields,...action.payload},
donationFields: {...state.donationFields,...action.payload},
// items : {...state.items,...action.payload},
// isChecked: action.payload
})
case SET_ITEMS:
return {
...state,
items: action.payload
}
default:
return state;
}
}
That's it.
Happy Coding :)
I present my problem to you
In the following code, I'm trying to retrieve phone numbers from an API and then show them in a Card; in each card, I have a different number which is displayed
and also in each card, I have an input field to enter the phone number which I obtained before.
My problem is that I don't want to fill in the input manually with the recovered number.
So basically I would like to start my function without having to fill in this field manually.
Do you have any idea how to do this?
I tried to simplify the code so that it is as clear as possible
Thanks for your help Neff
import React, { Component } from 'react';
import { CardText, Card,Row, Col, CardTitle, Button } from 'reactstrap';
import axios from 'axios'
const entrypoint = process.env.REACT_APP_API_ENTRYPOINT+'/api';
class AdminPage extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
message: {
to: '',
body: 'hola amigo :)'
},
submitting: false,
error: false
};
this.onHandleChange = this.onHandleChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit(event) {
event.preventDefault();
this.setState({ submitting: true });
fetch('/api/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(this.state.message)
})
.then(res => res.json())
.then(data => {
if (data.success) {
this.setState({
error: false,
submitting: false,
message: {
to: '',
body: ''
}
});
} else {
this.setState({
error: true,
submitting: false
});
}
});
}
// rest of the component
onHandleChange(event) {
const name = event.target.getAttribute('name');
this.setState({
message: { ...this.state.message, [name]: event.target.value }
});
}
getRandom = async () => {
const res = await axios.get(
entrypoint + "/alluserpls"
)
this.setState({ data: res.data })
}
componentDidMount() {
this.getRandom()
}
render() {
let datas = this.state.data.map(datass => {
const status = JSON.parse(localStorage.getItem("validated-order")||"{}")[datass.id];
return (
<div>
< Col sm="12" key={datass.id} className="wtfFuHereIsForOnlyBackGroundColorForCol12Nice">
<div key="a">
<Card body className="yoloCardBody">
<CardText> Téléphone {datass.phone}</CardText>
<form
onSubmit={this.onSubmit}
className={this.state.error ? 'error sms-form' : 'sms-form'} >
<div>
<input
type="tel"
name="to"
id="to"
value={this.state.message.to}
onChange={this.onHandleChange}
/>
</div>
<Button className="buttonForLancerMaybe" type="submit" disabled=
{this.state.submitting}>SMS</Button>
</form>
</Card>
</div>
</Col>
</div>
)
})
return (
<div> <div>
<div>
{datas}
</div>
</div>
</div>
<div className="box">
</div>
</div>
)
}
}
export default AdminPage
So I guess this little change in your code will help you, separating the logic and making a new component for your form section would be your solution. say we have a component called "SmsForm" so first, you need to import it in your current component:
import SmsForm from "../SmsForm/Loadable";
and then you pass your phone number as a prop to this SmsForm like this:
let datas = this.state.data.map(datass => {
const status = JSON.parse(localStorage.getItem("validated-order") || "{}")[datass.id];
return (
<div>
< Col sm="12" key={datass.id} className="wtfFuHereIsForOnlyBackGroundColorForCol12Nice">
<GridLayout className="GridlayoutTextOnlyForGridOuiAndHeigthbecauseHeigthWasBug" layout={layout} cols={12} rowHeight={30} width={1200}>
<div key="a">
<Card body className="yoloCardBody">
<CardText> Téléphone {datass.phone}</CardText>
<SmsForm phone={datass.phone}/>
</Card>
</div>
</GridLayout>
</ Col>
</div>
)
})
and SmsForm would be sth like this:
import React from 'react';
...
export class SmsForm extends React.Component {
constructor(props) {
super(props);
this.state = {
message: {
to: props.phone,
body: 'hola amigo :)'
},
submitting: false,
error: false
};
this.onHandleChange = this.onHandleChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit(event) {
event.preventDefault();
this.setState({ submitting: true });
fetch('/api/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(this.state.message)
})
.then(res => res.json())
.then(data => {
if (data.success) {
this.setState({
error: false,
submitting: false,
message: {
to: '',
body: ''
}
});
} else {
this.setState({
error: true,
submitting: false
});
}
});
}
// rest of the component
onHandleChange(event) {
const name = event.target.getAttribute('name');
this.setState({
message: { ...this.state.message, [name]: event.target.value }
});
}
render() {
return (
<form
onSubmit={this.onSubmit}
className={this.state.error ? 'error sms-form' : 'sms-form'} >
<div>
<input type="tel" name="to" id="to" value={datass.phone} onChange={e => this.onHandleChange(e, e.target.value)}/>
</div>
<Button className="buttonForLancerMaybe" type="submit" disabled=
{this.state.submitting}>SMS</Button>
</form>
);
}
}
export default SmsForm;
I am trying to validate a form with two inputs. If each input has at least a character or more, the button should be enabled.
The problem here is that the state is always one step behind. I handled validation in the callback but it still didnt solve the problem. Please help anyone!
state = {
name : '',
nameIsValid: false,
zip : '',
zipIsValid: false,
allIsValid: false
}
handleChange = (event) => {
this.setState({
[event.target.name] : event.target.value,
}, ()=>this.handleValidation())
}
handleValidation = () => {
if(this.state.name.length > 0){
this.setState({nameIsValid : true})
} else {
this.setState({nameIsValid: false})
}
if(this.state.zip.length > 0){
this.setState({zipIsValid : true})
} else {
this.setState({zipIsValid: false})
}
if(this.state.nameIsValid && this.state.zipIsValid){
this.setState({allIsValid: true})
}
}
render() {
return (
<div>
Name: <input name="name" onChange={this.handleChange} value={this.state.name}/><br />
Zip: <input name="zip" onChange={this.handleChange} value={this.state.zip}/><br />
<button disabled={!this.state.allIsValid}>Proceed</button>
</div>
)
}
I think it's down to the multiple setStates you're using. You can actually make your code a little more concise and make this work at the same time.
class App extends React.Component {
state = {
name: '',
nameIsValid: false,
zip: '',
zipIsValid: false,
allIsValid: false
};
handleChange = (event) => {
// Destructure the name and value from the target
const { target: { name, value } } = event;
this.setState({
// Set only that changed input valid property to true or false
// depending on whether it has length
[`${name}IsValid`]: value.length > 0 || false,
[name]: value
}, this.validate);
}
validate = () => {
// Then just set the allIsValid property based on the
// whether the other properties are both true
this.setState((state) => ({
allIsValid: state.nameIsValid && state.zipIsValid
}));
}
render() {
return (
<div>
Name:
<input name="name" onChange={this.handleChange} value={this.state.name}/>
<br />
Zip:
<input name="zip" onChange={this.handleChange} value={this.state.zip} />
<br />
<button disabled={!this.state.allIsValid}>Proceed</button>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
state = {
name: '',
zip: ''
}
handleChange = event => {
this.setState({
[event.target.name]: event.target.value
});
}
validateForm = () => {
return this.state.name.length > 0 && this.state.zip.length > 0;
}
<button disabled={!this.validateForm()}>Proceed</button>
I'm working on a self project React for front-end and node for back-end, part of the app is that when a user submits an image url it counts the entries and it updates in the server then it should re-render on the front-end to the screen. The problem is it doesn't re-render, i have console.log tested and everything works from the server side, the problem is in the setState in react wont re-render and i'm hoping any one help me understand why it is not working?
Here is the code related to my problem
class App extends Component {
constructor() {
super()
this.state = {
input: '',
imgUrl: '',
box: {},
route: 'signin',
isSignedIn: false,
user: {
id: '',
name: '',
email: '',
entries: 0,
joined: '',
},
}
}
loadUser = data => {
this.setState({
user: {
id: data.id,
name: data.name,
email: data.email,
entries: data.entries,
joined: data.joined,
},
})
}
onButtonSubmit = () => {
fetch('http://localhost:3001/image', {
method: 'put',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: this.state.user.id,
}),
})
.then(response => response.json)
.then(count => {
this.setState({ ...this.state.user, entries: count })
})
.catch(err => console.log(err))
}
}
render() {
return (
<div className="App">
<Navigation
isSignedIn={this.state.isSignedIn}
onRouteChange={this.onRouteChange}
/>
{this.state.route === 'home' ? (
<div>
<Rank
name={this.state.user.name}
entries={this.state.user.entries}
/>
<ImageLinkForm
onInputChange={this.onInputChange}
onButtonSubmit={this.onButtonSubmit}
/>
<FaceRecognition box={this.state.box} imgUrl={this.state.imgUrl} />
</div>
) : this.state.route === 'signin' ? (
<Signin loadUser={this.loadUser} onRouteChange={this.onRouteChange} />
) : (
<Register
loadUser={this.loadUser}
onRouteChange={this.onRouteChange}
/>
)}
</div>
)
}
this code is suppose to print the entries count on the screen but its not
this.setState({...this.state.user, entries: count})
here is the server side where entries gets updated and sent to the front-end
app.put('/image', (req, res) => {
const { id } = req.body
let found = false
database.users.forEach(user => {
if (user.id === id) {
found = true
user.entries++
return res.json(user.entries)
}
})
if (!found) {
res.status(400).json('not found')
}
})
here is the rank Component where entries gets printed
import React from 'react';
const Rank = ({ name, entries}) => {
return (
<div>
<div className='rank'>
{`${name} your current rank is...`}
</div>
<div className='white f1 '>
{entries}
</div>
</div>
);
}
export default Rank;
Thanks in advance.
I don’t see any use of doing ...this.state.user in setState So
Change
this.setState({...this.state.user, entries: count})
To
this.setState({entries: count})