ReactJS add multiple input fields dynamically - reactjs

Hello I am new to React and am lost at trying to figure out how to add input field dynamically with React.
If someone can please help me in figuring out how to bind an onclick to add another field dynamically to the form.
How can i click add button and another option input will render
class AddPost extends Component {
static contextTypes = {
router: React.PropTypes.object
};
appendInput() {
var newInput = `input-${this.state.inputs.length}`;
this.setState({ inputs: this.state.inputs.concat([newInput]) });
}
handleFormSubmit(formProps){
this.props.addPost(formProps);
this.context.router.push('/posts');
}
render(){
const {handleSubmit,fields:{title,option}} = this.props;
return (
<div className="row top-buffer">
<div className="col md-auto">
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<fieldset className="form-group">
<label>Question:</label>
<input {...title} className="form-control" placeholder="Enter question here"/>
{title.touched && title.error && <div className="text-danger">{title.error}</div>}
</fieldset>
<fieldset className="form-group">
<label>Option:</label>
<input {...option} className="form-control" placeholder="Enter option"/>
{option.touched && option.error && <div className="text-danger">{option.error}</div>}
</fieldset>
<fieldset className="form-group">
<label>Option:</label>
<input {...option} className="form-control" placeholder="Enter option"/>
{option.touched && option.error && <div className="text-danger">{option.error}</div>}
</fieldset>
<button className="btn btn-success">Add</button>
</form>
<button onClick={ () => this.appendInput() }>
CLICK ME TO ADD AN INPUT
</button>
</div>
</div>
);
}
}
function validate(formProps){
const errors = {};
if(! formProps.title){
errors.title = "Title is required";
}
if(! formProps.option){
errors.body = "Option is required";
}
return errors;
}
function mapStateToProps(state){
return {
posts:state.post
}
}
export default reduxForm({
form:'post',
fields:['title','body'],
validate:validate,
},mapStateToProps,{addPost})(AddPost);

If you are using redux-form. Checkout the example with FieldArray, that should help.

Related

Clicking on react button asks me to leave site

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>
</>
)
}

Working with input[type="text"] and input[type="checkbox"] in react.js

I was working with checkboxes type input in the form. Just want to know the way I am handling it, Is it the right way or not?
Code:
import React from 'react';
import { AiOutlineSearch } from "react-icons/ai";
import { useScroll } from '../custom_hook/useScroll';
const SearchBar = ({ totalPrograms, programs, setPrograms, isLoading }) => {
const scrolled = useScroll();
const handleSubmit = (event) => {
event.preventDefault();
const searchProgramName = document.getElementById('search').value;
if(searchProgramName) {
setPrograms(
programs.filter(program =>
program.name.toLowerCase().includes(searchProgramName)
)
);
}
else {
handleClick();
}
}
const handleClick = () => {
const allPhase = document.getElementsByName('phase');
const checkedPhaseValue = [];
allPhase.forEach(phase => {
if(phase.checked) {
checkedPhaseValue.push(phase.value);
}
});
setPrograms(checkedPhaseValue.length ?
totalPrograms.filter(
program => checkedPhaseValue.includes(program.phase.toLowerCase())
)
: totalPrograms
);
}
return (
<header className={`container header header-sb ${scrolled && 'h-shadow'}`}>
<form className="container container-center" onSubmit={handleSubmit}>
<div className="type-search">
<AiOutlineSearch className="icon"/>
<input id="search" disabled={isLoading} type="search" placeholder="search by program name"/>
</div>
<div className="checkbox-container">
<div className="d-inline">
<input type="checkbox" disabled={isLoading} onClick={handleClick} name="phase" id="open_application" value="application_open"/>
<label htmlFor="open_application">Open Application</label>
</div>
<div className="d-inline">
<input type="checkbox" disabled={isLoading} onClick={handleClick} name="phase" id="application_in_review" value="application_review"/>
<label htmlFor="application_in_review">Application in Review</label>
</div>
<div className="d-inline">
<input type="checkbox" disabled={isLoading} onClick={handleClick} name="phase" id="in_progress" value="in_progress"/>
<label htmlFor="in_progress">in Progress</label>
</div>
<div className="d-inline">
<input type="checkbox" disabled={isLoading} onClick={handleClick} name="phase" id="completed" value="completed"/>
<label htmlFor="completed">Completed</label>
</div>
</div>
</form>
</header>
)
}
export default SearchBar;
The work I have to do is :
● Once the list is loaded, the user can now search through the page based on two
parameters:
The name of the program
Filter on the stage of the programs
● Once the user applies this filter+search then the page should pick out the programs
and show the result set (the filter is to be done on the front end and not a separate
server call)

React updating the state value in a wrong place

