I am new to Redux. I've learned React and trying to learn Redux. I am building a todo app with Redux. I am managed to create, read and delete todos, but I am not managed to edit the todo.
My code: AddTodoForm
<FormGroup>
<Label for="title">Title</Label>
<Input type="text" name="title" id="title" placeholder="Enter Title" onChange={this.handleChange.bind(this)} /> {/* <input type="text" value={this.state.value} onChange={this.handleChange.bind(this, 'title')} /> */}
</FormGroup>
<FormGroup>
<Label for="description">Description </Label>
<Input type="textarea" name="description" id="description" onChange={this.handleChange.bind(this)} />
</FormGroup>
<FormGroup>
<div>
<CustomInput className="toggleInput" type="checkbox" data-toggle="toggle" id="exampleCustomCheckbox" label="Do You want to add Reminder??" onChange={this.toggle.bind(this, !this.state.checkBoxToggle)} />
</div>
</FormGroup>
{this.state.checkBoxToggle ?
<FormGroup>
<Label for="reminder">Reminder </Label>
<Input type="datetime-local" name="date" defaultValue={moment(Date.now()).format( 'YYYY-MM-DDTHH:mm')} id="date" onChange={this.handleChange.bind(this)} />
</FormGroup>
: ''}
<FormGroup check row>
<Col className="text-center">
<Button className="btn btn-success" onClick={this.handleSubmit.bind(this)}>Submit</Button>
</Col>
</FormGroup>
My handleChange function, where I set states of input:
handleChange(e) {
console.log(e.target.value, e.target.name);
if (e.target.name == "date") {
console.log('date is', e.target.value, new Date(e.target.value).valueOf());
this.setState({
[e.target.name]: new Date(e.target.value).valueOf()
})
} else {
this.setState({
[e.target.name]: e.target.value
})
}
}
This the render list function, where I want to edit my todo, but I am not able to edit the todo. I am able to delete, but not edit:
renderList() {
if (this.props.todos) {
return _.map(this.props.todos, (todo, id) => {
return (
<tr key={id + 1}>
<th scope="row">{id + 1}</th>
<td><Input type="text" disabled name="title" id="title" value={todo.title} onChange={this.handleChange.bind(this)} /></td>
<td><Input type="textarea" value={todo.description ? todo.description : this.state.description} name="description" id="description" onChange={this.handleChange.bind(this)} /></td>
<td>{todo.reminder}</td>
<td> <button className='btn btn-danger' onClick={this.onDeleteClick.bind(this, todo._id)}>Delete</button></td>
<td><button className='btn btn-success' onClick={this.markCompleted.bind(this, todo._id)}>Mark Complete</button></td>
</tr>
);
})
}
}
The specific todo, which I want to edit doesn't allow to type any value in the input box. I am not able to set it. Please let me know where I am doing wrong.
Don't reinvent the wheel. Instead of trying to reimplement form state, with event handlers, slice and reducers, use Redux Form.
It is made for that specific purpose and has an elegant, efficient API.
Related
I try to handle the user's text input with hooks.
const [inputValues, setInputValues] = useState({
firstName:"",
lastName:"",
email:"",
telNum:"",
contactType:"Tel.",
message:"",
agree:false
});
and I try to update the values by
const handleChange = event => {
setInputValues({ ...inputValues, [event.target.name]: event.target.value,});
}
and the event:
onChange={handleChange}
Sample input Field code:
<FormGroup row>
<Label htmlFor='firstname' md={2}>
First Name
</Label>
<Col md={10}>
<Input
type='text'
id='firstname'
name='firstname'
placeholder='First Name'
value={firstName}
valid={errors.firstName === ""}
invalid={errors.firstName !== ""}
onBlur={handleBlur("firstName")}
onChange={handleChange} />
<FormFeedback>{errors.firstName}</FormFeedback>
</Col>
</FormGroup>
But whenever I typed something in the input field. I Can't find the value that I entered un the input field.
I didn't understand what happened here. Please Help me to get out from this
There is a typo error in your code. name property is firstName not firstname.
<FormGroup row>
<Label htmlFor='firstname' md={2}>
First Name
</Label>
<Col md={10}>
<Input
type='text'
id='firstname'
name='firstName'
placeholder='First Name'
value={inputValues.firstName}
valid={errors.firstName === ""}
invalid={errors.firstName !== ""}
onBlur={handleBlur("firstName")}
onChange={handleChange} />
<FormFeedback>{errors.firstName}</FormFeedback>
</Col>
</FormGroup>
replace value to value={inputValues. firstName}
I'm trying to take the inputs using a form and update the state when the checkbox is clicked but for some reason, the state doesn't update. It doesn't throw any error. I searched on google for answers but none of them were plausible.
My code:
class PatientForm extends React.Component{
constructor(){
super();
this.state={
patientName: "",
age: null,
sex: "",
email: "",
phoneNo: null
}
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit = (event) => {
console.log(this.state);
const target = event.target;
const value = target.type === "checkbox" ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
alert(this.state.patientName);
console.log(this.state);
}
render(){
return (
<div className="container-fluid">
<Jumbotron>
<h3 className="display-5">Enter Patient info</h3>
<Form>
<Form.Text className="text-muted">
We'll never share your details with anyone else.
</Form.Text>
<Form.Row>
<Col>
<Form.Control name="patientName" type="text" placeholder="Patient name" required/>
</Col>
<Col>
<Form.Control name="age" type="number" placeholder="Patient Age" required/>
</Col>
<Col>
<Form.Control name="sex" type="text" placeholder="Patient Sex" required/>
</Col>
</Form.Row>
<br />
<Form.Group>
<Form.Control name="email" type="email" placeholder="Enter email" required/>
</Form.Group>
<Form.Group>
<Form.Control name="phoneNo" type="number" placeholder="Phone number" required/>
</Form.Group>
<Form.File />
<Form.Label>Patient's Eth Address</Form.Label>
<Form.Text className="text-muted">
################
</Form.Text>
<Form.Group >
<Form.Check
type="checkbox"
label="Tick if the entered info is correct"
onClick = {this.handleSubmit}
/>
</Form.Group>
<Button variant="primary" type="submit" onClick={ () => console.log(this.state)}>
Submit
</Button>
</Form>
<p>{this.state.patientName}</p>
</Jumbotron>
</div>
)
}
}
export default PatientForm;
Here the handleSubmit function is revoked when the checkbox is clicked.
You need to attach the handleSubmit function to onChange event of every <Form.Control /> you want to use to update the state properties.
Read the "Handling Multiple Inputs" documentation page for more insights.
Here is how you should write you <PatientForm /> (I renamed handleSubmit to handleChange and provide new implementation of handleSumbit):
class PatientForm extends React.Component {
constructor() {
super();
this.state = {
patientName: "",
age: null,
sex: "",
email: "",
phoneNo: null
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const target = event.target;
const value = target.type === "checkbox" ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSubmit(event) {
// e.g.: send to remote API
event.preventDefault();
console.log("state", this.state);
console.log("data sent to remote API");
}
render() {
return (
<div className="container-fluid">
<Jumbotron>
<h3 className="display-5">Enter Patient info</h3>
<Form>
<Form.Text className="text-muted">
We'll never share your details with anyone else.
</Form.Text>
<Form.Row>
<Col>
<Form.Control
name="patientName"
type="text"
placeholder="Patient name"
onChange={this.handleChange}
required
/>
</Col>
<Col>
<Form.Control
name="age"
type="number"
placeholder="Patient Age"
onChange={this.handleChange}
required
/>
</Col>
<Col>
<Form.Control
name="sex"
type="text"
placeholder="Patient Sex"
onChange={this.handleChange}
required
/>
</Col>
</Form.Row>
<br />
<Form.Group>
<Form.Control
name="email"
type="email"
placeholder="Enter email"
onChange={this.handleChange}
required
/>
</Form.Group>
<Form.Group>
<Form.Control
name="phoneNo"
type="number"
placeholder="Phone number"
onChange={this.handleChange}
required
/>
</Form.Group>
<Form.File />
<Form.Label>Patient's Eth Address</Form.Label>
<Form.Text className="text-muted">################</Form.Text>
<Form.Group>
<Form.Check
type="checkbox"
label="Tick if the entered info is correct"
/>
</Form.Group>
<Button variant="primary" type="submit" onClick={this.handleSubmit}>
Submit
</Button>
</Form>
<p>{this.state.patientName}</p>
</Jumbotron>
</div>
);
}
}
I'm working on a form to create a new product and I need a row with 3 equals fields but I'm not getting there using React Semantic Ui.
How can I code 3 equal input fields using react semantic ui?
That's what I've tried:
import { Form, Input, Button, TextArea, Header, Icon } from "semantic-ui-react";
function CreateProduct() {
return (
<>
<Header as="h2" block>
<Icon name="add square" color="violet" />
Cadastrar Produto
</Header>
<Form>
<Form.Group widths="equal">
<Form.Field
control={Input}
name="name"
label="Nome"
placeholder="Nome do Produto"
/>
<Form.Field
control={Input}
name="price"
label="Preço"
placeholder="Preço"
min="0.00"
step="0.10"
type="number"
/>
<Form.Field
control={Input}
name="media"
type="file"
label="Imagem"
accept="image/*"
content="Escolha Imagem"
/>
</Form.Group>
<Form.Field
control={TextArea}
name="description"
label="Descrição"
placeholder="Descrição do Produto"
/>
<Form.Field
control={Button}
inverted
color="violet"
icon="pencil alternate"
content="Cadastrar"
type="submit"
/>
</Form>
</>
);
}
export default CreateProduct;
The output that I am getting is:
See the 3rd input "Imagem"?
It seems that the field is not following the Form.Group props widths='equal' from semanctic-react-ui document
This layout is exceed because of the file type content.
May be you can try this way to get that layout
import React, { Component } from "react";
import { Form, Input, Button, TextArea } from "semantic-ui-react";
class FormExample extends Component {
fileInputRef = React.createRef();
render() {
return (
<Form>
<Form.Group widths="equal">
<Form.Field
control={Input}
name="name"
label="Nome"
placeholder="Nome do Produto"
/>
<Form.Field
control={Input}
name="price"
label="Preço"
placeholder="Preço"
min="0.00"
step="0.10"
type="number"
/>
<Form.Field>
<label>Imagem</label>
<Button
style={{ width: "100%" }}
content="Choose File"
labelPosition="left"
icon="file"
onClick={() => this.fileInputRef.current.click()}
/>
<input
ref={this.fileInputRef}
type="file"
hidden
onChange={this.fileChange}
/>
</Form.Field>
</Form.Group>
<Form.Field
control={TextArea}
name="description"
label="Descrição"
placeholder="Descrição do Produto"
/>
<Form.Field
control={Button}
inverted
color="violet"
icon="pencil alternate"
content="Cadastrar"
type="submit"
/>
</Form>
);
}
}
export default FormExample;
demo : https://codesandbox.io/s/zen-frost-9ihqw (adjust the screen size for full view)
I found a good solution just adding the "Fluid" props on the second .
<Form.Field
fluid
control={Input}
name="price"
label="Preço"
placeholder="Preço"
min="0.00"
step="0.10"
type="number"
/>
I am newbie to redux .I'm trying to create an application using redux-form. Could you please help me how to trigger an action when any changes happen in any of the field in the form .
import React from 'react'
import { Field, reduxForm } from 'redux-form'
import { Col, Button, Form, FormGroup, Label, Input, FormText } from 'reactstrap';
const renderField=({ input, label,name, type, meta})=>(
<FormGroup row>
<Label for={name} sm={2}>{label}</Label>
<Col sm={10}>
<input {...input} placeholder={label} type={type}></input>
</Col>
</FormGroup>
)
const BreakupForm=(props)=>{
console.log(props);
const { handleSubmit, pristine, reset, submitting } = props
return(
<div>
<Label >Breakup</Label>
<form onSubmit={handleSubmit}>
<Field label="Basic" name="basic" component={renderField} type="text" placeholder="basic"/>
<Field label="HRA" name="hra" component={renderField} type="text" placeholder="HRA"/>
<Field label="Transport Allowance" name="ta" component={renderField} type="text" placeholder="Transport Allowance" />
<Field label="Special Allowance" name="specialAllowance" component={renderField} type="text" placeholder="Special Allowance" />
<Field label="LTA" name="lta" component={renderField} type="text" placeholder="LTA"/>
<Field label="Medical Bills" name="medicalBills" component={renderField} type="text" placeholder="Medical Bills"/>
</form>
</div>
)
}
export default reduxForm({
form: 'breakupForm' // a unique identifier for this form
})(BreakupForm)
You can use onChange on every field you want to observe, for instance:
<Field label="Basic" name="basic" component={renderField} type="text" placeholder="basic" onChange={onChangeHandler} />
and then write your onChangeHandler which will be called with the following parameters:
event, newValue, previousValue, name
For instance, looking at your code, you can listen to field basic changes like this:
const BreakupForm = (props) => {
const onBasicFieldChange = (event, newValue, previousValue, name) => {
console.log(newValue)
}
console.log(props);
const { handleSubmit, pristine, reset, submitting } = props
return (
<div>
<Label >Breakup</Label>
<form onSubmit={handleSubmit}>
<Field onChange={onBasicFieldChange} label="Basic" name="basic" component={renderField} type="text" placeholder="basic" />
<Field label="HRA" name="hra" component={renderField} type="text" placeholder="HRA" />
<Field label="Transport Allowance" name="ta" component={renderField} type="text" placeholder="Transport Allowance" />
<Field label="Special Allowance" name="specialAllowance" component={renderField} type="text" placeholder="Special Allowance" />
<Field label="LTA" name="lta" component={renderField} type="text" placeholder="LTA" />
<Field label="Medical Bills" name="medicalBills" component={renderField} type="text" placeholder="Medical Bills" />
</form>
</div>
)
}
Well, according to Redux Form documentation, Redux Form onChange callback
Field component accepts a prop (onChange), you can pass a function to the onChange props.
<Field label="Basic" onChange={this.handleChange} name="basic" component={renderField} type="text" placeholder="basic"/>
handleChange will be a function defined in your class.
Since your component is stateless component, you can passs the callback function through props
<Field label="Basic" onChange={props.handleChange} name="basic" component={renderField} type="text" placeholder="basic"/>
I am trying to populate a form with initial data however I am unsure of the syntax for this functionality and how it's suppose to be applied. initially the form I am using is a component that I also use to create a client. I am trying to reuse this form as the form for editing a client. It has two functions.
As per suggestions in Redux I have a this as a component and I also have a container.
Now, using the redux tool in Chrome I can look at the state and its clear the action has added an "editClient" entry with data so I do have the data. Its called "editClient" in the state.
My problem is that I do not know how to use this to set these state values as initial values. I have looked carefully at the docs but I am confused as to the way it should be stuctured.
Here is my client form in its entirety:
import React, { PropTypes } from 'react'
import { Field, reduxForm, FormSection } from 'redux-form'
import { connect } from 'react-redux'
import { Col, Row } from 'react-bootstrap'
import { Button, Glyphicon, Panel } from 'react-bootstrap'
import Moment from 'moment'
import Address from '../../address/addressContainer'
import FormField from '../../formComponents/formField'
import CheckboxField from '../../formComponents/checkboxField'
import TextField from '../../formComponents/textField'
import StaticText from '../../formComponents/staticText'
import TextAreaField from '../../formComponents/textAreaField'
import DateField from '../../formComponents/datefield'
import reducer from '../edit/reducer'
export const CLIENT_FORM_NAME = 'Client'
const required = value => (value ? undefined : 'Required')
const maxLength = max => value =>
value && value.length > max ? `Must be ${max} characters or less` : undefined
const number = value =>
value && isNaN(Number(value)) ? 'Must be a number' : undefined
const minValue = min => value =>
value && value < min ? `Must be at least ${min}` : undefined
const email = value =>
value && !/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)
? 'Invalid email address'
: undefined
const tooOld = value =>
value && value > 65 ? 'You might be too old for this' : undefined
const aol = value =>
value && /.+#aol\.com/.test(value)
? 'Really? You still use AOL for your email?'
: undefined
const normalizeMobilePhone = value => {
if (!value) {
return value
}
const onlyNums = value.replace(/[^\d]/g, '')
if (onlyNums.length <= 4) {
return onlyNums
}
if (onlyNums.length <= 8) {
return `${onlyNums.slice(0, 4)} ${onlyNums.slice(4)}`
}
return `${onlyNums.slice(0, 4)} ${onlyNums.slice(4, 7)} ${onlyNums.slice(7, 10)}`
}
export const Client = (props) => {
const {
handleSubmit,
companyValue,
isWarrantyCompanyValue,
isEditMode } = props
const { reset } = props
return (
<Row>
<Col md={12}>
<h2><Glyphicon glyph="edit" /> {isEditMode ? 'Edit' : 'New'} Client</h2>
<hr />
<form onSubmit={handleSubmit} className="form-horizontal">
{isEditMode && (
<Panel header={<h3>Client - Basic Details</h3>}>
<Row>
<Field component={StaticText}
name="clientNo"
id="clientNo"
label="Client No."
fieldCols={4}
labelCols={4}
controlCols={8}
/>
<Field component={StaticText}
name="dateCreated"
id="dateCreated"
label="Date Created."
fieldCols={4}
labelCols={4}
controlCols={8}
/>
<Field component={StaticText}
name="userName"
id="userName"
label="Created By."
fieldCols={4}
labelCols={4}
controlCols={8}
/>
</Row>
<Row>
<Field
component={props => {
return (
<StaticText {...props}>
<p
className="form-control-static"
>
<Glyphicon glyph={props.input.value ? 'ok' : 'remove'} />
{' '}{props.input.value ? 'Has jobs attached' : 'No jobs attached'}
</p>
</StaticText>
)
}}
name="activity"
id="activity"
label="Activity"
fieldCols={4}
labelCols={4}
controlCols={8}
/>
<Field component={CheckboxField}
name="active"
id="active"
label="De-Activate"
checkboxLabel="De activate this client"
fieldCols={4}
labelCols={4}
controlCols={8}
/>
</Row>
</Panel>
)}
<Panel header={<h3>Client - CompanyDetails</h3>}>
<Row>
<Field component={CheckboxField}
id="company"
name="company"
label="Company?"
checkboxLabel="Client represents a company"
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
{companyValue && (
<div>
<Row>
<Field component={TextField}
name="companyName"
id="companyName"
type="text"
label="Company Name"
placeholder="Enter company name..."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
<Field component={TextField}
name="abn"
id="abn"
type="text"
label="ABN."
fieldCols={6}
labelCols={3}
controlCols={5}
/>
</Row>
<Row>
<Field component={CheckboxField}
id="isWarrantyCompany"
name="isWarrantyCompany"
label="Warranty Company?"
checkboxLabel="Client represents a warranty company"
fieldCols={6}
labelCols={3}
controlCols={9}
/>
{isWarrantyCompanyValue && (
<Field component={CheckboxField}
id="requiresPartsPayment"
name="requiresPartsPayment"
label="Requires Parts Payment?"
checkboxLabel="We pay for parts"
fieldCols={6}
labelCols={3}
controlCols={9}
/>
)}
</Row>
<Row>
<Field component={TextField}
name="companyEmail"
id="companyEmail"
type="email"
label="Spare Parts Email."
placeholder="Enter spare parts email..."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
</div>
)}
</Panel>
<Panel header={<h3>Client - {companyValue ? 'Company Contact' : 'Personal'} Details</h3>}>
<Row>
<Field component={TextField}
name="clientFirstName"
id="clientFirstName"
type="text"
label="First Name."
placeholder="Enter first name..."
fieldCols={6}
labelCols={3}
controlCols={9}
validate={[required]}
/>
<Field component={TextField}
name="clientLastName"
id="clientLastName"
type="text"
label="Last Name."
placeholder="Enter last name..."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
<Row>
<Field component={TextField}
name="mobilePhone"
id="mobilePhone"
type="text"
label="Mobile No."
placeholder="Enter mobile No..."
fieldCols={6}
labelCols={3}
controlCols={5}
normalize={normalizeMobilePhone}
/>
<Field component={TextField}
name="phone"
id="phone"
type="text"
label="Phone No."
placeholder="Enter phone No..."
fieldCols={6}
labelCols={3}
controlCols={5}
/>
</Row>
<Row>
<Field component={TextField}
name="email"
id="email"
type="email"
label="Email."
placeholder="Enter email address..."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
</Panel>
<FormSection name="Address">
<Address />
</FormSection>
<Panel header={<h3>Notes</h3>}>
<Row>
<Field component={TextAreaField}
id="notes"
name="notes"
label="Notes."
placeholder="Enter notes here..."
fieldCols={12}
labelCols={1}
controlCols={11}
/>
</Row>
</Panel>
<Panel header={<h3>Client - Bank Details</h3>}>
<Row>
<Field component={TextField}
name="bankName"
id="bankName"
type="text"
label="Bank Name."
placeholder="Enter bank name..."
fieldCols={4}
labelCols={4}
controlCols={8}
/>
<Field component={TextField}
name="bsb"
id="bsb"
type="text"
label="BSB No."
placeholder="Enter BSB No..."
fieldCols={4}
labelCols={4}
controlCols={8}
/>
<Field component={TextField}
name="account"
id="account"
type="text"
label="Account No."
placeholder="Enter Account No..."
fieldCols={4}
labelCols={4}
controlCols={8}
/>
</Row>
</Panel>
<div className="panel-body">
<Row>
<Col xs={4}>
<Row>
<Col xs={8} xsOffset={4}>
<Button bsStyle="primary" type="submit" bsSize="small">
<Glyphicon glyph="ok" /> Submit
</Button>
{' '}
<Button type="reset" bsSize="small" onClick={reset}>
<Glyphicon glyph="ban-circle" /> Clear
</Button>
</Col>
</Row>
</Col>
</Row>
</div>
</form>
</Col>
</Row >
)
}
let ClientForm = reduxForm({
form: CLIENT_FORM_NAME,
})(Client)
ClientForm = connect(
state => ({
initialValues: state.editClient // pull initial values from client reducer
}),
{ reducer } // bind client loading action creator
)(Client)
export default ClientForm
I have added the following at the bottom as per the redux form example:
ClientForm = connect(
state => ({
initialValues: state.editClient // pull initial values from client reducer
}),
{ reducer } // bind client loading action creator
)(Client)
...wnd when I save it I get the following error.
Exception: Call to Node module failed with error: Error: Field must be inside a component decorated with reduxForm()
I believe I have not understood how to set the initial values.
Where have I gone wrong and what I need to do to make this take the state values and load them?
The parameter for the function that connect returns should be ClientForm instead of Client. Try this:
ClientForm = connect(
state => ({
initialValues: state.editClient // pull initial values from client reducer
}),
{ reducer } // bind client loading action creator
)(ClientForm)