react-bootstrap - Form.Control defaultValue not updated when re-rendered - reactjs

When I call setState and my form is re-rendered, the value of the text input doesn't change.
import React, { Component } from 'react';
import { Button, Col, Form, Row } from 'react-bootstrap';
export default class Test extends Component {
constructor(props) {
super(props);
this.state = {
status: "new"
}
}
approve = (e) => {
this.setState({
status: "I'm newer than you!"
});
e.preventDefault();
}
render() {
return (
<div>
Status is {this.state.status}
<Form onSubmit={this.approve}>
<Form.Group as={Row} controlId="status">
<Form.Label column >Status</Form.Label>
<Col>
<Form.Control readOnly type="text" size="sm" defaultValue={this.state.status} />
</Col>
</Form.Group>
<Form.Group as={Row}>
<Button type="submit">approve</Button>
</Form.Group>
</Form>
</div>
);
}
}
When I click on the button, I see the static text ("Status is ...") get updated but the input field does not. Have I wrongly assumed the text input should update?

If you want to change it, you can replace 'defaultValue' with 'value' in FormControl component.
<Form.Control readOnly type="text" size="sm" value={this.state.status} />

Related

react - pass function by props in stateless and run in function

I want to call a function passed from a parent in react stateless component and run that function in the child (checkBoxhandleChange).
react do not recognize passed function (props) in side child function(checkBoxhandleChange).
I make a function for all of type components (checkbox, input, ....) in the parent and handle all
import React, { Component } from 'react';
import Input from "./base/input";
class Parent extends Component {
state = { data: [] }
handleChange = ({ currentTarget: input }) => {
const data = { ...this.state.data };
data[input.name] = input.value;
this.setState({ data });
console.log("handleChange", input.name, input.value);
};
render() {
const { data } = this.state
return (
<Input
label=" is active ?"
require={true}
type="textarea"
name={"reasons"}
value={data.reasons}
handleChange={this.handleChange}
/>
);
}
}
export default Parent;
child => Input.jsx
import {
Form,
Row,
Col,
} from "react-bootstrap";
import "./style.scss";
const Input = ({
name,
label,
value,
handleChange,
}) => {
function checkBoxhandleChange({ currentTarget: input }) {
console.log([input.name], input.value)
handleChange({ currentTarget: { name: input.name, value: input.checked } })
}
return (
<Row className="my-input">
<Col md={12}>
<Form.Group className="mb-3 col-md-12" controlId="formBasicCheckbox">
<Form.Check type="checkbox" label={label} name={name}
value={value}
onChange={checkBoxhandleChange} />
</Form.Group>
</Col>
</Row>
);
};
export default Input;
First of all I suggest you to remove your checkBoxHandleChange() from Input.jsx and directly call the handleChange() function from your child file using the props.
import { Form, Row, Col } from "react-bootstrap";
import "./style.scss";
const input = (props) => {
<div>
<Row className="my-input">
<Col md={12}>
<Form.Group className="mb-3 col-md-12" controlId="formBasicCheckbox">
<Form.Check type="checkbox" label={label} name={name}
value={value}
onChange={props.changedInput}/>
</Form.Group>
</Col>
</Row>
</div>
};
export default input;
You can then edit your parent file as such by modifying this line handleChange={this.handleChange} to this changedInput={this.handleChange}

Getting Data From React-Bootstrap Input

I am not finding good docs or videos on how to get data from my inputs with React-Bootstrap. I want to be able to click the button and then bring what I typed into the input box into my onClick function.
import React from "react";
import Button from 'react-bootstrap/Button';
import './Search.css';
import InputGroup from 'react-bootstrap/InputGroup';
import FormControl from 'react-bootstrap/FormControl';
class search extends React.Component {
constructor(props){
super(props);
this.text = React.createRef();
this.searchChar = this.searchChar.bind(this);
}
searchChar = () => {
console.log("Button Clicked")
const value = this.input.current.value;
console.log(value)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">Character Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl ref = {this.input}
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
/>
</InputGroup>
<Button onClick={this.searchChar(this.input)} variant="outline-danger">Search </Button>
</form>
</div>
);
}
}
export default search;
Just try to write your input values in state
for example;
import React from "react";
import Button from 'react-bootstrap/Button';
import './Search.css';
import InputGroup from 'react-bootstrap/InputGroup';
import FormControl from 'react-bootstrap/FormControl';
class search extends React.Component {
constructor(props){
super(props);
this.state = {
basicAddon1 : null,
};
}
searchChar = () => {
console.log("Button Clicked")
const value = this.state.basicAddon1;
console.log(value)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">Character Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
onChange={event => {
this.setState({
basicAddon1 : event.target.value
});
}}
value={this.state.basicAddon1 ? this.state.basicAddon1 : ""}
/>
</InputGroup>
<Button onClick={this.searchChar(this.input)} variant="outline-danger">Search </Button>
</form>
</div>
);
}
}
export default search;
you can create inputChangeHandler function or something else for improve your code
it just basic
The same way you deal with getting data from a form in pure React, you do with react-bootstrap. This answer here shows many options to do so.
My favourite approach among those options is this one. Using that approach your code would be something like:
class search extends React.Component {
constructor(props) {
super(props)
this.handleSave = this.handleSave.bind(this)
}
onChange(event) {
// Intended to run on the change of every form element
event.preventDefault()
this.setState({
[event.target.name]: event.target.value,
})
}
handleSave() {
console.log(`Do something with : {this.state.characterName}`)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">
Character Search
</InputGroup.Text>
</InputGroup.Prepend>
<FormControl
name="characterName"
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
onChange={this.onChange.bind(this)}
/>
</InputGroup>
<Button onClick={this.handleSave} variant="outline-danger">
Search{' '}
</Button>
</form>
</div>
)
}
}

