Form async-validator not rendering - reactjs

I am trying to make a simple form.
I am able to get all valid data if they are inputted and receive errors on the console, if they are not:
async-validator: ["username is required"]
async-validator: ["passwordis required"]
But the errors are not rendering.
Parent
const HomePage = () => (
<Layout className="layout" style={{ minHeight: '100vh' }}>
<Header>Teste</Header>
<Content className={_s.Content}>
<LoginForm />
</Content>
<Footer style={{ textAlign: 'center' }}>React Node Boilerplate by Igor Cesar</Footer>
</Layout>
);
export default HomePage;
Form
class LoginForm extends React.Component {
handleSubmit = e => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
};
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form onSubmit={this.handleSubmit} className={_s.loginForm}>
<Form.Item>
{getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }]
})(
<Input
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
placeholder="Username"
/>
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }]
})(
<Input
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
type="password"
placeholder="Password"
/>
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: true
})(<Checkbox>Remember me</Checkbox>)}
<a className={_s.loginFormForgot} href="/">
Forgot password
</a>
<Button type="primary" htmlType="submit" className={_s.loginFormButton}>
Log in
</Button>
Or register now!
</Form.Item>
</Form>
);
}
}
const WrapperLoginForm = Form.create()(LoginForm);
export default WrapperLoginForm;

In order to help people who will reach this page in the future:
The author reported the bug to antdesign and a solution was found.
This was a problem with lodash-webpack-plugin, and the required change is in webpack.config.js. Turns out LodashModuleReplacementPlugin() should receive {paths: true} as a parameter, and the problem's gone.
module.exports = {
//... rest of your webpack config
plugins: [
//... rest of your plugins
new LodashModuleReplacementPlugin({paths: true}),
],
}

Related

Was Form.create() from antd replaced?

