Use different value of input field than it is showing in React Form - reactjs

I have a form in react, and I want the input field to show "No Limit" as default value if no other value specified, or the customer input otherwise. but If no value specified, I need the value to be -1 (for other part of the code).
My code right now lokks like this:
import { Field, Form } from "react-final-form";
const RecordingForm = (props: Props) => {
const onSubmit = (values: any) => {
//some code here...
};
return (
<div>
<Form
onSubmit={onSubmit}
initialValues={{ totaltime_maximum: -1,}}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit}>
<Field name="totaltime_maximum">
{({ input, meta }) => (
<div>
<label>Maximum duration (seconds):</label>
<input {...input} type="number" placeholder="No Limit" />
{meta.error && meta.touched && <span>{meta.error}</span>}
</div>
)}
</Field>
</form>
)}
/>
</div>
);
};
export default RecordingForm;
But, the result of this code is this input box:
And I want it to look like this:
and the value (to my using in the code) to be -1.
how can I do that?

Related

How to set state for text box in functional component

I am working on React JS. I have one text-box component and I want to show some default value in it. After that, the user should be allowed to change the value. Now I am unable to change the value. The text box is behaving like read-only. Below is my code
const EditStyleFormComponent = ({
submitting,
invalid,
}) => (
<form className={className} onSubmit={handleSubmit}>
<h2>LSPL (Low Stock Presentation Level)</h2>
<Line />
<InputGroup>
<TextFieldWithValidation name="lsplMan" label="LSPL Manual" input={{ onChnage:'', value: 'Current' }} />
</InputGroup>
</form>
);
Below is my TextFieldWithValidation code.
export const TextFieldWithValidationComponent = ({
meta,
input,
noStyles,
...otherProps
}) => (
<TextField
state={noStyles ? textFieldStates.DEFAULT : getState(meta)}
errorMessage={meta.touched ? meta.error : null}
{...input}
{...otherProps}
/>
);
Below is my TextField code.
const TextField = ({
className,
label,
description,
state,
errorMessage,
isEditable,
spaceAtBottom, // Not used, but we don't want it in otherProps
...otherProps
}) => {
const inputId = _.uniqueId();
return (
<div className={className}>
{label &&
<label htmlFor={inputId}>{label}</label>
}
<div className="input-group" id={isEditable ? 'editable' : 'readonly'}>
<input
id={inputId}
readOnly={!isEditable}
{...otherProps}
/>
{getStatusIcon(state)}
{errorMessage &&
<Error>{errorMessage}</Error>
}
{description &&
<Description>{description}</Description>
}
</div>
</div>
);
};
Can someone help me to fix this issue? Any help would be appreciated. Thanks
You can use State Hook for manage state in functional component.
Example :
const Message = () => {
const [message, setMessage] = useState( '' );
return (
<div>
<input
type="text"
value={message}
placeholder="Enter a message"
onChange={e => setMessage(e.target.value)}
/>
<p>
<strong>{message}</strong>
</p>
</div>
);
};
Yu defined onChange as empty string in EditStyleFormComponent component. So on any change input component just do nothing.
onChange should be some function that will update value.
If you want to use functional components there are two possible solutions:
Lift state up to parent component of EditStyleFormComponent (in case parent is class based component)
Use React Hooks like so (just example!)
const EditStyleFormComponent = ({
submitting,
invalid,
}) => {
const [inputValue, setInputValue] = useState ('Current'); // default value goes here
return <form className={className} onSubmit={handleSubmit}>
<h2>LSPL (Low Stock Presentation Level)</h2>
<Line />
<InputGroup>
<TextFieldWithValidation name="lsplMan" label="LSPL Manual" input={{ onChnage: (e) => { setInputValue(e.target.value); }, value: inputValue }} />
</InputGroup>
</form>
};

Creating a Dynamic on Demand Input field

