Focus kickout on custom redux form input - reactjs

I got this redux form input :
<Field
component={MyCustomComponent}
name={name}
type={type}
/>
Using this custom element (bootstrap) :
<FormGroup controlId='login'>
<FormControl name={name} placeholder={name} value={props.value} onChange={input.onChange} {...props} />
</FormGroup>
And I use it like so :
<Input type='text' name='email' placeholder='Email' {...email} />
<Input type='password' name='password' placeholder='Password' {...password} />
Something strange happens. When I select the input and I try to write something inside, I am automatically kicked out of the input (focus).
When I try to write it again, everything works.
It's only when I select it for the first time after that the page is loaded.
Full form :
<Form onSubmit={handleSubmit(this.onLogin)}>
<div>
<Input type='text' name='email' placeholder='Email' {...email} />
<Input type='password' name='password' placeholder='Password' {...password} />
</div>
<Button type='submit' bsStyle='primary' bsSize='large' active>
<FormattedMessage
id='login.select-label'
defaultMessage='Login'
/>
</Button>
</Form>
Full input :
export const Input = (props) => {
const { name, type } = props
const MyCustomComponent = ({input}: props) => (
<FormGroup controlId='login'>
<FormControl name={name} placeholder={name} value={props.value} onChange={input.onChange} {...props} />
</FormGroup>
)
return (
<Field
component={MyCustomComponent}
name={name}
type={type}
/>
)
}

Related

Validating radio button with React Hook Form