i am trying to create a login page in react using antd. I found a tutorial for doing this,but i belive that it is outdated, because it gives an error. I read on a forum that form.create() is not available anymore, but i don't know how to replace it.Here is my code:
import { Form, Icon, Input, Button, Spin } from 'antd';
import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom';
import * as actions from '../store/actions/auth';
const FormItem = Form.Item;
const antIcon = <Icon type="loading" style={{ fontSize: 24 }} spin />;
class NormalLoginForm extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
this.props.onAuth(values.userName, values.password);
this.props.history.push('/');
}
});
}
render() {
let errorMessage = null;
if (this.props.error) {
errorMessage = (
<p>{this.props.error.message}</p>
);
}
const { getFieldDecorator } = this.props.form;
return (
<div>
{errorMessage}
{
this.props.loading ?
<Spin indicator={antIcon} />
:
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem>
{getFieldDecorator('userName', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />
)}
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" style={{marginRight: '10px'}}>
Login
</Button>
Or
<NavLink
style={{marginRight: '10px'}}
to='/signup/'> signup
</NavLink>
</FormItem>
</Form>
}
</div>
);
}
}
const WrappedNormalLoginForm = Form.create()(NormalLoginForm);
const mapStateToProps = (state) => {
return {
loading: state.loading,
error: state.error
}
}
const mapDispatchToProps = dispatch => {
return {
onAuth: (username, password) => dispatch(actions.authLogin(username, password))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(WrappedNormalLoginForm);
When i try to run it, i get an error that says:
TypeError: _antd.Form.create(...) is not a function
How can i rewrite the code in order to make it run?
AntD has removed Form.create in v4 and you can replace the above code with the modified API structure like
class NormalLoginForm extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
this.props.onAuth(values.userName, values.password);
this.props.history.push('/');
}
});
}
render() {
let errorMessage = null;
if (this.props.error) {
errorMessage = (
<p>{this.props.error.message}</p>
);
}
const { getFieldDecorator } = this.props.form;
return (
<div>
{errorMessage}
{
this.props.loading ?
<Spin indicator={antIcon} />
:
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem name='userName' rules={[{ required: true, message: 'Please input your username!' }]}>
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
</FormItem>
<FormItem name="password" rules={[{ required: true, message: 'Please input your Password!' }]}>
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" style={{marginRight: '10px'}}>
Login
</Button>
Or
<NavLink
style={{marginRight: '10px'}}
to='/signup/'> signup
</NavLink>
</FormItem>
</Form>
}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
loading: state.loading,
error: state.error
}
}
const mapDispatchToProps = dispatch => {
return {
onAuth: (username, password) => dispatch(actions.authLogin(username, password))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(NormalLoginForm);
Please see the migration guidelines for more details
I think you are using Antd v4.*. Form.create({}) is no more in latest version, so you have to your code as follow to make it working. V4 has. major changes so you have to go through migration guidelines
import { Form, Input, Button, Spin } from 'antd';
import { LoadingOutlined, UserOutlined, LockOutlined } from "#ant-design/icons";
import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom';
import * as actions from '../store/actions/auth';
const FormItem = Form.Item;
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} />;
class NormalLoginForm extends React.Component {
handleFinish = (values) => {
this.props.onAuth(values.userName, values.password);
this.props.history.push('/');
}
render() {
let errorMessage = null;
if (this.props.error) {
errorMessage = (
<p>{this.props.error.message}</p>
);
}
return (
<div>
{errorMessage}
{
this.props.loading ?
<Spin indicator={antIcon} />
:
<Form onFinish={this.handleFinish} className="login-form">
<FormItem name="userName" rules={[{ required: true, message: 'Please input your username!' }]}>
<Input prefix={<UserOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
)}
</FormItem name="password" rules={[{ required: true, message: 'Please input your Password!' }]}>
<FormItem>
<Input prefix={<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />
)}
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" style={{marginRight: '10px'}}>
Login
</Button>
Or
<NavLink
style={{marginRight: '10px'}}
to='/signup/'> signup
</NavLink>
</FormItem>
</Form>
}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
loading: state.loading,
error: state.error
}
}
const mapDispatchToProps = dispatch => {
return {
onAuth: (username, password) => dispatch(actions.authLogin(username, password))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(NormalLoginForm);

React js - Save previous value in Ant Design Steps

I am using Ant Design Steps for my form but I am having a problem on how to save the value of the previous input.
Here is my code whole code:
import React from 'react';
import 'antd/dist/antd.css';
import './index.css';
import { Form, Icon, Input, Button, Steps } from 'antd';
const { Step } = Steps;
const steps = [
{
title: 'First',
content: 'First-content',
},
{
title: 'Second',
content: 'Second-content',
}
];
class NormalLoginForm extends React.Component {
constructor (props) {
super (props) ;
this.state = {
current: 0
}
}
next() {
const current = this.state.current + 1;
this.setState({ current });
}
prev() {
const current = this.state.current - 1;
this.setState({ current });
}
handleSubmit = e => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
};
render() {
const { current } = this.state
const { getFieldDecorator } = this.props.form;
return (
<div>
<Steps current={current}>
{steps.map(item => (
<Step key={item.title} title={item.title} />
))}
</Steps>
<Form onSubmit={this.handleSubmit} className="login-form">
{current === 0 ? (
<Form.Item>
{getFieldDecorator('username', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
placeholder="Username"
/>,
)}
</Form.Item>
): ''}
{current === 1 ? (
<Form.Item>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
type="password"
placeholder="Password"
/>,
)}
</Form.Item>
): ''}
</Form>
{current < steps.length - 1 && (
<Button type="primary" onClick={() => this.next()}>
Next
</Button>
)}
{current === steps.length - 1 && (
<Button type="primary" onClick={this.handleSubmit}>
Done
</Button>
)}
{current > 0 && (
<Button style={{ marginLeft: 8 }} onClick={() => this.prev()}>
Previous
</Button>
)}
</div>
);
}
}
What is happening is when I click next, the value of the previous input is gone. What I want to happen is when I click next the previous value will be save so when I click submit both of the values will be output in the console. The code comes from ant design and I used it for example
You should consider storing the data in a state :
constructor (props) {
super (props) ;
this.state = {
current: 0,
firstInput: '',
secondInput: '',
}
}
<Input
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
placeholder="Username"
onChange={(e) => this.setState({firstInput: e.target.value})}
/>,
Then, in your submit press, you will be able to access the values of firstInput and secondInput by doing this.state.firstInput & this.state.secondInput.

Getting warning when i use withCookies()