I am new to React and doing a personal project to help with some organization in my life.
I have a field where I need to be able to add multiple names some times. I think I am close...I can't get the fields to appear but they act like they are all the same field, like they are bound together
Here is what I am getting
NameInput.jsx (component)
import React, { useState } from "react";
import { Form, Label } from "semantic-ui-react";
const NameInput = ({
input,
width,
type,
placeholder,
meta: { touched, error }
}) => {
let [inputs, setInputs] = useState([""]);
return (
<div className="nameField">
<Form.Field error={touched && !!error} width={width}>
{inputs.map((value, i) => (
<div>
<label>Name {i + 1}</label>
<input {...input} placeholder={placeholder} type={type} />{" "}
{touched && error && (
<Label basic color="red">
{error}
</Label>
)}
{e =>
setInputs(
inputs.map((value, j) => {
if (i === j) value = e.target.value;
return value;
})
)
}
</div>
))}
</Form.Field>
<button
className="ui compact button"
onClick={() => setInputs(inputs.concat(""))}
>
Add Additional Seller
</button>
</div>
);
};
export default NameInput;
And this is how I call the component. This stores to my firebase as nameField
<label>Name Field</label>
<Field
name="nameField"
type="text"
component={NameInput}
placeholder="Enter Full Name"
/>
Ideally, I'd want it to save has nameField, namefield2, nameField3 but I believe I can get that part solved on my own if I could just get my component to play nice.
Haven't you ever get a warning that a key should be provided for list items?
You should assign a unique key for each input div.

How to add react-phone-number-input to -react-final-form?

I'm currently creating a form using react-final-form and trying to use react-phone-number-input with it through integration as an adapter, as displayed through this example.
I attempted to use the example to learn how it is done, but I'm not sure how to access the component and create the adapter for it properly.
import React from 'react';
import { Form, Field } from 'react-final-form';
import PhoneInput from 'react-phone-number-input';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const onSubmit = async values => {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
const PhoneAdapter = ({ input, meta, ...rest }) => (
<PhoneInput
{...input}
{...rest}
value={input.value}
onChange={(event, value) => input.onChange(value)}
/>
)
class ContactForm extends React.Component {
render() {
return (
<>
<Form
onSubmit={onSubmit}
initialValues={{ }}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit}>
<fieldset>
<Field component={PhoneAdapter} />
</fieldset>
<fieldset>
<button type="submit" disabled={submitting || pristine}>
Submit
</button>
</fieldset>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
</>
);
}
}
export default ContactForm;
Update: July 2019
Apparently, all you need to do is to spread the input property of Field. Works flawlessly. Learn about spreading if you're not familiar with it.
const PhoneAdapter = ({ input }) => (
<PhoneInput {...input} />
)
<Field name="phone" placeholder="Enter phone number" component={PhoneAdapter} />
I ended up experimenting with the FieldRenderProps props until it worked out. I wasn't so sure whether it would work or not, as react-phone-number-input is two elements in a component. I thought it would implement the input on only one of the elements.
By using input, I gain access to the input's props. Hence, I called upon it's value, as the default looks like so:
<PhoneInput
placeholder="Enter phone number"
value={ this.state.value } // This is what I called.
onChange={ value => this.setState({ value }) }/>
I then did the same for the onChange function prop.
const PhoneAdapter = ({ input }) => (
<PhoneInput value={input.value.value} onChange={value => input.onChange(value)} />
)
Finally, I used the component adapter like so:
<Field name="phone" placeholder="Enter phone number" component={PhoneAdapter} />

Programatically changing a FieldArray value in Redux-Form