I have a custom radio button component in React looking like this:
export default function SingleSelectionButton(props) {
const {
values, name, required, errors, defaultData,
xs, md, register, infoBox, infoBoxContent, validateField } = props;
return (
<>
<Form.Group>
<Form.Label>
<FormattedMessage
id={name}
/>
</Form.Label>
{values.map((value) => (
<span key={value} className="SingleSelectionButton">
<input
{...register(name, { required: required}
id={name + value}
type="radio"
name={name}
value={value}
defaultChecked={defaultData.primary[name] === value}
/>
<label htmlFor={name + value}>
<FormattedMessage id={value} />
</label>
</span>
))}
</Form.Group>
</>
);
};
I call it like this, using an array for the different values:
<SingleSelectionButton
name="us_person"
md={6}
values={["yes", "no"]}
register={register}
required={true}
errors={errors}
validateField="no"
/>
The validation with required is working fine.
The problem is that I don't manage to validate a value in particular.
I have tried the following:
<input
{...register(name, { required: required, validate: value => value === validateField })}
id={name + value}
type="radio"
name={name}
value={value}
defaultChecked={defaultData.primary[name] === value}
/>
And also:
<input
{...register(name, { required: required, pattern: validateField })}
id={name + value}
type="radio"
name={name}
value={value}
defaultChecked={defaultData.primary[name] === value}
/>
So far no joy. What am I missing?

JSX input field returning attributes with null values

I am trying to hide the placeholder and aria-lablelledby attributes when their value is null. Here is the code:
{this.attachAddons(
<Input
key="input"
aria-describedby={
HasErrors(validation)
? null
: `error-${fieldName
.replace('[', '-')
.replace(']', '')}-validation`
}
invalid={Validate.isInvalid(state)}
valid={Validate.isValid(state)}
value={value}
disabled={disabled}
required={required}
id={id}
name={fieldName}
maxLength={props.maxLength}
placeholder={placeholder}
aria-labelledby={`${suffix ? `${id}-desc` : ``}`}
{...rest}
/>,
inputPrefix,
inputSuffix,
inputGroupClassName,
id,
)}
Currently the code rendered looks like:
<input id="username" name="username" maxlength="23" placeholder="" aria-labelledby="" type="text" />
We want it to be:
<input id="username" name="username" maxlength="23" type="text" />

Formik values not updating in Input form but state updates

I am creating an invoice generator with Formik. The issue is that the Fields Component prints out the new state of the form when I click save changes. But when I return to the form again, the old field persists. If I click on something or return, then the new field replaces the old field. I looked at other solutions like enableReinitialize and passing a handleChange but I have the same issue.
Edit Invoice Form Component
<Formik
initialValues={{
senderAddress: invoice.senderAddress,
clientName: invoice.clientName,
clientEmail: invoice.clientEmail,
clientAddress: invoice.clientAddress,
createdAt: new Date(invoice.createdAt),
paymentTerms: invoice.paymentTerms,
description: invoice.description,
items: invoice.items,
invoice: invoice.paymentTerms
}}
validationSchema={validationSchema}
onSubmit={onSubmit}
>
{formik => (
<Form setIsOpen={setIsOpen}
enableReinitialize>
<Heading>Edit <span>#</span>{invoice.id}</Heading>
<Fields client={client} getClientsChild={getClientsChild} setDraftId={setDraftId} />
<Buttons>
<Button type="button" secondary onClick={() => setIsOpen(false)}>Cancel</Button>
<Button type="submit" onClick={() => addDraft(formik.values)}>Save Changes</Button>
</Buttons>
</Form>
)}
Fields Component
useEffect(() => {
console.log(client)
//setFieldValue(businessID, client.draft.business_id)
//setFormikContext const { setFieldValue } = useFormikContext()
//setFieldValue(`items[${index}].total`, rounded || '0');
//onChange={value => setFieldValue(name, value)}
if (client) {
console.log("Client in child", client.draft)
setDraftId(client.draft.id)
formik.values.businessID = client.draft.businessID
formik.values.clientName = client.restaurant.first_name + client.restaurant.last_name;
formik.values.clientEmail = client.restaurant.email;
formik.values.clientAddress.street = client.restaurant.address;
formik.values.clientAddress.postCode = client.restaurant.postal_code;
formik.values.paymentTerms = client.draft.terms;
formik.values.businessID = client.draft.business_id;
console.log("Client in child", client.draft)
}
}, [client])
return (
<TouchScrollable>
<Wrapper>
<FieldSet>
<Legend>Bill From</Legend>
<BillFrom>
<SelectClient update={update} id="client" label="Select Client" name="clientOptions" options={clients ? clients : [{ name: '', value: '' }]} />
<Input label="Street Address" name="senderAddress.street" />
<Input label="City" name="senderAddress.city" />
<Input label="Post Code" name="senderAddress.postCode" />
<Input label="Country" name="senderAddress.country" />
</BillFrom>
</FieldSet>
<FieldSet>
<Legend>Bill To</Legend>
<BillTo>
<Input label="Business ID ( If financing Net 30 terms )" name="businessID" />
<Input label="Client's Name" name="clientName" />
<Input label="Client's Email" name="clientEmail" placeholder="e.g. email#example.com" />
<Input label="Street Address" name="clientAddress.street" />
<Input label="Postal Code" name="clientAddress.postCode" />
</BillTo>
</FieldSet>
<FieldSet>
<OtherFields>
<DatePicker label="Invoice Date" name="createdAt" />
<Select label="Payment Terms" name="paymentTerms" options={dropdownOptions} />
<Input label="Description" name="description" placeholder="e.g. Graphic Design Service" />
</OtherFields>
</FieldSet>
<Items name="items" />
{formik.submitCount > 0 && formik.errors &&
<Errors>
{reduceErrors(formik.errors).map((item, index) => (
<Error key={index}>{item}</Error>
))}
</Errors>
}
</Wrapper>
</TouchScrollable>
)
}

semantic-ui-react: Does large dataset in Form.Select makes the Form slow?

I am having below form(inside modal) created using semantic-ui-react.
<Modal open={editBasicModal} size="small">
<Modal.Header>Your basic details</Modal.Header>
<Modal.Content scrolling>
<Form loading={isSubmitting}>
<Form.Group inline widths="equal">
<Form.Input
required
label="First Name"
fluid
type="text"
name="firstName"
value={values.firstName}
onChange={handleChange}
error={errors.firstName !== undefined}
/>
<Form.Input
required
label="Last Name"
fluid
type="text"
name="lastName"
value={values.lastName}
onChange={handleChange}
error={errors.lastName !== undefined}
/>
</Form.Group>
<Form.TextArea
label="Bio"
type="text"
name="bio"
value={values.bio}
onChange={handleChange}
rows={3}
error={errors.bio !== undefined}
/>
<Form.Select
label="Country"
name="location.country"
placeholder="Country"
value={values.location.country}
onChange={(e, { value }) => {
setFieldValue("location.country", value);
}}
options={this.state.allCountries}
/>
</Form>
</Modal.Content>
<Modal.Actions open={true}>
<Button type="submit" onClick={handleSubmit} >
Update
</Button>
</Modal.Actions>
</Modal>
The above code is from a component which uses Formik + yup.
this.state.allCountries is an array of 200+ records. Now this is making my form slow, the typing inside textarea and input are very slow.
As per my findings the large dataset in the Form.Select is causing the issue, because if i replace the options={this.state.allCountries} to options={[ { key: 1, value: "india", text: "india"} ]}, everything starts working fine. Or if I delete the Form.Selectthen also form works fine.
Few questions?
Is it a known issue?
what are the possible solutions?
I figured out that this is a problem with Form.Select. I changed it with select and everything worked smoothly then. Here is the updated code for select:
<Form.Field >
<label htmlFor="location.country">Country</label>
<select
name="location.country"
id="location.country"
value={values.location.country }
onChange={event => {
setFieldValue("location.country", event.target.value);
}}
>
<option key={0} value={undefined}>
-select-
</option>
{this.state.allCountries}
</select>
</Form.Field>
This renders similar(somewhat) select element with no slowness issue.
Hope it would help someone.

How can I pass the input id with the name and value in redux form?

I'm following along with one of redux-form's tutorials and I'm unable to find a reference on how to properly pass an input's id when submitting the form. Currently, the key value pair submits just fine, but if I want to add the id per input as well, how can I achieve that?
demo
const renderField = (props) => (
<div>
<label>{props.label}</label>
<div>
<input {...props.input} placeholder={props.label} type={props.type} id={props.id}/>
{props.meta.touched && ((props.meta.error && <span>
{props.meta.error}</span>) || (props.meta.warning && <span>
{props.meta.warning}</span>))}
</div>
</div>
)
const FieldLevelValidationForm = (props) => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={() => handleSubmit(this, props.id)}>
<Field name="username" type="text"
component={renderField} label="Username"
id="user"
validate={[ required, maxLength15 ]}
/>
<Field name="email" type="email"
component={renderField} label="Email"
id="userEmail"
validate={email}
warn={aol}
/>
<Field name="age" type="number"
component={renderField} label="Age"
id="userAge"
validate={[ required, number ]}
warn={tooOld}
/>
<Field name="favoriteColor" component="select" id="userColor">
<option value="ff0000">Red</option>
<option value="00ff00">Green</option>
<option value="0000ff">Blue</option>
</Field>
<div>
<button type="submit" disabled={submitting}>Submit</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>Clear Values</button>
</div>
</form>
)
}

Resources