My form does not accept the input value from a user

I have a login form i created with react-strap I am facing a problem with input value, the form behave as readonly for the first input of email but accept the second input of the password.
I have tried to delete the email field to trace if the password field will fail to accept input but it worked perfect
I have attached my component code, Please i will appreciate anyone who can help to solve this problem
import React, { Component } from 'react';
import { Button, Card, CardBody, Col, Container, Form, Input, InputGroup, Row } from
'reactstrap';
import './Login.css'
class Login extends Component {
constructor(props) {
super(props)
this.state = {
email:'',
password:''
}
}
changeHandler = (e) =>{
this.setState({[e.target.name]:e.target.value });
}
onSubmit = (e) =>{
e.preventDefault();
fetch('http://localhost:5000/user/login',{
method:'POST',
body:JSON.stringify(this.state),
})
.then(response =>{
if(response.status === 200){
this.props.history.push('/')
}else{
const error = new Error(response.error);
throw error;
}
})
.catch(err=>{
console.error(err);
alert('Ooops! Login failed please check your email and password, then try again')
})
}
render() {
return (
<div className="app flex-row align-items-center">
<Container className="container">
<Row className="justify-content-center">
<Col md="12" lg="10" xl="8">
<Card className="mx-4">
<CardBody className="p-4">
<Form onSubmit={this.onSubmit} className="login-form">
<h1>Login Form</h1>
<InputGroup className="mb-3">
<Input type="email "
name="email "
required="required"
placeholder="email "
value={this.state.email }
onChange={this.changeHandler}
/>
</InputGroup>
<InputGroup className="mb-3">
<Input type="password"
name="password"
required="required"
placeholder="Password"
value={this.state.password}
onChange={this.changeHandler}
/>
</InputGroup>
<Row>
<Col xs="12" sm="6">
<Button type="submit" className="btn btn-info mb-1" block><span>Login</span>
</Button>
Home
</Col>
</Row>
</Form>
</CardBody>
</Card>
</Col>
</Row>
</Container>
</div>
)
}
}
export default Login;
The issue is you have a space in your input name:
<Input type="email "
name="email "
^ remove this space
As a result of that, your change handler fails to set the state because it's setting "email " not "email".
You also have a space in your input type and placeholder.
The problem may be in changeHandler. As you pass it to a input like
onChange={this.changeHandler}
The this in
changeHandler = (e) =>{
this.setState({[e.target.name]:e.target.value });
}
refers to input and not to Class component, so it does not update the state.
To fix this the problem you should bind the Class component this to changeHandler.
constructor(props) {
super(props);
this.state = {
email:'',
password:''
}
this.changeHandler = this.changeHandler.bind(this);
}
You may also read this article.

Problem connect Redux with parent props from React

