I have almost finished building a simple calculator, using React.
I just have a trouble with multiple decimals. What I try to do is writing a condition but it doesn't work. Could you help me, please?
Here is a part of my code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '0'
};
}
addToInput = e => {
const value = e.target.value;
const oldValue = this.state.input;
if (this.state.input != '0') {
this.setState({ input: (this.state.input + value) });
} else if (value == '.' && oldValue.includes('.')) {
console.log('Mulitple decimals');
} else {
this.setState({ input: value });
}
};
render() {
return (<Button addToInput={ this.addToInput } />);
}
}
class Button extends React.Component {
render() {
return (
<div className="row">
<button
value="."
id="decimal"
onClick={ this.props.addToInput }
>.
</button>
<button
value="0"
id="zero"
onClick={ this.props.addToInput }
>0
</button>
<button
value="-"
id="subtract"
onClick={ this.props.addToInput }
>-
</button>
</div>
);
}
}
Thank you in advance!
Change you addToInput like this:
addToInput = e => {
const value = e.target.value;
const oldValue = this.state.input;
if (value === '.' && oldValue.includes('.')) {
console.log('Mulitple decimals');
return;
}
if (this.state.input !== '0') {
this.setState({ input: (this.state.input + value) });
} else {
this.setState({ input: value });
}
};
Why you have had a problem:
addToInput = e => {
const value = e.target.value;
const oldValue = this.state.input;
if (this.state.input !== '0') {
// after first addToInput you will end up here ALWAYS
this.setState({ input: (this.state.input + value) });
} else if (value === '.' && oldValue.includes('.')) {
// You will never be here because this.state.input !== '0' is always true after first addToInput
console.log('Mulitple decimals');
} else {
// you will end up here only when you lunch your addToInput first time
this.setState({ input: value });
}
};
You could look at the value coming in, check if it's a . and check if the input already has one. If it does, do nothing, otherwise add the value to the end of the input:
addToInput = e => {
const { value } = e.target;
const { input } = this.state;
if (value === "." && input.includes(".")) {
return;
}
this.setState({ input: `${input}${value}` });
};
Well regular expression will help you.
const regex = /^[1-9]\d*(\.\d+)?$/;
Then you can check your value:
regex.test('222') // true
regex.test('222.') // false
regex.test('222.0') // true
regex.test('222.0.1') // false
regex.test('222.01234') // true
regex.test('abc') // false
Related
I am referring to this tutorial for simple react autocomplete https://www.digitalocean.com/community/tutorials/react-react-autocomplete
But I have a slightly different requirement. Instead of typing something on the input field, I want all the suggestions to come up on clicking the input field. I am basically implementing a requirement where on clicking the input field, it should show user what are the available options.
Here is my sandbox https://codesandbox.io/s/distracted-easley-wdm5x
Specifically in the Autocomplete.jsx file (as mentioned below)
import React, { Component, Fragment } from "react";
import PropTypes from "prop-types";
class Autocomplete extends Component {
static propTypes = {
suggestions: PropTypes.instanceOf(Array)
};
static defaultProps = {
suggestions: []
};
constructor(props) {
super(props);
this.state = {
// The active selection's index
activeSuggestion: 0,
// The suggestions that match the user's input
filteredSuggestions: [],
// Whether or not the suggestion list is shown
showSuggestions: false,
// What the user has entered
userInput: ""
};
}
onChange = (e) => {
const { suggestions } = this.props;
const userInput = e.currentTarget.value;
// Filter our suggestions that don't contain the user's input
const filteredSuggestions = suggestions.filter(
(suggestion) =>
suggestion.toLowerCase().indexOf(userInput.toLowerCase()) > -1
);
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.value
});
};
onClick = (e) => {
this.setState({
activeSuggestion: 0,
filteredSuggestions: [],
showSuggestions: false,
userInput: e.currentTarget.innerText
});
};
onClick2 = (e) => {
console.log("text check", e.currentTarget.innerText);
if (e.currentTarget.innerText === "") {
const { suggestions } = this.props;
const filteredSuggestions = suggestions;
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.innerText
});
}
};
onKeyDown = (e) => {
const { activeSuggestion, filteredSuggestions } = this.state;
// User pressed the enter key
if (e.keyCode === 13) {
this.setState({
activeSuggestion: 0,
showSuggestions: false,
userInput: filteredSuggestions[activeSuggestion]
});
}
// User pressed the up arrow
else if (e.keyCode === 38) {
if (activeSuggestion === 0) {
return;
}
this.setState({ activeSuggestion: activeSuggestion - 1 });
}
// User pressed the down arrow
else if (e.keyCode === 40) {
if (activeSuggestion - 1 === filteredSuggestions.length) {
return;
}
this.setState({ activeSuggestion: activeSuggestion + 1 });
}
};
render() {
const {
onChange,
onClick2,
onClick,
onKeyDown,
state: {
activeSuggestion,
filteredSuggestions,
showSuggestions,
userInput
}
} = this;
let suggestionsListComponent;
if (showSuggestions) {
if (filteredSuggestions.length) {
suggestionsListComponent = (
<ul className="suggestions">
{filteredSuggestions.map((suggestion, index) => {
let className;
// Flag the active suggestion with a class
if (index === activeSuggestion) {
className = "suggestion-active";
}
return (
<li className={className} key={suggestion} onClick={onClick}>
{suggestion}
</li>
);
})}
</ul>
);
} else {
suggestionsListComponent = (
<div className="no-suggestions">
<em>No suggestions, you're on your own!</em>
</div>
);
}
}
return (
<Fragment>
<input
type="text"
onChange={onChange}
onKeyDown={onKeyDown}
value={userInput}
onClick={onClick2}
/>
{suggestionsListComponent}
</Fragment>
);
}
}
export default Autocomplete;
In the input element in return section,
<input
type="text"
onChange={onChange}
onKeyDown={onKeyDown}
value={userInput}
onClick={onClick2}
/>
I have added a onClick functionality that calls the function onClick2.
onClick2 = (e) => {
console.log("text check", e.currentTarget.innerText);
if (e.currentTarget.innerText === "") {
const { suggestions } = this.props;
const filteredSuggestions = suggestions;
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.innerText
});
}
};
My function simply returns all the suggestions back on clicking the input field. I am able to select items from suggestions and it gets put in the input field. But when I click on the input field again, the value disappears.
I want this autocomplete suggestion to only show once on clicking the empty input field and after selecting the item from list, I should be able to edit the value further.
What am I doing wrong?
Input values are not stored into innerText, but in value prop.
Look at this:
onClick2 = (e) => {
console.log("text check", e.currentTarget.innerText);
if (e.currentTarget.value === "") {
const { suggestions } = this.props;
const filteredSuggestions = suggestions;
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.value
});
}
};
This should solve your problem
You are doing the wrong check in onClick2 function. Instead of checking e.currentTarget.innerText === "", it has to be e.target.value as we are validating the text in input field.
onClick2 = (e) => {
console.log("text check", e.target.value);
if (e.target.value === "") {
const { suggestions } = this.props;
const filteredSuggestions = suggestions;
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.innerText
});
}
};
Here is the working link - https://codesandbox.io/s/jolly-meadow-5fr6x?file=/src/Autocomplete.jsx:1344-1711
I have a parent component which has timer component inside it. Timer starts at 15 minutes and count downs till 0. When my timer shows time as 0 I want to trigger a submit button event, submit button is inside Quiz Component (Quiz Component is also a child component of Parent Component). I found probably I can use MutationObserver when p tag changes. I am not sure whether it's the correct and only approach or there is better way to achieve this.
Parent Component:
import React, { Component } from 'react';
import '../css/App.css'
import Quiz from './Quiz';
import Timer from './Timer';
import { connect } from 'react-redux';
import { ActionTypes } from '../redux/constants/actionTypes';
import { saveQuizAll, getQuizIndex } from '../commonjs/common.js';
const mapStateToProps = state => { return { ...state.quiz, ...state.quizAll } };
const mapDispatchToProps = dispatch => ({
onQuizLoad: payload => dispatch({ type: ActionTypes.QuizLoad, payload }),
onQuizChange: payload => dispatch({ type: ActionTypes.QuizAnswerAll, payload }),
onPagerUpdate: payload => dispatch({ type: ActionTypes.PagerUpdate, payload })
});
class QuizContainer extends Component {
state = {
quizes: [
{ id: 'data/class1.json', name: 'Class 1' },
{ id: 'data/class2.json', name: 'Class 2' },
{ id: 'data/class3.json', name: 'Class 3' },
{ id: 'data/class4.json', name: 'Class 4' },
],
quizId: 'data/class1.json'
};
pager = {
index: 0,
size: 1,
count: 1
}
componentDidMount() {
console.log('componentDidMount');
this.load(this.state.quizId);
}
load(quizId, isValReload) {
console.log('In load');
let url = quizId || this.props.quizId;
if (isValReload) {
let quiz = this.props.quizAll.find(a => url.indexOf(`${a.id}.`) !== -1);
console.log('In load quiz : ', quiz);
this.pager.count = quiz.questions.length / this.pager.size;
this.props.onQuizLoad(quiz);
this.props.onPagerUpdate(this.pager);
}
else {
fetch(`../${url}`).then(res => res.json()).then(res => {
let quiz = res;
quiz.questions.forEach(q => {
q.options.forEach(o => o.selected = false);
});
quiz.config = Object.assign(this.props.quiz.config || {}, quiz.config);
this.pager.count = quiz.questions.length / this.pager.size;
this.props.onQuizLoad(quiz);
this.props.onPagerUpdate(this.pager);
});
}
}
//This event implements restriction to change class without finishing curretnly selectd class
onClassClick = (e) => {
let qus = this.props.quiz.questions;
// console.log(qus);
let isNotAllAns = qus.some((q, i) => {
var isNot = false;
if (q.answerType.id !== 3 && q.answerType.id !== 4) {
isNot = (q.options.find((o) => o.selected === true)) === undefined;
}
else {
// console.log('q', q);
isNot = ((q.answers === "" || q.answers.length === 0));
}
return isNot;
});
if (isNotAllAns) {
alert('Please complete the quiz.');
e.stopPropagation();
}
}
/*
saveQuizAll(_quizAll, _quiz) {
let allQuiz = [];
// , _quizAll, _quiz;
// if (true) {
// _quiz = this.quiz;
// _quizAll = this.quizAll;
// }
console.log(this, _quiz, _quizAll);
if (_quiz.questions.length !== 0) {
if (_quizAll.length !== undefined) {
console.log('Not Initial Setup Splice', _quiz.id);
allQuiz = _quizAll;
const qIndex = this.getQuizIndex(_quiz.id.toString());
if (qIndex > -1) {
allQuiz.splice(qIndex, 1, _quiz);
}
else {
allQuiz.splice(_quizAll.length, 0, _quiz);
// allQuiz.splice(this.props.quizAll.length-1, 0, this.props.quizAll, this.props.quiz);
}
}
else {
allQuiz[0] = _quiz;
}
return allQuiz;
// if (true) {
// this.onQuizChange(allQuiz);
// }
}
}
*/
onChange = (e) => {
// console.log(this.props.quizAll, this.props.quizAll.length);
let allQuiz = [];
allQuiz = saveQuizAll(this.props.quizAll, this.props.quiz);
//below code converted into saveQuizAll funstion
/*
if (this.props.quizAll.length !== undefined) {
console.log('Not Initial Setup Splice', this.props.quiz.id);
allQuiz = this.props.quizAll;
const qIndex = this.getQuizIndex(this.props.quiz.id.toString());
if (qIndex > -1) {
allQuiz.splice(qIndex, 1, this.props.quiz);
}
else {
allQuiz.splice(this.props.quizAll.length, 0, this.props.quiz);
// allQuiz.splice(this.props.quizAll.length-1, 0, this.props.quizAll, this.props.quiz);
}
}
else {
allQuiz[0] = this.props.quiz;
}
*/
// console.log('allQuiz Out - ', allQuiz);
this.props.onQuizChange(allQuiz);
console.log('Check QuizAll - ', this.props.quizAll);
const aQuiz = JSON.parse(JSON.stringify(this.props.quizAll));
this.setState({ quizId: e.target.value });
if (aQuiz.length !== undefined && getQuizIndex(this.props.quizAll, e.target.value) > -1) {
// console.log(aQuiz.findIndex(a => e.target.value.indexOf(`${a.id}.`) !== -1));
this.load(e.target.value, true);
}
else {
this.setState({ quizId: e.target.value });
this.load(e.target.value, false);
}
}
// getQuizIndex(qID) {
// return this.props.quizAll.findIndex(a => (qID.indexOf(`${a.id}.`) !== -1 || qID.indexOf(`${a.id}`) !== -1));
// }
render() {
return (
<div className="container">
<header className="p-2">
<div className="row">
<div className="col-6">
<h3>DADt Application</h3>
</div>
<div className="col-6 text-right">
<label className="mr-1">Select Quiz:</label>
<select onChange={this.onChange} onClick={this.onClassClick}>
{this.state.quizes.map(q => <option key={q.id} value={q.id}>{q.name}</option>)}
</select>
</div>
</div>
</header>
<Timer duration={900}/>
<Quiz quiz={this.state.quiz} quizId={this.state.quizId} saveAll={saveQuizAll} mode={this.state.mode} />
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(QuizContainer);
Here is my Timer Component
import React, { Component } from 'react'
class Timer extends Component {
constructor(props) {
super(props);
this.state = {
seconds: 0
};
}
tick() {
this.setState((prevState) => ({
seconds: prevState.seconds + 1
}));
}
componentDidMount() {
this.interval = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
const { duration } = this.props;
let timeLeft = duration - this.state.seconds;
timeLeft = Number(timeLeft);
let minutes = Math.floor(timeLeft % 3600 / 60);
let seconds = Math.floor(timeLeft % 3600 % 60);
let minutesDisplay = minutes > 0 ? minutes + (minutes === 1 ? " : " : " : ") : "";
let secondsDisplay = seconds > 0 ? seconds + (seconds === 1 ? "" : "") : "";
return <p className="badge badge-success">Time Left: {minutesDisplay}{secondsDisplay}</p>;
}
}
export default Timer;
Quiz Component:
import React, { Component } from 'react';
import { ActionTypes } from '../redux/constants/actionTypes';
import Review from './Review';
import Questions from './Questions';
import Result from './Result';
import { connect } from 'react-redux';
// import { saveQuizAll } from '../commonjs/common.js';
const mapStateToProps = state => { return { ...state.quiz, ...state.mode, ...state.pager, ...state.quizAll } };
const mapDispatchToProps = dispatch => ({
onSubmit: payload => dispatch({ type: ActionTypes.QuizSubmit, payload }),
onQuizChange: payload => dispatch({ type: ActionTypes.QuizAnswerAll, payload }),
onPagerUpdate: payload => dispatch({ type: ActionTypes.PagerUpdate, payload })
});
class Quiz extends Component {
move = (e) => {
let id = e.target.id;
let index = 0;
if (id === 'first')
index = 0;
else if (id === 'prev')
index = this.props.pager.index - 1;
else if (id === 'next') {
index = this.props.pager.index + 1;
}
else if (id === 'last')
index = this.props.pager.count - 1;
else
index = parseInt(e.target.id, 10);
if (index >= 0 && index < this.props.pager.count) {
let pager = {
index: index,
size: 1,
count: this.props.pager.count
};
this.props.onPagerUpdate(pager);
}
}
saveStore(e) {
let allQuiz = [];
console.log(this, e);
allQuiz = this.props.saveAll(e.props.quizAll, e.props.quiz);
console.log(allQuiz);
this.props.onQuizChange(allQuiz);
}
setMode = (e) => this.props.onSubmit(e.target.id);
// setMode(e) {
// console.log('in mode',e);this.props.onSubmit(e.target.id);
// }
renderMode() {
console.log('Inside here', this.props.mode);
if (this.props.mode === 'quiz') {
return (<Questions move={this.move} />)
} else if (this.props.mode === 'review') {
return (<Review quiz={this.props.quiz} move={this.move} />)
} else {
console.log('Before Results');
const divSel = document.querySelector('div.col-6.text-right');
// console.log('divSel', divSel);
if (divSel) {
divSel.style.display = "none";
}
return (<Result questions={this.props.quizAll || []} />)
}
}
render() {
return (
<div>
{this.renderMode()}
{(this.props.mode !== 'submit') &&
<div>
<hr />
<button id="quiz" className="btn btn-primary" onClick={this.setMode}>Quiz</button>
<button id="review" className="btn btn-primary" onClick={this.setMode}>Review</button>
<button id="submit" className="btn btn-primary" onClick={(e) => {this.setMode(e); this.saveStore(this)}}>Submit Quiz</button >
</div >}
</div>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Quiz);
I think you can have two approaches.
1. The "react" way
In the Parent component:
// ...
constructor(props) {
// ...
this.state = {
timeExpired: false
};
}
const onTimeExpired = () => {
this.setState({timeExpired: true});
}
// ...
render() {
return (
<div className="container">
{ // ... }
<Timer duration={900} onTimeExpired={onTimeExpired}/>
<Quiz quiz={this.state.quiz} quizId={this.state.quizId} saveAll={saveQuizAll} mode={this.state.mode} triggerSubmit={this.state.timeExpired} />
</div>
);
}
In the Timer component:
// ...
componentDidUpdate() {
if (this.state.seconds === this.props.duration) {
this.props.onTimeExpired();
}
}
// ...
In the Quiz component:
// ...
componentDidUpdate() {
if (this.props.triggerSubmit) {
// Do whatever you do on submit
}
}
// ...
2. The "quick and dirty" way:
In the Timer component
// ...
componentDidUpdate() {
if (this.state.seconds === this.props.duration) {
const quizForm = document.getElementById('quizFormId');
quizForm && quizForm.submit();
}
}
// ...
Provide a prop method onTimeFinished in your Timer component. Then in your render function you can add
{ !(this.props.duration-this.state.seconds) && this.props.onTimeFinished() }
Reference: React Conditional Rendering
try this:
Parent Component:
// state
state = {
triggerSubmit: false
}
// functions
doSubmit = () => {
this.setState({ triggerSubmit: true });
}
resetSubmit = () => {
this.setState({ triggerSubmit: false });
}
// jsx
<Timer duration={900} doSubmit={this.doSubmit} />
<Quiz
quiz={this.state.quiz}
quizId={this.state.quizId}
saveAll={saveQuizAll}
mode={this.state.mode}
resetSubmit={this.resetSubmit}
triggerSubmit={this.state.triggerSubmit} />
Timer Component:
// function
doSubmit = (timeLeft) => {
if (timeLeft === 0) {
this.props.doSubmit();
}
}
// jsx
<p className="badge badge-success"
onChange={() => {this.doSubmit(timeLeft)}>
Time Left: {minutesDisplay}{secondsDisplay}
</p>
Quiz Component:
// state
state = {
triggerSubmit: this.props.triggerSubmit
}
// function
triggerSubmit = () => {
if (this.state.triggerSubmit) {
your trigger submit code here...
this.props.resetSubmit();
}
}
I am new to react, I am trying to write a react component, component has several features.
user can input a random number, then number will be displayed in the
page too.
implement a button with text value 'start', once click the button,
the number value displayed will reduce one every 1second and the
text value will become 'stop'.
continue click button, minus one will stop and text value of button
will become back to 'start'.
when number subtracted down to 0 will automatically stop itself.
I have implemented first three features. but I am not sure how do I start the last one. should I set another clearInteval? based on if statement when timer counts down 0?
code is here:
var myTimer;
class App extends Component {
constructor(props) {
super(props);
this.state = {
details: [{ id: 1, number: "" }],
type: false
};
this.handleClick = this.handleClick.bind(this);
}
changeNumber = (e, target) => {
this.setState({
details: this.state.details.map(detail => {
if (detail.id === target.id) {
detail.number = e.target.value;
}
return detail;
})
});
};
handleClick = () => {
this.setState(prevState => ({
type: !prevState.type
}));
if (this.state.type === false) {
myTimer = setInterval(
() =>
this.setState({
details: this.state.details.map(detail => {
if (detail.id) {
detail.number = parseInt(detail.number) - 1;
}
return detail;
})
}),
1000
);
}
if (this.state.type === true) {
clearInterval(myTimer);
}
};
render() {
return (
<div>
{this.state.details.map(detail => {
return (
<div key={detail.id}>
Number:{detail.number}
<input
type="number"
onChange={e => this.changeNumber(e, detail)}
value={detail.number}
/>
<input
type="button"
onClick={() => this.handleClick()}
value={this.state.type ? "stop" : "start"}
/>
</div>
);
})}
</div>
);
}
}
export default App;
just add
if (detail.number === 0) {
clearInterval(myTimer);
}
in
handleClick = () => {
this.setState(prevState => ({
type: !prevState.type
}));
if (this.state.type === false) {
myTimer = setInterval(
() =>
this.setState({
details: this.state.details.map(detail => {
if (detail.id) {
detail.number = parseInt(detail.number) - 1;
if (detail.number === 0) {
clearInterval(myTimer);
}
}
return detail;
})
}),
1000
);
}
if (this.state.type === true) {
clearInterval(myTimer);
}
};
Here You have this solution on Hooks :)
const Test2 = () => {
const [on, setOn] = useState(false)
const initialDetails = [{ id: 1, number: "" }]
const [details, setDetails] = useState(initialDetails)
const changeNumber = (e, target) => {
setDetails({ details: details.map(detail => { if (detail.id === target.id) { detail.number = e.target.value; } return detail; }) });
if (this.state.details.number === 0) { setOn(false) }
};
const handleClick = () => {
if (on === false) {myTimer = setInterval(() =>
setDetails({details: details.map(detail => {if (detail.id) {detail.number = parseInt(detail.number) - 1; if (detail.number === 0) {clearInterval(myTimer);} }
return detail;})}),1000);}
if (on === true) { clearInterval(myTimer); }
};
return (
<div>
{details.map(detail => {
return (
<div key={detail.id}>
Number:{detail.number}
<input
type="number"
onChange={e => changeNumber(e, detail)}
value={detail.number}
/>
<input
type="button"
onClick={() => handleClick()}
value={on ? "stop" : "start"}
/>
</div>
);
})}
</div>
)
}
I have 3 Textfields, what I want to do is just to accept number so if someone put text and click continue the application should display an error saying that just numbers are allowed.
The following code displays an error message if the Textfield is empty and thats ok but the other validation to check if the user inputs text or numbers is pending and I'm stucked.
import React from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import TextField from 'material-ui/TextField';
import Divider from 'material-ui/Divider';
import cr from '../styles/general.css';
export default class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
buy_: '',
and_: '',
save_: '',
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event, index, value) {
this.setState({value});
}
clear() {
console.info('Click on clear');
this.setState({
buy_: '',
and_: '',
save_: ''
});
}
validate() {
let isError = false;
const errors = {
descriptionError: ''
};
if (this.state.buy_.length < 1 || this.state.buy_ === null) {
isError = true;
errors.buy_error = 'Field requiered';
}
if (this.state.and_.length < 1 || this.state.and_ === null) {
isError = true;
errors.and_error = 'Field requiered';
}
if (this.state.save_.length < 1 || this.state.save_ === null) {
isError = true;
errors.save_error = 'Field requiered';
}
this.setState({
...this.state,
...errors
});
return isError;
}
onSubmit(e){
e.preventDefault();
// this.props.onSubmit(this.state);
console.log('click onSubmit')
const err = this.validate();
if (!err) {
// clear form
this.setState({
buy_error: '',
and_error: '',
save_error: ''
});
this.props.onChange({
buy_: '',
and_: '',
save_: ''
});
}
}
render() {
return (
<div className={cr.container}>
<div className ={cr.boton}>
<Divider/>
<br/>
</div>
<div className={cr.rows}>
<div>
<TextField
onChange={(e) => {this.setState({buy_: e.target.value})}}
value={this.state.buy_}
errorText={this.state.buy_error}
floatingLabelText="Buy"
/>
</div>
<div>
<TextField
onChange={(e) => {this.setState({and_: e.target.value})}}
value={this.state.and_}
errorText={this.state.and_error}
floatingLabelText="And"
/>
</div>
<div>
<TextField
onChange={(e) => {this.setState({save_: e.target.value})}}
value={this.state.save_}
errorText={this.state.save_error}
floatingLabelText="Save"
/>
</div>
</div>
<div className={cr.botonSet}>
<div className={cr.botonMargin}>
<RaisedButton
label="Continue"
onClick={e => this.onSubmit(e)}/>
</div>
<div>
<RaisedButton
label="Clear"
secondary ={true}
onClick={this.clear = this.clear.bind(this)}
/>
</div>
</div>
</div>
);
}
}
Can someone help me on this please.
Thanks in advance.
You can prevent users from input text by using this :
<TextField
onChange={(e) => {
if(e.target.value === '' || /^\d+$/.test(e.target.value)) {
this.setState({and_: e.target.value})
} else {
return false;
}
}}
value={this.state.and_}
errorText={this.state.and_error}
floatingLabelText="And"
/>
The TextField component can restrict users to entering text using the JavaScript test method:
<TextField
onChange={(e) => {
if(e.target.value == '' || (/\D/.test(e.target.value))) {
this.setState({and_: e.target.value})}
}
else {
return false;
}
}
value={this.state.and_}
errorText={this.state.and_error}
floatingLabelText="And"
/>
Try adding this code in your validate function.
You can use regex to validate your fields for text or numbers like :
import * as RegExp from './RegExpression';
validate() {
let isError = false;
const errors = {
descriptionError: ''
};
if (this.state.buy_ && !RegExp.NAME.test(this.state.buy_)) {
// validation check if input is name
isError = true;
errors.buy_error = 'Invalid name';
}
if (this.state.and_ && !RegExp.NUMBER.test(this.state.and_)) {
// validation check if input is number
isError = true;
errors.and_error = 'Invalid Number';
}
this.setState({
...this.state,
...errors
});
return isError;
}
In RegexExpression file add these validations like this :
export const NAME = /^[a-z ,.'-()"-]+$/i;
export const NUMBER = /^[0-9]*$/ ;
You are not initialising error object in state but accessed in TextField as this.state.and_error. Either you should initialise error in constructor like this.state = { and_error: "" } or initialise error object as
this.state = {
error: {
and_error: "",
buy_error: "",
save_error: ""
}
}
So in your TextField
<TextField
onChange={(e) => {
if(e.target.value === "" || (/\D/.test(e.target.value))) {
this.setState({and_: e.target.value})}
}
else {
return false;
}
}
value={this.state.and_}
errorText={this.state.error.and_error} // If initialised error string access as this.state.and_error
floatingLabelText="And"
/>
Your validate function will be like
validate() {
let isError = false;
const errors = this.state.errors;
if (this.state.buy_.toString().length < 1 || this.state.buy_ === null) {
isError = true;
errors.buy_error = 'Field requiered';
}
if (this.state.and_.toString().length < 1 || this.state.and_ === null) {
isError = true;
errors.and_error = 'Field requiered';
}
if (this.state.save_.toString().length < 1 || this.state.save_ === null) {
isError = true;
errors.save_error = 'Field requiered';
}
this.setState({errors});
return isError;
}
Hope this will heps you!
You can use react-validation for all validation and set rules for validation
Try to check the checkbox, you will see undefined. That's strange I think I used find properly. Or there's a better way to do it?
http://jsbin.com/ficijuwexa/1/edit?js,console,output
class HelloWorldComponent extends React.Component {
constructor(){
super()
this.handleChange = this.handleChange.bind(this);
this.state = {
"fruits":[
{"name":"banana","value":true},
{"name":"watermelon","value":false},
{"name":"lemon","value":true},
]
}
}
handleChange(e,key){
const newFruitsData = this.state.fruits.find(obj => {
obj.name === key ? obj.value = e.target.checked : ''
});
console.log(newFruitsData) // <-- why does this output undefined?
}
render() {
return (
<div>
{this.state.fruits.map(obj =>
<div key={obj.name}>
<label>{obj.name}</label>
<input onChange={(e) => this.handleChange(e, obj.name)} type="checkbox" defaultChecked={obj.value} />
</div>
)}
<br />
<pre>{JSON.stringify(this.state.fruits,null,2)}</pre>
</div>
);
}
}
Your find has no return statement, it always return undefined while it should return boolean
const newFruitsData = this.state.fruits.find(obj => obj.name === key && obj.value === e.target.checked);
In the handleChange(), the Array.prototype.find should return Bool:
handleChange(e,key){
let nxState = Object.assign({}, this.state)
nxState.fruits.find(obj => {
if (obj.name === key) {
obj.value = e.target.checked
return true
} else {
return false
}
});
this.setState(nxState)
}
And you should use setState() instead, it's my opinion of course
--- Update
Check it