I want to add validation in my react form I am using SimpleReactValidator library for validation, but once I setup the code, the error is not displaying. But when i add
{validator.showMessages('fullName', fullName, 'required|alpha')}
before the return statement it's showing me without click on submit button.
Here's my code
import React, { useState } from 'react';
import SimpleReactValidator from 'simple-react-validator';
const UserDetails = ({ setForm, formData, navigation }) => {
const {
fullName
}= formData;
const useForceUpdate = () => useState()[1];
const validator = new SimpleReactValidator();
const forceUpdate = useForceUpdate();
const submitForm = (e) =>{
e.preventDefault()
if (validator.allValid()) {
alert('You submitted the form and stuff!');
} else {
validator.showMessages();
forceUpdate();
}
}
return(
<>
<input
type="text"
name="fullName"
placeholder='Name'
onChange={setForm}
defaultValue={fullName}
/>
{validator.message('fullName', fullName, 'required|alpha')}
</>
);
}
export default UserDetails;
Hope this will help you
import React, { useState } from 'react';
import SimpleReactValidator from 'simple-react-validator';
const UserDetails = () => {
const validator = new SimpleReactValidator();
const [state, setState] = useState({
fullName:""
})
const handleChnage = (e) => {
setState({
fullName:e.target.value
})
}
const submitForm = () => {
if (validator.allValid()) {
alert('You submitted the form and stuff!');
} else {
validator.showMessages();
}
}
return (
<>
<input
type="text"
name="fullName"
placeholder='Name'
onChange={(e) => handleChnage(e)}
defaultValue={state.fullName}
/>
{validator.message('fullName', state.fullName, 'required|alpha')}
<button onClick={() => submitForm()}>submit</button>
</>
);
}
export default UserDetails;
This code example would solve your problem.
class App extends React.Component {
constructor(props){
super(props)
this.validator = new SimpleReactValidator({autoForceUpdate: this});
this.state = {
fullName: ''
};
}
handleFullNameChange(e) {
this.setState({fullName: e.target.value});
}
handleFullNameBlur() {
if(this.validator.allValid()) {
this.validator.hideMessages();
} else {
this.validator.showMessages();
}
}
render(){
return (
<div>
<input type="text" name="fullName" placeholder='Name' onChange={this.handleFullNameChange.bind(this)} onBlur={this.handleFullNameBlur.bind(this)} value={this.state.fullName} />
{this.validator.message('fullName', this.state.fullName, 'required|alpha')}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'))
You can also take a look on Codepen here: https://codepen.io/aptarmy/pen/oNXRezg
Related
I have a container component that works with Redux, in it I determined the state of the text field and throw it into the form component that works with Formik
But I have such a problem that after clicking the button, the text field is not cleared
How do I fix this ? I've seen a lot about resetForm() from Formik, but I can't work with it
TaskInput.jsx
export const TaskInput = ({ value, onChange, onAdd }) => {
const formik = useFormik({
initialValues: {
text: value,
},
})
return (
<Container>
<Formik>
<FormWrapper onSubmit={onAdd}>
<Input
id="task"
type="text"
placeholder="Add a task"
value={formik.text}
onChange={onChange}
/>
<AddButton type="submit">Add</AddButton>
</FormWrapper>
</Formik>
</Container>
)
}
Task.jsx(component container)
class Task extends PureComponent {
constructor(props) {
super(props)
this.state = {
taskText: '',
}
}
handleInputChange = e => {
this.setState({
taskText: e.target.value,
})
}
handleAddTask = () => {
const { taskText } = this.state
const { addTask } = this.props
addTask(uuidv4(), taskText, false)
this.setState({
taskText: '',
})
}
render() {
const { taskText } = this.state
return (
<>
<TaskInput
onAdd={this.handleAddTask}
onChange={this.handleInputChange}
value={taskText}
/>
...
</>
)
}
}
const mapStateToProps = ({ tasks }) => {
return {
tasks,
}
}
export default connect(mapStateToProps, {
addTask,
removeTask,
completeTask,
editTask,
})(Task)
Solution
export const TaskInput = ({ value, onChange, onAdd }) => {
const inputRef = useRef(null)
const formik = useFormik({
initialValues: {
text: value,
},
})
const onSubmit = () => {
onAdd(),
inputRef.current.value = ''
}
return (
<Container>
<Formik>
<FormWrapper onSubmit={onSubmit}>
<Input
ref={inputRef}
id="task"
type="text"
placeholder="Add a task"
value={formik.text}
onChange={onChange}
/>
<AddButton type="submit">Add</AddButton>
</FormWrapper>
</Formik>
</Container>
)
}
I want to make text editor and save the written data to a server (Mongodb) with its styling, then show the saved written data in the styled way, I did the coding for the editor but the problem now is how to send the data to the server. POST
Here is the code for TextEditor.js
import React, { Component } from "react";
import { Editor } from "react-draft-wysiwyg";
import { EditorState, convertToRaw } from "draft-js";
import "react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
import draftToHtml from "draftjs-to-html";
export default class TextEditor extends Component {
state = {
editorState: EditorState.createEmpty(),
};
onEditorStateChange = (editorState) => {
this.setState({
editorState,
});
};
render() {
const { editorState } = this.state;
console.log(draftToHtml(convertToRaw(editorState.getCurrentContent())));
return (
<div>
<Editor
editorState={editorState}
toolbarClassName="toolbarClassName"
wrapperClassName="wrapperClassName"
editorClassName="editorClassName"
onEditorStateChange={this.onEditorStateChange}
/>
<textarea
disabled
value={draftToHtml(convertToRaw(editorState.getCurrentContent()))}
></textarea>
</div>
);
}
}
Write Page Write.jsx
import axios from 'axios';
import TextEditor from '../../components/TextEditor/TextEditor';
export default function Write() {
const [desc, setDesc] = useState('');
const { user } = useContext(Context);
const handleSubmit = async (e) => {
e.preventDefault();
const newPost = {
username: user.username,
desc,
};
try {
const res = await axios.post('/posts', newPost);
window.location.replace('/post/' + res.data._id);
} catch (err) {}
};
return (
<div className='write'>
<form className='writeForm' onSubmit={handleSubmit}>
<TextEditor
placeholder='Write your story'
type='text'
className='writeInput writeText'
onChange={(e) => setDesc(e.target.value)}
/>
<button className='writeSubmit' type='submit'>
نشر
</button>
</form>
</div>
);
}
Post.js
const mongoose = require('mongoose');
const PostSchema = new mongoose.Schema({
desc: {
type: String,
required: true,
},
});
module.exports = mongoose.model('Post', PostSchema);
I know that I have to use JSON.stringify(convertToRaw()) and convertFromRaw() but I didn't know where to use them, it's been now week and I'm still trying to solve this problem.
It should be like something this.
import { EditorState } from "draft-js";
const data = convertFromRaw(response);
const state = EditorState.createWithContent(data);
<Editor editorState={state} readOnly={true} />
The code below is using antd v3,for the antd v4 the form.create() is already not available, I read the documentation,it shows to replace the form.create() by useform.I tried to put it in the code(the second code) but still not working. Hhow can I use useForm in the code?
import React from 'react'
import {Form, Input} from 'antd'
const EditableContext = React.createContext();
const EditableRow = ({ form, index, ...props }) => (
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
);
export const EditableFormRow = Form.create()(EditableRow);
export class EditableCell extends React.Component {
state = {
editing: false,
};
toggleEdit = () => {
const editing = !this.state.editing;
this.setState({ editing }, () => {
if (editing) {
this.input.focus();
}
});
};
save = e => {
const { record, handleSave } = this.props;
this.form.validateFields((error, values) => {
if (error && error[e.currentTarget.id]) {
return;
}
this.toggleEdit();
handleSave({ ...record, ...values });
});
};
}
The useForm code
export const EditableFormRow = () => {
const { form, index, ...props } = useForm();
return (
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
)
};
useForm() return array, you can get form like this:
import React from "react";
import ReactDOM from "react-dom";
import { Form, Input, Button } from "antd";
const App = () => {
return <>{["a#x.com", "b#x.com"].map((email) => EditRow({ email }))}</>;
};
const layout = {
labelCol: { span: 8 },
wrapperCol: { span: 16 }
};
const tailLayout = {
wrapperCol: { offset: 8, span: 16 }
};
const EditRow = ({ email }) => {
const [form] = Form.useForm();
const onFinish = (values) => {
console.log(values);
};
const onClick = () => {
console.log(form.getFieldValue("email"));
};
return (
<Form form={form} layout={layout} onFinish={onFinish}>
<Form.Item
name="email"
label="email"
rules={[{ required: true }]}
initialValue={email}
>
<Input />
</Form.Item>
<Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit">
Submit
</Button>
<Button onClick={onClick}>getFieldValue</Button>
</Form.Item>
</Form>
);
};
How can I make the text area empty after I click the submit button??
Im trying to create a simple form submit in react. Can you please tell me how can i make the text area empty after I click the Submit button. This is my problem.
This is my App.js code:
import React, { Component } from 'react'
import Textarea from "./Textarea";
import Button from "./Button";
export class App extends Component {
constructor(){
super();
this.state = {
Tinput: '',
// Ninput:'',
submit: ''
}
}
changeHandle = (event) => {
this.setState({
Tinput: event.target.value
})
}
submitHandle = (event) => {
event.preventDefault();
this.setState({
submit: this.state.Tinput
})
}
resetHandle = (event) => {
event.preventDefault();
this.setState(
{submit: ''}
)
}
// handleKeypress = (event) => {
// if (event.keyCode === 'Enter') {
// this.submitHandle();
// }
// }
render() {
return (
<div>
<div>
<Textarea changeHandle={this.changeHandle} change={this.state.Tinput}/>
<Button action={this.submitHandle} name="submit"/>
<Button action={this.resetHandle} name="Reset" />
</div>
<p>{this.state.submit}</p>
</div>
)
}
}
export default App
This is my Textarea.js code:
import React from 'react'
const Textarea = (props) => {
return (
<div>
<textarea
type="text"
onChange={props.changeHandle}
// onKeyPress={this.handleKeypress}
value={props.change}
className="form-control"
id="exampleFormControlTextarea1" rows="3"
placeholder='write something here'
/>
</div>
);
}
export default Textarea;
This is my button.js code:
import React from 'react'
const Button = (props) => {
return (
<div>
<button type="submit" className="btn btn-primary" onClick={props.action}>{props.name}</button>
</div>
);
}
export default Button;
You can set it as empty in submit function
submitHandle = (event) => {
event.preventDefault();
this.setState({
submit: this.state.Tinput,
Tinput:""
})
}
Try this :
submitHandle = (event) => {
event.preventDefault();
this.setState({
submit: this.state.Tinput,
Tinput: '',
})
}
I crafted a reactjs crud app with help of a tutorial and it works great now. Now i am trying to merge two form together so that same form should be used for both add and update operation.
This is my allpost.js file
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Post from '../components/Post';
import EditComponent from '../components/editComponent';
class AllPost extends Component {
render() {
return (
<div>
<h1>All Posts</h1>
{this.props.posts.map((post) => (
<div key={post.id}>
{post.editing ? <EditComponent post={post} key={post.id} /> :
<Post key={post.id} post={post} />}
</div>
))}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
posts: state
}
}
export default connect(mapStateToProps)(AllPost);
and this is my postForm.js file:
import React, { Component } from 'react';
import { connect } from 'react-redux'
class PostForm extends Component {
handleSubmit = (e) => {
e.preventDefault();
const title = this.getTitle.value;
const message = this.getMessage.value;
const data = {
id: new Date(),
title,
message,
editing: false
}
console.log(data)
this.props.dispatch({
type: 'ADD_POST',
data,
});
this.getTitle.value = '';
this.getMessage.value = '';
}
render() {
return (
<div>
<h1>Create Post</h1>
<form onSubmit={this.handleSubmit}>
<input required type="text" ref={(input)=>this.getTitle = input}
placeholder="Enter Post Title"/>
<br /><br />
<textarea required rows="5" ref={(input)=>this.getMessage = input} cols="28"
placeholder="Enter Post" />
<br /><br />
<button>Post</button>
</form>
</div>
);
}
}
export default connect()(PostForm);
and this is my editComponent.js file
import React, { Component } from 'react';
import { connect } from 'react-redux';
class EditComponent extends Component {
handleEdit = (e) => {
e.preventDefault();
const newTitle = this.getTitle.value;
const newMessage = this.getMessage.value;
const data = {
newTitle,
newMessage
}
this.props.dispatch({ type: 'UPDATE', id: this.props.post.id, data: data })
}
render() {
return (
<div>
<form onSubmit={this.handleEdit}>
<input required type="text" ref={(input) => this.getTitle = input}
defaultValue={this.props.post.title} placeholder="Enter Post Title" /><br /><br />
<textarea required rows="5" ref={(input) => this.getMessage = input}
defaultValue={this.props.post.message} cols="28" placeholder="Enter Post" /><br /><br />
<button>Update</button>
</form>
</div>
);
}
}
export default connect()(EditComponent);
and this is my post.js file:
import React, { Component } from 'react';
import { connect } from 'react-redux'
class Post extends Component {
render() {
return (
<div>
<h2>{this.props.post.title}</h2>
<p>{this.props.post.message}</p>
<button onClick={() => this.props.dispatch({type: 'EDIT_POST', id: this.props.post.id})}>EDIT
</button>
<button onClick={ () => this.props.dispatch({type: 'DELETE_POST', id: this.props.post.id}) }>DELETE
</button>
</div>
);
}
}
export default connect()(Post);
and this is my postReducer.js file:
const postReducer = (state = [], action) => {
switch(action.type) {
case 'ADD_POST':
return state.concat([action.data]);
case 'DELETE_POST':
return state.filter((post)=>post.id !== action.id);
case 'EDIT_POST':
return state.map((post)=>post.id === action.id ? {...post,editing:!post.editing}:post)
case 'UPDATE':
return state.map((post)=>{
if(post.id === action.id) {
return {
...post,
title:action.data.newTitle,
message:action.data.newMessage,
editing: !post.editing
}
} else return post;
})
default:
return state;
}
}
export default postReducer;
Can anyone please help me to achieve this? I tried a lot to use same form form for both add and update and i failed to achieve this.
I think it's better you create separate component for rendering form data(FormComponent) and separate components for edit(EditComponent) and add(AddComponent).
This way there will not be clutter in one component and no if/else conditions for different modes like edit or add, or in future copy mode.
This approach will add flexibility and enhances compositional pattern of react.
1) AddComponent
import React, { Component } from 'react';
import { connect } from 'react-redux'
class AddComponent extends Component {
handleSubmit = (title, message) => {
const data = {
id: new Date(),
title,
message,
editing: false
}
this.props.dispatch({
type: 'ADD_POST',
data,
});
}
render() {
return (
<div>
<h1>Create Post</h1>
<FormComponent
buttonLabel='Post'
handleSubmit={this.handleSubmit}
/>
</div>
);
}
}
export default connect()(AddComponent);
2) EditComponent
import React, { Component } from 'react';
import { connect } from 'react-redux';
class EditComponent extends Component {
handleSubmit = (newTitle, newMessage) => {
const data = {
newTitle,
newMessage
}
this.props.dispatch({ type: 'UPDATE', id: this.props.post.id, data: data })
}
render() {
return (
<div>
<FormComponent
buttonLabel='Update'
handleSubmit={this.handleSubmit}
/>
</div>
);
}
}
export default connect()(EditComponent);
3) FormComponent
import React, { Component } from 'react';
class FormComponent extends Component {
handleSubmit = (e) => {
e.preventDefault();
const title = this.getTitle.value;
const message = this.getMessage.value;
this.props.handleSubmit(title, message);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input required type="text" ref={(input) => this.getTitle = input}
defaultValue={this.props.post.title} placeholder="Enter Post Title" /><br /><br />
<textarea required rows="5" ref={(input) => this.getMessage = input}
defaultValue={this.props.post.message} cols="28" placeholder="Enter Post" /><br /><br />
<button>{this.props.buttonLabel}</button>
</form>
);
}
}
export default FormComponent;
Hope that helps!!!
You can create your own Form component with a prop of editMode to control whether it's Create or Update.
import React, {Component} from 'react';
import PropTypes from 'prop-types';
class Form extends Component {
handleSubmit = e => {
e.preventDefault();
const {editMode, post} = this.props;
const title = this.titleRef.value;
const body = this.bodyRef.value;
if (editMode){
const data = {
title,
body
}
this.props.dispatch({type: 'UPDATE', id: post.id, data})
}
else {
const data = {
id: new Date(),
title,
message,
editing: false
}
this.props.dispatch({type: 'ADD_POST', data});
}
}
render() {
const {editMode, post} = this.props;
const pageTitle = editMode ? 'Edit Post' : 'Create Post';
const buttonTitle = editMode ? 'Update' : 'Post';
return (
<div>
<h1>{pageTitle}</h1>
<form onSubmit={this.handleSubmit}>
<input
required
type="text"
ref={input => this.titleRef = input}
placeholder="Enter Post Title"
defaultValue={post.title}
/>
<textarea
required
rows="5"
ref={input => this.bodyRef = input}
cols="28"
placeholder="Enter Post"
defaultValue={post.body}
/>
<button>{buttonTitle}</button>
</form>
</div>
);
}
}
Form.propTypes = {
editMode: PropTypes.bool,
post: PropTypes.object
}
Form.defaultProps = {
editMode: false, // false: Create mode, true: Edit mode
post: {
title: "",
body: ""
} // Pass defined Post object in create mode in order not to get undefined objects in 'defaultValue's of inputs.
}
export default Form;
It would be on create mode by default but if you wanna update the post you should pass editMode={true} to your form component.