I am trying to implement a simple form validation in React where the length of the name should be more than 1 char long, length of country should be more than 2 char long along with the password. However, the password and the country are getting validated properly. But, the name field isn't getting properly validated. Firstly, it's allowing to submit the name if it's just 1 char long and instead is showing the error in the country's span tag. Also, I am not sure how to implement the logic for email validation. Here is my code:
import React, { Component } from "react";
export default class SignUp extends Component {
constructor(){
super();
this.state={
name:'',
country:'',
email:'',
pass:'',
formErrors:{
nameError:'',
countryError:'',
emailError:'',
passwordError:''
}
}
this.handleChange=this.handleChange.bind(this);
this.handleValidate=this.handleValidate.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
handleChange =(e) =>{
let name=e.target.name;
let value=e.target.value;
this.setState({
[name]:value
})
}
handleValidate= () =>{
let { name,country,email,pass} =this.state;
let nameError, countryError, emailError, passError;
if(!name)
nameError="Missing name"
if(name && name.length<2)
countryError="Length of name should be more than 1 character"
if(!country)
countryError="Missing country"
if(country && country.length<3)
countryError="Length of country should be more than 2 characters"
/* if(!email)
emailError="Email can't be empty"
let lastAtPosi=email.lastIndexOf('#');
let lastDotPosi=email.lastIndexOf('.');
console.log("last # posti"+lastAtPosi);
console.log("Last . posi"+lastDotPosi);
*/
if(!pass)
passError="Password can't be empty"
if(pass && pass.length<6)
passError="Password must be more than 6 characters long"
this.setState({
formErrors:{
nameError:nameError,
countryError:countryError,
// emailError:emailError,
passwordError:passError
}
})
console.log("name "+nameError);
}
handleSubmit= (e) =>{
e.preventDefault();
this.handleValidate();
}
render() {
const { name, country, email, pass, formErrors } = this.state;
return (
<div>
<form>
<h3>Sign Up</h3>
<div className="form-group">
<label>Name</label>
<input type="text" onChange={this.handleChange}name="name"value={name} className="form-control" placeholder="Enter name" />
{formErrors.nameError? <span variant="danger">{formErrors.nameError}</span>:'valid'}
</div>
<div className="form-group">
<label>Country</label>
<input type="text" onChange={this.handleChange}name="country"value={country} className="form-control" placeholder="Enter country" />
{formErrors.countryError? <span variant="danger">{formErrors.countryError}</span>:'valid'}
</div>
<div className="form-group">
<label>Email address</label>
<input type="email" onChange={this.handleChange}name="email"value={email} className="form-control" placeholder="Enter email" />
{formErrors.emailError?<span variant="danger">{formErrors.emailError}</span>:'valid'}
</div>
<div className="form-group">
<label>Password</label>
<input type="password" onChange={this.handleChange}name="pass" value={pass} className="form-control" placeholder="Enter password" />
{formErrors.passwordError?<span variant="danger">{formErrors.passwordError}</span>:'valid'}
</div>
<button onClick={this.handleSubmit}type="submit" className="btn btn-primary btn-block">Sign Up</button>
</form>
</div>
);
}
}
Sandbox linkenter link description here
In your handleValidate, you assign an error to the wrong error variable:
if(name && name.length<2)
countryError="Length of name should be more than 1 character"
It should be:
if(name && name.length<2)
nameError="Length of name should be more than 1 character"

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;

Unable to type in input after adding value in React Js

I have tried with the following code with react js
import React, { Component } from 'react';
import Sidebar from './../Sidebar';
import Header from './../Header';
import {get_profile} from './../services/Services';
import $ from 'jquery';
export default class Profile extends Component {
constructor(props) {
super(props);
this.state = { userDetails: '' } ;
}
componentWillMount() {
$(window).scrollTop(0)
console.log('sdfds')
get_profile().then((response) => {
var userResults = $.parseJSON(response.text);
this.setState({ userDetails: userResults.response });
console.log(userResults);
}).catch((error) => {
//alert(error)
console.log(error);
});
}
handleChange(event) {
console.log(event.target.id)
this.setState({[event.target.name]: event.target.value});
}
render() {
return (
<div className="admin-panel">
<Sidebar />
<Header />
<div className="main-content">
<div className="contents">
<div className="container-fluid">
<div className="row">
<div className="col-sm-6">
<h2 className="page-title">Profile</h2>
<div className="form-group">
<label >First Name</label>
<input type="text" id="firstName" className="form-control" value={this.state.userDetails.firstName} />
</div>
<div className="form-group">
<label >Last Name</label>
<input type="text" id="lastName" className="form-control" value={this.state.userDetails.lastName} />
</div>
<div className="form-group">
<label >Email</label>
<input type="text" id="email" name="email" className="form-control" value={this.state.userDetails.email} />
</div>
<button type="button" className="btn btn-squared btn-success margin-inline" onClick={(e)=> {this.profileUpdate()}}>Update</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
After fetching the results i'm unable to edit the input box value. I have tried with defaultValue but that also not working for me. I'm struck with this issue, Kindly help me to solve the issue.
Just pass an onChange handler to the input which will update the value of the corresponding key of userDetails like this:
<input
...
value={this.state.userDetails.firstName}
onChange={this.onChange}
/>
onChange(e) {
this.setState((previousState) => {
const userDetails = previousState.userDetails
return { userDetails: {...userDetails, firstName: e.target.value} }
})
}
or you can write a common onChange function like this:
<input
...
value={this.state.userDetails.firstName}
onChange={(e) => {this.onChange(e.target.value, 'firstName')}}
/>
<input
...
value={this.state.userDetails.lastName}
onChange={(e) => {this.onChange(e.target.value, 'lastName')}}
/>
<input
...
value={this.state.userDetails.email}
onChange={(e) => {this.onChange(e.target.value, 'email')}}
/>
onChange(value, key) {
this.setState((previousState) => {
const userDetails = previousState.userDetails
return { userDetails: {...userDetails, [key]: value} }
})
}

Resources