I am using react-cookie in my project. When i use withCookies() i am getting warning in console log like this
Warning: Failed prop type: Invalid prop component of type object
supplied to Route, expected function
How can i solve this.?
Below is the code
import React from 'react';
import { Form, Icon, Input, Button, Checkbox } from 'antd';
import { withCookies } from "react-cookie";
import './Login.css';
class NormalLoginForm extends React.Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log(values);
const { cookies } = this.props;
cookies.set('token', 'dfsfsd54dg2g45fg575f432sd4');
}
});
}
render() {
const { getFieldDecorator } = this.props.form;
return (
<div style={{ textAlign: 'center' }}>
<img className="logo-white" src={'https://cdn.medcampus.io/wp-content/uploads/2018/08/01131559/MC_Logo_Black.png'} alt="logo"/>
<div className="login-container">
<br/>
<Form onSubmit={this.handleSubmit} className="login-form">
<Form.Item>
{getFieldDecorator('email', {
rules: [{ required: true, message: 'Please input your Email id!' }, {
type: 'email', message: 'The input is not valid E-mail!',
}],
})(
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Email" size={"large"} />
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" size={"large"} placeholder="Password" />
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: true,
})(
<Checkbox>Remember me</Checkbox>
)}
<a className="login-form-forgot" href="">Forgot password</a>
<Button type="primary" size={"large"} htmlType="submit" className="login-form-button">Log in</Button>
</Form.Item>
</Form>
</div>
</div>
);
}
}
const Login = withCookies(Form.create({ name: 'normal_login' })(NormalLoginForm));
export { Login };
Following the comments, you are exporting all imports from your containers' files as default, so basically you'll get an object, not a function(the exact export).
To prevent this, there is several ways to do it:
Import your container in App from its own file.
in index.js of pages, you can do this :
import { Login } from `LoginContainerFile`;
import { Comp1} from `Comp1ContainerFile`;
import { Comp2} from `Comp2ContainerFile`;
export { Login, Comp1, Comp2 };
Good luck and hope it resolves your problem.

Unexpected token (8:8) while parsing file

