I am working on a React-Redux app, currently working on showing a modal box on a button click of a form. But I can't make it work. I have tried so many things but can't figure out why the modal box doesn't appear. Here is my code.
The Modal component file
import React from 'react'
import { connectModal } from 'redux-modal'
import { Button, Modal } from 'react-bootstrap'
import UpdatePasswordForm from 'forms/updatepassword'
export class UpdatePassword extends React.Component {
constructor(props) {
super(props)
}
renderCloseIcon (handleHide) {
return (
<button className='close' onClick={ handleHide }>
<span>
<i className="modal__close"/>
</span>
</button>
)
}
renderModalLogo () {
return (
<div className="modal__header modal__header_login">
<div className="modal__logo"></div>
</div>
)
}
render() {
const { show, handleHide } = this.props
return (
<Modal
show={ show }
onHide={ handleHide }
backdrop={ true }
className="modal_dark modal_center"
dialogClassName="modal-background-fix">
<div className="modal__container">
{ this.renderCloseIcon(handleHide) }
{ this.renderModalLogo() }
<div className="modal__content">
<UpdatePasswordForm onSubmit={() => {}}/>
</div>
</div>
</Modal>
)
}
}
export default connectModal({name: 'updatepassword'})(UpdatePassword)
The form that is loaded in the Modal
import React from 'react'
import { Field, reduxForm } from 'redux-form'
import Text from '../containers/Text'
const I18n = {}
I18n.t = Text.t
const UpdatePasswordForm = (props) => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<fieldset className="form-group">
<Field name="current_password" component="input"
type="password" placeholder="Password" className="form-control" />
</fieldset>
<fieldset className="form-group">
<Field name="password" component="input"
type="password" placeholder="New Password" className="form-control" />
</fieldset>
<fieldset className="form-group">
<Field name="password_confirm" component="input" type="password"
placeholder="New password confirmation" className="form-control" />
</fieldset>
<fieldset className="form-group form-group_btns">
<button type="submit" disabled={pristine || submitting} className="btn btn-primary btn-block">
{ 'CHANGE PASSWORD' }
</button>
</fieldset>
</form>
)
}
export default reduxForm({
form: 'updatepassword' // a unique identifier for this form
})(UpdatePasswordForm)
The file where modal is called
import React from 'react';
import './EditInformation.scss'
import { show } from 'redux-modal'
import UpdatePassword from './Modals/UpdatePassword'
// TODO fix stylee stylee
// TODO onChange is not updating correctly, FIX!
const EditInformation = ({ onSubmit, onChange, user, formSubmitting }) => {
return (
<div>
<UpdatePassword />
<form className='form-line form-line_light'>
<div className='col-xs-16 col-sm-8'>
<fieldset className='form-group'>
<button
onClick={(e) => {
show('updatepassword')
e.preventDefault()
}}
className='btn btn-secondary btn-lg profile-edit__addcard'
style={ { position: 'relative', top: '-27px' } }>
<i className='fa fa-plus'/>Vaihda salasana
</button>
</fieldset>
</div>
</form>
</div>
);
};
export default EditInformation;
In the beginning of our project, I tried to develope my own modal with all custom functionalities. Many problems has occured. I searched some open source projects, then I found a project on github. You should use react-modal, It's easy to use and well designed.
react-modal
There was a stupid mistake that I have figured out now. But I should get an error for that which I am not getting. I had to pass 'show' to the const EditInformation which I have done now and it is working all fine. Here is that part of the code:
const EditInformation = ({ onSubmit, onChange, user, formSubmitting, show }) => {
I wasn't passing 'show' previously.
Related
I am learning react and I have a component which as a 2 input fields and a button, at the moment, clicking on the button will display a message in console log, but when the button is clicked it displays a popup Leave site?, Changes that you made may not be saved.
this is my code in this component
import React, { useRef, useState, Component } from 'react'
import { useAuthState } from 'react-firebase-hooks/auth';
import { useCollectionData } from 'react-firebase-hooks/firestore';
import { signOut } from 'firebase/auth';
class InfoLgnTest extends Component {
render() {
this.state = {
user: null
}
return (
<div>
<div className="App">
<SignInWithEmailPassword />
</div>
</div>
)
}
}
function SignInWithEmailPassword() {
const emailRef = useRef()
const passwordRef = useRef()
const signIn = () => {
console.log("InfoLgnTest singin clicked")
}
return (
<>
<div className="form">
<form>
<div className="input-container">
<label>Username </label>
<input
name="email"
type="text"
ref={emailRef}
required
placeholder ="something#gmail.com"
/>
</div>
<div className="input-container">
<label>Password </label>
<input
type="text"
name="pass"
ref={passwordRef}
required
placeholder ="..."
/>
</div>
<div className="button-container">
<input type="submit" onClick={signIn}/>
</div>
</form>
</div>
</>
)
}
export default InfoLgnTest
This code has a form, by default form send data as a request on the same page, for resolve this:
Add onSubmit to form,
call preventDefault method from event
call the function signIn
Change <input type="submit" ... /> to <button type="submit">Send</button>
function SignInWithEmailPassword() {
const emailRef = useRef()
const passwordRef = useRef()
const signIn = () => {
console.log("InfoLgnTest singin clicked")
}
// new function to handle submit
const submitForm = (event) => {
event.preventDefault();
signIn();
}
return (
<>
<div className="form">
{/* Add onSubmit */}
<form onSubmit={submitForm}>
<div className="input-container">
<label>Username </label>
<input
name="email"
type="text"
ref={emailRef}
required
placeholder ="something#gmail.com"
/>
</div>
<div className="input-container">
<label>Password </label>
<input
type="text"
name="pass"
ref={passwordRef}
required
placeholder ="..."
/>
</div>
<div className="button-container">
{/* Change input to button */}
<button type="submit">Send</button>
</div>
</form>
</div>
</>
)
}
when i try to login then i get this error (TypeError: Cannot read property 'validateFields' of undefined), i also read the documentation about antd but i don't want to use antd in my project how can i resolve this issue without antd... i have simple react-bootstrap Form... anybody know how can i solve this issue?
login.js
import React from 'react'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux';
import { Form } from 'react-bootstrap';
import * as actions from './actions/auth';
import FullPageLoader from "../components/FullPageLoader";
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>
);
}
return (
<div className="form-flex">
{errorMessage}
{
this.props.isLoading ?
<FullPageLoader />
:
<Form onSubmit={this.handleSubmit} className="login-form form-group">
<h1 className="h4 text-center font-weight-normal">Sign in</h1>
<div className="form-group">
<input
className="form-control"
name="username"
autoComplete="off"
type="text"
required
placeholder="username" />
</div>
<div className="form-group">
<input
className="form-control"
name="password"
autoComplete="off"
type="password"
required
placeholder="password" />
</div>
<div className="form-group">
<button type="submit" className="btn btn-block btn-secondary">Login</button>
</div>
<small>
<Link to="/passwordforget">Forgot password?</Link>
</small>
</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);
The error Cannot read property 'validateFields' of undefined is being caused by the code this.props.form.validateFields. You are not passing a form prop into the component so it is undefined, and throwing that error.
Either define a validator somewhere and use it, or remove that line.
import React, { Component } from 'react';
import TaskBar from './Task';
class Todo extends Component {
state = {
todo: ''
}
changeHandler = (event) => {
console.log(event.target.value);
}
render() {
return (
<React.Fragment>
<div className="card">
<h5 className="card-header">Todo</h5>
<div className="card-body">
<h5 className="card-title">Task you want to do</h5>
<form>
<input type="text" className="form-control" value={this.state.todo} name="todo" onChange={(event) => this.changeHandler(event)} />
</form>
</div>
<button className="btn btn-primary">Go somewhere</button>
</div>
</React.Fragment>
)
}
}
export default Todo;
In the above code i don't know why i couldn't make any change
2) I am using Bootstrap cdn in my public folder and i am using these classes here
You forgot to set state inside your onchange handler.
import React, { Component } from 'react';
import TaskBar from './Task';
class Todo extends Component {
state = {
todo: ''
}
changeHandler = (event) => {
console.log(event.target.value);
this.setState({todo: event.target.value}) //you forgot to do this//
}
render() {
return (
<React.Fragment>
<div className="card">
<h5 className="card-header">Todo</h5>
<div className="card-body">
<h5 className="card-title">Task you want to do</h5>
<form>
<input type="text" className="form-control" value={this.state.todo} name="todo" onChange={(event) => this.changeHandler(event)} />
</form>
</div>
<button className="btn btn-primary">Go somewhere</button>
</div>
</React.Fragment>
)
}
}
export default Todo;
Link to a codesandbox example - https://codesandbox.io/s/jydjj?module=/example.js
Also currently your onchange uses an arrow function which creates a new function on every hit which is considered bad practice so i would suggest you to do this instead.
<input type="text" className="form-control" value={this.state.todo} name="todo" onChange={this.changeHandler} />
I am getting error while using redux-form
Error msg in console:
bundle.js:32511 Uncaught Error: You must either pass handleSubmit()
an onSubmit function or pass onSubmit as a prop(…)
the above error appeared on page load and button click
Please refer to the below code sample which cause the console error.
import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
import { createPost } from '../actions/index';
class PostsNew extends Component {
render() {
const { fields: { title, categories, content }, handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.props.createPost)}>
<h3>Create a new Post</h3>
<div className="form-group">
<label>Title</label>
<input type="text" className="form-control" {...title}/>
</div>
<div className="form-group">
<label>Categories</label>
<input type="text" className="form-control" {...categories}/>
</div>
<div className="form-group">
<label>Content</label>
<textarea className="form-control" {...content}/>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
);
}
}
export default reduxForm({
form: 'PostsNewForm',
fields: ['title', 'categories', 'content']
}, null, { createPost })(PostsNew);
This was a step by step follow of StephenGrider redux tutorial
Thanks in advance :)
If PostsNew is Container (if this is directly invoked form Routes) then you have to make handleSubmit function instead of taking from this.props
import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
import { createPost } from '../actions/index';
class PostsNew extends Component {
handleSubmit(formValues){
console.log(formValues);
//do what ever you want
}
render() {
const { fields: { title, categories, content } } = this.props;
return (
<form onSubmit={this.handleSubmit(this.props.createPost)}>
<h3>Create a new Post</h3>
<div className="form-group">
<label>Title</label>
<input type="text" className="form-control" {...title}/>
</div>
<div className="form-group">
<label>Categories</label>
<input type="text" className="form-control" {...categories}/>
</div>
<div className="form-group">
<label>Content</label>
<textarea className="form-control" {...content}/>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
);
}
}
OR
In case PostsNew is React Component that is used inside a Container then you can pass handleSubmit in props of PostsNew
<PostsNew
handleSubmit={ (values) => {console.log(values)}}
/>
You need to pass onsubmit props from parent component
import React from 'react';
import { connect } from 'react-redux';
import { initialize } from 'redux-form';
import PostsNew from './PostsNew';
class App extends React.Component {
handleSubmit(data) {
console.log('Submission received!', data);
this.props.dispatch(initialize('contact', {})); // clear form
}
render() {
return (
<div id="app">
<h1>App</h1>
<PostsNew onSubmit={this.handleSubmit.bind(this)}/>
</div>
);
}
}
export default connect()(App);
I was running into the same problem until I explicitly imported connect into my file. After that, I was able to call this.props.createPost successfully.
This is my solution:
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form'
import { createPost } from '../actions/index';
import { connect } from 'react-redux';
class PostsNew extends Component {
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.props.createPost)}>
<h3>Create a New Post</h3>
<div className="form-group">
<label>Title</label>
<Field name="title" component="input" type="text" className="form-control" placeholder="Title" />
</div>
<div className="form-group">
<label>Categories</label>
<Field name="categories" component="input" type="text" className="form-control" placeholder="Title" />
</div>
<div className="form-group">
<label>Content</label>
<Field name="content" component="textarea" type="text" className="form-control" placeholder="Title" />
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
);
}
}
export default connect(null, {createPost})(reduxForm({
form: 'PostsNew'
})(PostsNew));
This works perfectly. Check your action creator there should be a typo error in your action creator. Please refer the below action creator. If you followed the steps as he mentioned, this should work perfectly. What the error says is you don't have something called createPost in your props. Further more you can find my working project here in github.
export function createPost(props) {
console.log(props);
const request = axios.post(`${ROOT_URL}/posts${API_KEY}`, props);
return {
type: CREATE_POST,
payload: request
};
}
please install version 5 of redux-form.
npm install --save redux-form#5
I'm trying to create a redux form (using redux-form) that can dynamically create it's own inputs. I am having trouble figuring out how to make redux-form aware of the new fields that have been created. Is it possible to dynamically change the fields prop that redux-form passes in within the form component itself? Am I thinking about this wrong? Here is what I am working with.
class AddCustomer extends Component {
render() {
class Form extends Component {
constructor(props, context) {
super(props, context)
this.state = {
inputsToAdd: []
};
}
handleAddInput() {
let inputsToAdd = this.state.inputsToAdd.slice();
inputsToAdd.push(this.state.inputsToAdd.length);
this.setState({ inputsToAdd });
}
submitForm(data) {
console.log(data)
this.setState({inputsToAdd: []});
this.props.dispatch(initialize('addCustomer', {}))
}
render() {
const { fields, handleSubmit } = this.props;
return (
<div>
<form onSubmit={handleSubmit(this.submitForm.bind(this))}>
<Input type='text' label='Company name' {...fields['companyName']}/>
<Input type='email' label='Admin user email' {...fields['adminEmail']}/>
</form>
{this.state.inputsToAdd.map((element, index) => {
return (
<Input key={index} type='text' />
)
})}
<Button onClick={() => this.handleAddInput()}>Add Input</Button>
<Button onClick={handleSubmit(this.submitForm.bind(this))}>Submit</Button>
</div>
)
}
}
Form = connectReduxForm({
form: 'addCustomer',
fields: ['companyName', 'adminEmail']
})(Form);
return (
<div>
<h1>Add Customer</h1>
<Form />
</div>
)
}
}
As of Redux Form 6.* you can achieve what you are trying to do using <FieldArray/>
See the example below (taken from Redux documentation and slightly simplified)
import React from 'react'
import { Field, FieldArray, reduxForm } from 'redux-form'
import validate from './validate'
const renderMembers = ({ fields, meta: { touched, error } }) => (
<ul>
<li>
<button type="button" onClick={() => fields.push({})}>Add Member</button>
{touched && error && <span>{error}</span>}
</li>
{fields.map((member, index) =>
<li key={index}>
<button
type="button"
title="Remove Member"
onClick={() => fields.remove(index)}/>
<h4>Member #{index + 1}</h4>
<Field
name={`${member}.firstName`}
type="text"
component={renderField}
label="First Name"/>
<Field
name={`${member}.lastName`}
type="text"
component={renderField}
label="Last Name"/>
</li>
)}
</ul>
)
const FieldArraysForm = (props) => {
const { handleSubmit, submitting } = props
return (
<form onSubmit={handleSubmit}>
<FieldArray name="members" component={renderMembers}/>
<div>
<button type="submit" disabled={submitting}>Submit</button>
</div>
</form>
)
}
export default reduxForm({
form: 'fieldArrays', // a unique identifier for this form
validate
})(FieldArraysForm)
For more info checkout the documentation
http://redux-form.com/6.1.1/examples/fieldArrays/