I'm trying to figure out how to use this.props.dispatch(change) in order use one field selector value to update another fields value within a FieldArray.
https://codesandbox.io/s/2p7k7jn930
I can't seem to get the syntax in this correct.
this.props.dispatch(
change("FieldArraysForm", `${props.member}.firstName`, this.props.hasLastName)
);
Any thoughts? Expected behavior would be to add a member and then have anything typed into the Last Name field be programmatically updated in the First Name field.
/**
The following can replace the file in the Field Arrays example
(https://github.com/erikras/redux-form/tree/master/examples/fieldArrays) to demonstrate this functionality.
**/
import React from "react";
import { connect } from "react-redux";
import {
Field,
FieldArray,
reduxForm,
formValueSelector,
change
} from "redux-form";
import validate from "./validate";
const selector = formValueSelector("fieldArrays");
const renderField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<label>{label}</label>
<div>
<input {...input} type={type} placeholder={label} />
{touched && error && <span>{error}</span>}
</div>
</div>
);
class Member extends React.Component {
componentDidUpdate(prevProps, props) {
if (this.props.hasLastName !== prevProps.hasLastName) {
this.props.dispatch(
change("FieldArraysForm", `${props.member}.firstName`, this.props.hasLastName)
);
}
}
render() {
const { member, index, fields, hasLastName } = this.props;
return (
<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"
/>
{hasLastName && <p>{hasLastName}</p>}
</li>
);
}
}
Member = connect((state, props) => ({
hasLastName: selector(state, `${props.member}.lastName`)
}))(Member);
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) => (
<Member member={member} fields={fields} index={index} key={index} />
))}
</ul>
);
const FieldArraysForm = props => {
const { handleSubmit, pristine, reset, submitting } = props;
return (
<form onSubmit={handleSubmit}>
<Field
name="clubName"
type="text"
component={renderField}
label="Club Name"
/>
<FieldArray name="members" component={renderMembers} />
<div>
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
);
};
export default reduxForm({
form: "fieldArrays", // a unique identifier for this form
validate
})(FieldArraysForm);
In order to access the FieldArray dynamically, you would want to change this:
change("FieldArraysForm", `${props.member}.firstName`, this.props.hasLastName)
to this:
change("FieldArraysForm", `members[${this.props.index}].firstName`, this.props.hasLastName)
Also, pass in the form selector specified:
const selector = formValueSelector("fieldArrays");
This would give you:
change("fieldArrays", `members[${this.props.index}].firstName`, this.props.hasLastName)
Had to get some help on this one - thanks goes to #Amanda Field.
You need to specify the index of the field in FieldArray you want to change. To do so, just use <fieldName>.<index>.<propertyName>, for instance:
this.props.change('members.0.firstName', 'Donald')
where member is the name of your FieldArray field, 0 is the index of the item in the array you want to change and firstName is the property of the object.
See sandbox here

Control the Redux-form with the button

I am using the Redux-form to do a task.
This form in a form container.
In the form container or in the form component.
There are two buttons. An add button and a subtract button.
The form component is:
import React from 'react'
import { Field, reduxForm } from 'redux-form'
import TextField from 'material-ui/TextField'
import RaisedButton from 'material-ui/RaisedButton'
const renderTextField = ({ input, label, meta: { touched, error }, ...custom }) => (
<TextField hintText={label}
floatingLabelText={label}
errorText={touched && error}
{...input}
{...custom}
/>
)
const ActivityDetailForm = props => {
const { handleSubmit, pristine, reset, submitting,} = props
return (
<form onSubmit={handleSubmit}>
<div>
<RaisedButton
type="submit"
disabled={pristine || submitting}
label="saveChange"
fullWidth={true}
secondary={true}
/>
</div>
</form>
)
}
export default reduxForm({
form: 'ActivityDetailForm', // a unique identifier for this form
})(ActivityDetailForm)
Now, I face a problem. When I click the add button,
<div>
<Field name="field1" component={renderTextField} label="text1: "/>
</div>
the code above will be created in the form element.
When I click the add button again, the div element which includes the Field named field2 will be created in the form element.
... Field named field3
... Field named field4
... Field named field5
...
When I click the subtract button. The last Field element will be destroyed.
Do you know the method to solve this problem?
The following (untested) is a pretty basic example on how to achieve dynamic inputs with a FieldArray. You'd have to tweak this a bit to tailor it to your specific scenario.
const renderTextField = ({ input, label, meta: { touched, error }, ...custom }) => (
<TextField hintText={label}
floatingLabelText={label}
errorText={touched && error}
{...input}
{...custom}
/>
)
const ActivityDetailForm = props => {
const { handleSubmit, pristine, reset, submitting,} = props
const renderFieldArray = ({ fields }) => (
<div>
<div>
<RaisedButton
onTouchTap={() => fields.push({})}
label="Add"
/>
</div>
{fields.map((field, index) => (
<div>
<div key={index}>
<Field
name={`${field}.name`}
label={`Text ${index + 1}`}
component={renderTextField}
/>
</div>
<div>
<RaisedButton
onTouchTap={() => fields.remove(index)}
label="Remove"
/>
</div>
</div>
))}
</div>
);
return (
<form onSubmit={handleSubmit}>
<div>
<FieldArray
name="textFields"
component={renderFieldArray}
/>
<RaisedButton
type="submit"
disabled={pristine || submitting}
label="saveChange"
fullWidth={true}
secondary={true}
/>
</div>
</form>
)
}
export default reduxForm({
form: 'ActivityDetailForm', // a unique identifier for this form
})(ActivityDetailForm)

Resources