I'm using antd and I wanna use its registration Form in my project.
Note: Before adding this component my project (registration.js) was working correctly and I've just copied and pasted the antd component.
Here is my registration.js file:
import { Form, Input, Tooltip, Icon, Cascader, Select, Row, Col, Checkbox, Button, AutoComplete } from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const AutoCompleteOption = AutoComplete.Option;
class RegistrationForm extends React.Component {
state = {
confirmDirty: false,
autoCompleteResult: [],
};
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
}
handleConfirmBlur = (e) => {
const value = e.target.value;
this.setState({ confirmDirty: this.state.confirmDirty || !!value });
}
compareToFirstPassword = (rule, value, callback) => {
const form = this.props.form;
if (value && value !== form.getFieldValue('password')) {
callback('Two passwords that you enter is inconsistent!');
} else {
callback();
}
}
validateToNextPassword = (rule, value, callback) => {
const form = this.props.form;
if (value && this.state.confirmDirty) {
form.validateFields(['confirm'], { force: true });
}
callback();
}
handleWebsiteChange = (value) => {
let autoCompleteResult;
if (!value) {
autoCompleteResult = [];
} else {
autoCompleteResult = ['.com', '.org', '.net'].map(domain => `${value}${domain}`);
}
this.setState({ autoCompleteResult });
}
render() {
const { getFieldDecorator } = this.props.form;
const { autoCompleteResult } = this.state;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
},
};
const tailFormItemLayout = {
wrapperCol: {
xs: {
span: 24,
offset: 0,
},
sm: {
span: 16,
offset: 8,
},
},
};
const prefixSelector = getFieldDecorator('prefix', {
initialValue: '86',
})(
<Select style={{ width: 70 }}>
<Option value="86">+86</Option>
<Option value="87">+87</Option>
</Select>
);
const websiteOptions = autoCompleteResult.map(website => (
<AutoCompleteOption key={website}>{website}</AutoCompleteOption>
));
return (
<Form onSubmit={this.handleSubmit}>
<FormItem
{...formItemLayout}
label="E-mail"
>
{getFieldDecorator('email', {
rules: [{
type: 'email', message: 'The input is not valid E-mail!',
}, {
required: true, message: 'Please input your E-mail!',
}],
})(
<Input />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Password"
>
{getFieldDecorator('password', {
rules: [{
required: true, message: 'Please input your password!',
}, {
validator: this.validateToNextPassword,
}],
})(
<Input type="password" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Confirm Password"
>
{getFieldDecorator('confirm', {
rules: [{
required: true, message: 'Please confirm your password!',
}, {
validator: this.compareToFirstPassword,
}],
})(
<Input type="password" onBlur={this.handleConfirmBlur} />
)}
</FormItem>
<FormItem
{...formItemLayout}
label={(
<span>
Nickname
<Tooltip title="What do you want others to call you?">
<Icon type="question-circle-o" />
</Tooltip>
</span>
)}
>
{getFieldDecorator('nickname', {
rules: [{ required: true, message: 'Please input your nickname!', whitespace: true }],
})(
<Input />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Habitual Residence"
>
{getFieldDecorator('residence', {
initialValue: ['zhejiang', 'hangzhou', 'xihu'],
rules: [{ type: 'array', required: true, message: 'Please select your habitual residence!' }],
})(
<Cascader options={residences} />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Phone Number"
>
{getFieldDecorator('phone', {
rules: [{ required: true, message: 'Please input your phone number!' }],
})(
<Input addonBefore={prefixSelector} style={{ width: '100%' }} />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Website"
>
{getFieldDecorator('website', {
rules: [{ required: true, message: 'Please input website!' }],
})(
<AutoComplete
dataSource={websiteOptions}
onChange={this.handleWebsiteChange}
placeholder="website"
>
<Input />
</AutoComplete>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="Captcha"
extra="We must make sure that your are a human."
>
<Row gutter={8}>
<Col span={12}>
{getFieldDecorator('captcha', {
rules: [{ required: true, message: 'Please input the captcha you got!' }],
})(
<Input />
)}
</Col>
<Col span={12}>
<Button>Get captcha</Button>
</Col>
</Row>
</FormItem>
<FormItem {...tailFormItemLayout}>
{getFieldDecorator('agreement', {
valuePropName: 'checked',
})(
<Checkbox>I have read the agreement</Checkbox>
)}
</FormItem>
<FormItem {...tailFormItemLayout}>
<Button type="primary" htmlType="submit">Register</Button>
</FormItem>
</Form>
);
}
}
const WrappedRegistrationForm = Form.create()(RegistrationForm);
ReactDOM.render(<WrappedRegistrationForm />, document.getElementById('main'));
And this is my index.html file:
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>React Project</title>
</head>
<body>
<div id="main"></div>
<script src="/build/bundle.js"></script>
</body>
</html>
I face with this error in my registration.js file:
Unexpected token (8:8) while parsing file
Line 8 refers to where we have state = {, how can I solve this problem?
Probably you are not using the right transpilers.
Declaring global variables in classes like your state = { ... } is only possible with ES7 (I believe). You are probably using a ES6 transpiler.
One fix would be changing your syntax to ES6. So you would have to declare you state like this:
class RegistrationForm extends React.Component {
constructor(props) {
super(props);
this.state = { ... };
}
// ...
}
ES6 also doesn't support declaring class methods with arrow syntax (myMethod = () => { ... }). You would have to change all of your methods to myMethod() { ... }
Another fix would be to download the right presets so babel (I'm guessing you are using babel) can transpile your ES7 syntax.

Getting Uncaught TypeError: Super expression must either be null or a function, not undefined

Below is my loginForm.js from where I suspect the error is originating:-
import { Form, Icon, Input, Button, Checkbox } from 'antd';
const FormItem = Form.Item;
import React, { Component } from 'react';
class NormalLoginForm extends Component {
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
}
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem>
{getFieldDecorator('userName', {
rules: [{ required: true, message: 'Please input your username!' }],
})(
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input your Password!' }],
})(
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />
)}
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="login-form-button">
Log in
</Button>
Or register now!
</FormItem>
</Form>
);
}
}
const WrappedNormalLoginForm = Form.create()(NormalLoginForm);
export default WrappedNormalLoginForm;
Below is my main component file where I load handle routing:-
import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import WrappedNormalLoginForm from './loginForm'
export default class App extends Component {
render() {
return (
<div className="container">
<BrowserRouter>
<div>
<Route exact path="/" component={WrappedNormalLoginForm} />
</div>
</BrowserRouter>
</div>
);
}
}
I am unable to resolve this issue. I have extended using capital C which was mentioned as a fix for many of the questions asked regarding this.

Resources