Redux Submitting a form from Presentation Component to Container Component - reactjs

I am using a simple Login Form and i have LoginContainer (Container Component ) and Login (presentation component) and i am trying to submit the form and access the data in the Container Component.
Here is the code i have
Login.js:
export default class Login extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="login jumbotron center-block">
<h1>Login</h1>
<form role="form">
<div className="form-group">
<label htmlFor="username">Username</label>
<input type="text" className="form-control" ref="username" placeholder="Username" />
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input type="password" className="form-control" ref="password" placeholder="Password" />
</div>
<div className="form-group">
<button type="submit" className="btn btn-default" onClick={()=>{this.props.login(this.refs.username,this.refs.password)}}>Submit</button>
</div>
</form>
</div>
);
}
}
And the container component is:
class LoginContainer extends React.Component{
constructor(props){
super(props);
}
render(){
return(
<div>
<Login login={this.loginUser}/>
</div>
);
}
}
function mapStateToProps(state){
return state;
}
function mapDispatchToProps(dispatch){
return{
login : (username,password) => {
console.log('mapDispatchToProps : username=['+username+'] password=['+password+']');
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(LoginContainer);
The above code doesn't work as in the event handler for the submit i cannot access this.refs
Uncaught ReferenceError: refs is not defined
I don't want to maintain the state of Login Component. I can easily create state with username and password in Login and use setState with onclick or onchange on username and password controls.
Is there way i can send the data of form elements from Presentation component to Container component with a form submit ?
Thanks

You need to make event handling methods in Login.js file and bind them to the component context using bind function in the constructor.
export default class Login extends React.Component {
constructor() {
super();
this.login = this.login.bind(this);
}
login() {
this.props.login(this.refs.username,this.refs.password)
}
render() {
return (
<div className="login jumbotron center-block">
<h1>Login</h1>
<form role="form">
<div className="form-group">
<label htmlFor="username">Username</label>
<input type="text" className="form-control" ref="username" placeholder="Username" />
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input type="password" className="form-control" ref="password" placeholder="Password" />
</div>
<div className="form-group">
<button type="submit" className="btn btn-default" onClick={this.login}>Submit</button>
</div>
</form>
</div>
);
}
}
This way you dont maintain state of Logic component, you simply use props passed from the container.

Related

How to accept and pass two parameter as props

Hi I need to pass two parameters, to the class Chat. Currently it is getting only one parameter and displaying correctly.
const Chat = props => (
<div >
<ul>{props.messages.map(message => <li key={message}>{message}</li>)}</ul>
</div>
);
This Chat.js file is called from the Home.js. Suppose I need to pass the Chat component two parameters and I tried it like following.
import React, { Component } from 'react';
import { User } from './User';
import Chat from './Chat';
export class Home extends Component {
displayName = Home.name
state = {
messages: [],
names: []
};
handleSubmit = (message,name) =>
this.setState(currentState => ({
messages: [...currentState.messages, message],
names: [...currentState.names,name]
}));
render() {
return (
<div>
<div>
<User onSubmit={this.handleSubmit} />
</div>
<div>
<Chat messages={this.state.messages,this.state.name} />
</div>
</div>
);
}
}
In this scenario how should I change the Chat component to accept two parameters and display inside div tags.
This is what I tried. But seems it is incorrect.
const Chat = props => (
<div >
<ul>{props.messages.map((message, name) => <li key={message}>{message}</li> <li key={name}>{name}</li>)}</ul>
</div>
);
PS: The User Method
import * as React from 'react';
export class User extends React.Component{
constructor(props) {
super(props);
this.state = {
name: '',
message: ''
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
render() {
return (
<div className="panel panel-default" id="frame1" onSubmit={this.handleSubmit}>
<form className="form-horizontal" action="/action_page.php" >
<div className="form-group">
<label className="control-label col-sm-2" htmlFor="name">Your Name </label>
<div className="col-sm-10">
<input type="text" className="form-control" name="name" placeholder="Enter your Name" onChange={this.handleChange} />
</div>
</div>
<div className="form-group">
<label className="control-label col-sm-2" htmlFor="message">Message</label>
<div className="col-sm-10">
<input type="text" className="form-control" name="message" placeholder="Enter your Message" onChange={this.handleChange}/>
</div>
</div>
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button type="submit" id="submit" className="btn btn-default">Submit</button>
</div>
</div>
</form>
</div>
);
}
handleChange(evt) {
this.setState({ [evt.target.name]: evt.target.value });
}
handleSubmit = (e) => {
e.preventDefault();
this.props.onSubmit(this.state.message, this.state.name);
this.setState({ message: "" });
this.setState({name:""});
};
}
You can do this by using separate attributes to pass different props. So for instance, you might revise your <Home/> components render method like so:
<Chat messages={this.state.messages} names={this.state.names} />
and then to access these two bits of data (messages and name) from inside the <Chat /> component you could do the following:
const Chat = props => (
<div >
<ul>{props.messages.map((message, index) => <li key={message}>
From: { Array.isArray(props.names) ? props.names[index] : '-' }
Message: {message}</li>)}
</ul>
</div>
);
Hope this helps!
You have to pass them separately:
<Chat messages={this.state.messages} name={this.state.name} />

unable to get enter and get value in REACT.js

I am new to ReactJS and trying to build a sample application
I am unable to get enter the value in textbox and unable to get the value in alert. Am I doing something wrong. I have tried the example given on React.Js Form, but not working.
import React, { Component } from "react";
class AddNewStudent extends Component {
constructor(props) {
super(props);
this.state = {value:''};
this.OnSubmit = this.OnSubmit.bind(this);
}
OnSubmit(event){
alert('name value is : '+this.state.value);
event.preventDefault();
}
render(){
return(
<div>
<form onSubmit={this.OnSubmit}>
<fieldset className="Student-Form" id={this.props.id}>
<legend className="Legend">Add mew student</legend>
<div>
<div className="Block">
<div className="Float-Left">
<label>
<span>Name : </span>
<input type="text" value={this.state.value} />
</label>
</div>
</div>
<div className="clearFix" />
<div className="Block">
<div className="Float-None">
<label>
<input type="submit" value="Save" />
</label>
</div>
</div>
</div>
</fieldset>
</form>
</div>
);
}
}
export default AddNewStudent;
please change :
<input type="text" value={this.state.value} />
to:
<input type="text" value={this.state.value} onChange = {this.onChange}/>
In your class, add the 'onChange' function:
onChange(e){
this.setState({
value: e.target.value
})
}
and in your constructor:
this.onChange = this.onChange.bind(this)
Edit 1:
please check my codepen here
Edit 2:
If you have too many inputs, you can use a function like this:(it's just a rough example, in real world I'll create a new component to handle this together)
//in your constructor
this.state = {}
//in class 'controlled component way'
createInput(num){
let inputArray = []
for(let i = 0; i < num; i ++){
inputArray.push(<input key = {i} name = {i} onChange = {this.onChange} value = {this.state[i] || ''} />)
}
return inputArray
}
onChange(e){
let key = e.target.name
let newState = {}
newState[key] = e.target.value
this.setState(newState)
}
// in your render function
return <div>
{this.createInput(100)}
</div>
check my codepen here for this example
and of course you can also do this using uncontrolled component.
controlled component and uncontrolled
You can either bind onChange event to your input or setState when submiting the value , you cant change the state like that
Change your code to something like this
import React, { Component } from "react";
class AddNewStudent extends Component {
constructor(props) {
super(props);
this.state = {value:''};
this.OnSubmit = this.OnSubmit.bind(this);
}
OnSubmit(event){
this.setState({value: this.refs.infield.value},()=>{
alert('name value is : '+this.state.value);
})
event.preventDefault();
}
render(){
return(
<div>
<form onSubmit={this.OnSubmit}>
<fieldset className="Student-Form" id={this.props.id}>
<legend className="Legend">Add mew student</legend>
<div>
<div className="Block">
<div className="Float-Left">
<label>
<span>Name : </span>
<input type="text" ref = "infield"/>
</label>
</div>
</div>
<div className="clearFix" />
<div className="Block">
<div className="Float-None">
<label>
<input type="submit" value="Save" />
</label>
</div>
</div>
</div>
</fieldset>
</form>
</div>
);
}
}
export default AddNewStudent;
Hi to get the value add a name to the input and an onChange function to set the value to the state and then do what evere you want in onsubmit function
I cant write you a working code now because I'm using my phone but my this Will help
onfieldchange(e) {
this.setState({[e.target.name]: e.target.value});
}
onaSubmit(){
//do your code here
}
....
....
<input type="text" name="firstName" value={this.state.firstName} />
Hope this help you
There are two ways to handle form elements in reactjs:
Controlled and uncontrolled components(using refs).In controlled component approach ,you have to add the state of the input field to the input field value and onChange event to it, which is the one you are trying to do.Here is the working code.
import React, { Component } from "react";
class AddNewStudent extends Component {
constructor(props) {
super(props);
this.state = {
firstname:''
};
this.OnSubmit = this.OnSubmit.bind(this);
this.OnChange = this.OnChange.bind(this);
}
OnSubmit(event){
alert('name value is : '+this.state.firstname);
event.preventDefault();
}
OnChange(){
this.setState({
[e.target.name] : [e.target.value]
});
}
render(){
return(
<div>
<form onSubmit={this.OnSubmit}>
<fieldset className="Student-Form" id={this.props.id}>
<legend className="Legend">Add mew student</legend>
<div>
<div className="Block">
<div className="Float-Left">
<label>
<span>Name : </span>
<input type="text"
name="firstname"
value={this.state.firstname}
OnChange={this.OnChange}
/>
</label>
</div>
</div>
<div className="clearFix" />
<div className="Block">
<div className="Float-None">
<label>
<input type="submit" value="Save" />
</label>
</div>
</div>
</div>
</fieldset>
</form>
</div>
);
}
}
export default AddNewStudent;

How to reset form from higher order component in React?

Iam doing an app in react.js in which iam passing a component to higher order component.Now after form submission in PersonalInformation component the form needs to reset which is not happening.It is not happening by refs.
class PersonalInformation extends Component{
render(){
return(
<div>
<h3>Personal Information</h3>
<Form onSubmit={this.props.handleSubmit} ref="form" name="form">
<fieldset disabled={this.props.disabled}>
<Input type="text" name="firstName" title="FirstName" value=""/><br/>
<Input type="text" name="lastName" title="LastName" value=""/><br/>
<Input type="text" name="fatherName" title="Fathers's Name" value=""/><br/>
<Input type="text" name="motherName" title="Mother's Name" value=""/><br/>
</fieldset>
<button className="btn btn-default">{this.props.buttonName}</button>
</Form>
</div>
)
}
}
Now the Higher Order component is:
var MyHoc = function(AbstractComponent){
return class extends React.Component {
constructor(props){
super(props);
this.state={
buttonName:'Edit',
disabled:true,
anotherForm:false
}
this.handleSubmit=this.handleSubmit.bind(this);
this.newForm=this.newForm.bind(this);
}
handleSubmit(data){
this.setState({
buttonName:'Save',
disabled:false
})
if(!this.state.disabled){
console.log(data);
this.refs.form.reset();
}
}
newForm(){
this.setState({
anotherForm:true
})
}
render() {
return <AbstractComponent {...this.state} handleSubmit={this.handleSubmit}
newForm={this.newForm} />;
}
}
}
export default MyHoc(PersonalInformation);
You cannot access refs from different components. this.refs refers to the ref defined in that particular component.
You can pass a callback method in handleSubmit function and handlesubmit will call that method when it want to reset form. Something like this
handleSubmit(data, resetFormCallback){
this.setState({
buttonName:'Save',
disabled:false
})
if(!this.state.disabled){
console.log(data);
resetFormCallback();
}
}
And then in your child component you pass a callback method while calling handleSubmit
class PersonalInformation extends Component{
resetForm = () => {
this.refs.form.reset();
}
render(){
return(
<div>
<h3>Personal Information</h3>
<Form onSubmit={(data) => {this.props.handleSubmit(data, this.resetForm)}} ref="form" name="form">
<fieldset disabled={this.props.disabled}>
<Input type="text" name="firstName" title="FirstName" value=""/><br/>
<Input type="text" name="lastName" title="LastName" value=""/><br/>
<Input type="text" name="fatherName" title="Fathers's Name" value=""/><br/>
<Input type="text" name="motherName" title="Mother's Name" value=""/><br/>
</fieldset>
<button className="btn btn-default">{this.props.buttonName}</button>
</Form>
</div>
)
}
}
this refers to the component in hand. You are looking for a ref on another component, so that's not going to work.
At this line: this.refs.form.reset(); instead set some state like resetForm:true, which then gets passed down to your child component. Then you can reset your form from the component it lives in based on the state that gets passed to it via props.

How can I handle redux form submission in child component?

In all examples that I read, we always handle submission of the form from parent component.
For instance:
export default class ParentComponent extends React.Component{
constructor(){
super();
this.state = {
working: false,
users: []
}
}
handleSubmit(values){
//do something
}
render(){
return(
<div className="container">
<ReduxForm onSubmit={this.handleSubmit.bind(this)} {...this.props}/>
</div>
);
}
}
and in child component
class ReduxForm extends React.Component{
constructor(){
super();
}
render(){
const {handleSubmit, pristine, reset, submitting } = this.props;
return(
<div>
<h2>Hello, Redux form</h2>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="firstName">First Name</label>
<Field name="firstName" component="input" type="text" className="form-control"/>
</div>
<div className="form-group">
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" component="input" type="text" className="form-control"/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-success">Submit</button>
</div>
</form>
</div>
);
}
}
I think we should handle the submission in ReduxForm (child component) for reusable (what if we have another page, use that form again and we have to handle submission every time?)
I tried to handle the submission in redux form way, but it's not success.
Any idea?
Thank you so much!
You can delegate the submission callback to the function of your choice
class ReduxForm extends React.Component{
constructor(){
super();
this.submit = this.submit.bind(this);
}
submit(values) {
alert('SUBMIT : ' + JSON.stringify(values));
}
render(){
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.submit)}>
// ^^^^^^^^^^^
// Your submission handler
// ...
</form>
}
}

Cannot trigger component's function in my react app

I am currently working with react and I have runned into a problem this morning that i do not understand.
I am trying to handle a form submit from my component with a function by passing it in the onSubmit property but it does not trigger it. I then added a button to trigger a mock function with its onClick property, and i still got the same problem; it appears than I can't trigger my function and I cannot find any solution on the Google.
Here is my code so you can check it out:
import React from 'react';
import AgentsStore from '../stores/AgentsStore';
import AgentsActions from '../actions/AgentsActions';
class Agents extends React.Component {
constructor(props) {
super(props);
this.state = AgentsStore.getState();
this.onChange = this.onChange.bind(this);
}
componentDidMount() {
AgentsStore.listen(this.onChange);
}
componentWillUnmount() {
AgentsStore.unlisten(this.onChange);
}
onChange(state) {
this.setState(state);
}
handleSubmit(event) {
event.preventDefault();
var user = {};
user.name = this.state.newUser.name.trim();
user.lastname = this.state.newUser.lastname.trim();
if (user.name && user.lastname) {
AgentsActions.createUser(user);
}
}
onClick() {
console.log('clicked');
}
render() {
return (
<div /*className='container'*/>
<div className='alert alert-info'>
Hello from Agents
</div>
<div className='panel panel-default'>
<div className='panel-heading'>Create User</div>
<div className='panel-body'>
<form onSubmit={this.handleSubmit.bind(this)}>
<div className='form-group'>
<label className='control-label'>Name</label>
<input type='text'
className='form-control'
ref='nameTextField'
value={this.state.newUser.name}
onChange={AgentsActions.updateName} />
</div>
<div className='form-group'>
<label className='control-label'>Lastname</label>
<input type='text'
className='form-control'
ref='lastnameTextField'
value={this.state.newUser.lastname}
onChange={AgentsActions.updateLastname} />
</div>
<h4>Address</h4>
<button type='submit' className='btn btn-primary'>Submit</button>
</form>
<button onClick={this.onClick} className='btn btn-primary'>Submit</button>
</div>
</div>
</div>
)
}
}
export default Agents;
I do not know if I am missing something in my code or there is an error but i am kind of desperate. Also I am basing my code on another file that i have which is working just fine...
Thank you in advance for your time

Resources