I have been trying for several days to solve a problem between connect of redux and a props of a parent component. I use redux in my child component and at the same time use props to call a handlechange function and a state of the parent component.
When in the child component use connect does not update this.props.args properly, however in the parent there is no problem. Then I have a validation so that when all the fields are complete, my submit button will be activated.
Additionally implement a state and a function in the parent component to detect the movement of the mouse and pass it to the child component, to clear some doubts, the amazing thing is that in this case if it detects changes in this.props.mouse and much more rare is that when I fill a field and then move the mouse, my this.props.args in the child component if it is updated. I'm a little disconcerted and I do not know what is due.
Parent Component:
import React, { Component } from "react";
import SignUp from './login/SignUp';
class Login extends Component {
state = {
showRegister: true,
argsSignup: {},
move: {},
}
handleChange = (ev, input) => {
let argsSignup = this.state.argsSignup;
argsSignup[input.name] = input.value;
this.setState({argsSignup});
//console.log(this.state.argsSignup);
}
handleMouseMove = (event) => {
this.setState({
move: {
x: event.clientX,
y: event.clientY
}
});
}
render() {
const {showRegister, argsSignup, move} = this.state;
return(
<div onMouseMove={this.handleMouseMove}>
{showRegister && <SignUp args={argsSignup} handleChange={this.handleChange} mouse={move} />}
</div>
);
}
}
export default (Login);
Child Component (with connect):
import React, { Component } from "react";
import { connect } from "react-redux";
import { Form, Button } from 'semantic-ui-react';
import { signInFacebook } from "../../redux/createActions";
class SignUp extends Component {
render() {
const {args, handleChange, signInFacebook} = this.props;
return(
<React.Fragment >
<Form >
<Form.Field>
<Form.Input name='email' onChange={handleChange} placeholder='numero de movil o correo electronico' />
</Form.Field>
<Form.Field>
<Form.Input name='name' onChange={handleChange} placeholder='Nombre completo'/>
</Form.Field>
<Form.Field>
<Form.Input name='username' onChange={handleChange} placeholder='Nombre de usuario' />
</Form.Field>
<Form.Field>
<Form.Input name='password' onChange={handleChange} type="password" placeholder='contraseña' />
</Form.Field>
<Button
type='submit'
disabled={!args.email || !args.username || !args.name || !args.password }
primary
fluid>
Regístrate
</Button>
</Form>
<button onClick={signInFacebook}>Inicia sesion con Facebook</button>
</React.Fragment>
)
}
}
export default connect(null, {signInFacebook})(SignUp);
On the other hand, if I delete the connect from my child component, everything works great and if it detects the changes of this.props.args
Child Component (without connect):
import React, { Component } from "react";
import { connect } from "react-redux";
import { Form, Button } from 'semantic-ui-react';
import { signInFacebook } from "../../redux/createActions";
class SignUp extends Component {
render() {
const {args, handleChange, signInFacebook} = this.props;
return(
<React.Fragment >
<Form >
<Form.Field>
<Form.Input name='email' onChange={handleChange} placeholder='numero de movil o correo electronico' />
</Form.Field>
<Form.Field>
<Form.Input name='name' onChange={handleChange} placeholder='Nombre completo'/>
</Form.Field>
<Form.Field>
<Form.Input name='username' onChange={handleChange} placeholder='Nombre de usuario' />
</Form.Field>
<Form.Field>
<Form.Input name='password' onChange={handleChange} type="password" placeholder='contraseña' />
</Form.Field>
<Button
type='submit'
disabled={!args.email || !args.username || !args.name || !args.password }
primary
fluid>
Regístrate
</Button>
</Form>
<button onClick={signInFacebook}>Inicia sesion con Facebook</button>
</React.Fragment>
)
}
}
export default (SignUp);
I appreciate your help from now on. Thank you!!
When you connect your component, you are establishing a connection with Redux and the props of that component will be fed by the entire application state.
export default connect(mapStateToProps, {signInFacebook})(SignUp);
Your first parameter for connect function holds the mapStateToProps function which essentially maps the application state to props of the SignUp component. Keeping that null means that you're expecting a null state object from Redux and hence you are unable to get the desired result in this.props.args. Removing connect statement makes the props which are passed down to the child component accessible through this.props. That's the crux of Redux.

Use Popup to display Input Error message in React-Semantic-UI

It is possible to use the Popup Component to display the Input Errors in react Semantic UI?
Something like this
<Popup
content="Error Message"
trigger={
<Input placeholder='Name' />
}
/>
I think there is a way to achieve that, but not by using the PopUp component. To achieve that see the semantic-ui-react documentation on Forms with Label (pointing).
You can use the logic illustrated in the code below:
import React, { Component } from 'react'
import { Form, Label, Input, Button } from 'semantic-ui-react'
export default class MyCustomForm extends Component {
constructor(props){
super(props)
}
this.state = {
input1: 'some value',
input2: '',
errors: {
input1: 'Input 1 error message'
}
this.onChange = this.onChange.bind(this)
this.validate = this.validate.bind(this)
this.onSubmit = this.onSubmit.bind(this)
}
onChange(e, {name, value}){
const state = this.state
const { errors } = state
if(errors[name]){
delete errors[name]
}
this.setState(Object.assign({},...state,{[name]: value, errors }))
this.validate(name, value)
}
validate(name, value){
{/*
THIS SHOULD VALIDATE THE INPUT WITH THE APPROPRIATE NAME ATTRIBUTE
AND UPDATE THE ERRORS ATTRIBUTE OF THE STATE
*/}
}
onSubmit(e){
e.preventDefault()
{/* CLEAR THE ERRORS OF THE STATE, SUBMIT FORM TO BACKEND, THENj RESET ERRORS IF ANY */}
}
render() {
<Form size='small' key='mycustomform'>
<Form.Group>
<Form.Field error={errors.input1} required>
<label>Input1</label>
<Input name='input1' onChange={this.onChange}/>
{errors.input1 && <Label pointing color='red'>{errors.input1}</Label>}
</Form.Field>
</Form.Group>
<Form.Group>
<Form.Field error={errors.input2}>
<label>Input2</label>
<Input name='input2' onChange={this.onChange}/>
{errors.input2 && <Label pointing color='red'>{errors.input2}</Label>}
</Form.Field>
</Form.Group>
<Form.Field control={Button} onSubmit={this.onSubmit}/>
</Form>
}

Resources