How to show placeholder value on React/Formik Select Component? - javascript

I have a dropdown Select component. This component displays the values of the elements, that we get from the server. In the following schema:
[
{label: 1, value: 1},
{label: 2, value: 2},
{label: 3, value: 3},
]
I am using Formik and map through the data, to get the values. Problem is, that I don't have a placeholder value, thus users think the value is already selected.
I am reading through the formik examples and I am not founding anything similar.
Here is a working example, from the formik examples
I am trying to force the placeholder, as an option, but that doesn't work. Any ideas?
<div className="py-3">
<label>
<span className="font-weight-bold">Select Group</span>
<span className="text-danger">*</span>
</label>
<Field
name="group"
component="select"
placeholder="Select Group (Just one)"
className={classNames('form-control', {
'is-invalid': errors.group && touched.group
})}
>
{groups.map(group => (
<option key={group.label} value={group.value}>
{group.value}
</option>
))}
</Field>
{errors.group && touched.group ? (
<div className="text-danger">{errors.group}</div>
) : null}
</div>
Currently, the groups have initial value of the first item returned from the server.
I want to display the placeholder, like in the code above. This one placeholder="Select Group (Just one)"

Apparently, there are a lot of ways to do this. I chose the easiest one. I just added a defaultValue tag in a second option field. This allows the default value to be displayed and you can choose through the mapped options on render dropdown:
Like this:
<div className="py-3">
<label>
<span className="font-weight-bold">Select Group</span>
<span className="text-danger">*</span>
</label>
<Field
name="group"
component="select"
className={classNames('form-control', {
'is-invalid': errors.group && touched.group
})}
>
<option defaultValue>Select Group (Just one)</option>
{groups.map(group => (
<option key={group.label} value={group.value}>
{group.value}
</option>
))}
</Field>
</div>

Related

Updating default values of a React-Hook-Form, does not populate filelds with useFieldArray

This problem has consumed a lot of time trying to figure out what is wrong. I have a React-Hook-Form (v6.14.1) that needs to populate dynamic data, based on the component state.
On the initial load, everything works fine. If I change the state all updated data are displaying fine, except the dynamic data.
Here is a codesandbox link. If it does not render due to a library error, just hit the preview refresh button.
The goal is that the WAN 1 tab, on initial load displays the dynamic fields (WAN 1 VLAN-1) and WAN2 does not have dynamic fields to display. Hitting the Update Config button, WAN1 should not have dynamic fields to display and WAN2 should display one (WAN 2 VLAN-1). The problem is that WAN2 does not display it.
I have searched for similar questions, but all of them were about the values of the populated fields and not about displaying the fields themselves. I have used the reset method of react-hook-form and the defaltValue for each dynamic field as react-hook-form documentation suggests.
On App.js I have the state, a button that updates the state, and the Form component which has the state as property.
const [configdata, setConfigdata] = useState(config);
return (
<div className="App">
<UpdateConfig onClick={() => setConfigdata(configUpdated)} />
<Form
formData={configdata}
handleFormData={(data) => console.log(data)}
/>
</div>
);
}
On Form.js there is a Rect-hook-form FormProvider and the WanFields component that dynamically populates form fields.
<FormProvider {...methods}>
<form
onSubmit={methods.handleSubmit((data) =>
props.handleFormData(data)
)}
>
<Tab.Content>
{props.formData?.intfs?.length &&
props.formData?.intfs.map((intf, index) => (
<Tab.Pane key={index} eventKey={`wan${index}-tab`}>
<WanFields
key={`wan${index}-fields`}
intfNo={index}
portTypeOptions={props.portTypeOptions}
data={intf}
/>
</Tab.Pane>
))}
</Tab.Content>
</form>
</FormProvider>
Every time the props.formData update, there is a useEffect that reset the forms' default data.
const methods = useForm({ defaultValues: props.formData });
useEffect(() => {
methods.reset(props.formData);
}, [props.formData]);
In WanFields.js, there are all the form fields, and the useFieldArray method, that will populate the dynamic fields based on the forms' default values and a watch field value (watchIntfType ).
const methods = useFormContext();
const { errors, control, watch, register } = methods;
const { fields, append, remove } = useFieldArray({
control,
keyName: "fieldid",
name: `intfs[${intfNo}].subIntfs`
});
const watchIntfStatus = watch(`intfs[${intfNo}].enabledStatus`);
const watchIntfType = watch(`intfs[${intfNo}].enabled`);
Dynamic fields are populated as follows
{watchIntfType?.value >= "2" && (
<>
<div className="form-group">
<div className="btn btn-success" onClick={append}>
Add
</div>
</div>
<div id={`accordion-${intfNo}`}>
<Accordion>
{console.log("FIELDS", fields)}
// This is where the problem starts. fields are empty after updating data
{fields.map((field, index) => {
return (
<Card key={field.fieldid}>
<Accordion.Toggle
as={Card.Header}
variant="link"
eventKey={`${index}`}
style={{ cursor: "pointer" }}
>
<h4>
WAN {parseInt(intfNo) + 1}{" "}
<span style={{ margin: "0px 5px" }}>
<i className="fas fa-angle-right"></i>
</span>{" "}
VLAN-{index + 1}
</h4>
<div className="card-header-action">
<button
type="button"
className="btn btn-danger"
onClick={() => remove(index)}
>
Remove
</button>
</div>
</Accordion.Toggle>
<Accordion.Collapse eventKey={`${index}`}>
<Card.Body>
<div className="form-row">
<div className="form-group col-12 col-md-6">
<label>IP</label>
<input
type="text"
className="form-control"
name={`intfs[${intfNo}].subIntfs[${index}].ipAddress`}
defaultValue={field?.ipAddress}
ref={register()}
/>
</div>
<div className="form-group col-12 col-md-6">
<label>Subnet</label>
<input
type="number"
className="form-control"
min="0"
max="30"
name={`intfs[${intfNo}].subIntfs[${index}].subnet`}
defaultValue={field?.subnet}
ref={register()}
/>
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>
);
})}
</Accordion>
</div>
</>
)}
The problem is that when the state updates, form default values are updated, but the method useFieldArray attribute fields are not updated and stay as an empty array. I really cannot understand, what I am doing wrong. Any help will be much appreciated.
I don't know if is a correct method but i have resolv this probleme with method reset in a useEffect.
https://react-hook-form.com/api/useform/reset
defaultValues:
{
acvDesignOffice: generateRSEnv.acvDesignOffice,
earthQuakeZone: generateRSEnv.earthQuakeZone,
buildings: generateRSEnv.buildings,
},
useEffect(() => {
reset({
acvDesignOffice: generateRSEnv.acvDesignOffice,
earthQuakeZone: generateRSEnv.earthQuakeZone,
buildings: generateRSEnv.buildings,
});
}, [generateRSEnv]);

method is not getting called on onChange event in formik react

I have to call below method using formik
const handleChange = async (e:any, values: any) => {
alert(e.target.value);
alert(values);
alert('Method called');
};
below is formik code.
<Formik initialValues={formInitialSchema}
validationSchema={formValidationSchema}
onSubmit={handleSubmit}>
<Form>
<div className="col-md-4">
<label htmlFor="protoColNo">Protocol No</label>
<Field
id="protoColNo"
className="form-control"
name="protoColNo"
placeholder="Enter the Protocol No"
/>
<p className="text-danger">
<ErrorMessage name="protoColNo" />
</p>
</div>
<div className="col-md-4">
<label htmlFor="activerequests">Active Requests</label>
<select
name="activeRequest"
style={{ display: 'block' }}
onChange= {(e)=>handleChange}>
<option value="No" >No </option>
<option value="Yes" >Yes</option>
<option value="All" selected>All </option>
</select>
<p className="text-danger">
<ErrorMessage name="activerequests" />
</p>
</div>
</div>
</Form>
</Formik>
I have one input filed and one drop down. As soon as user change the value of drop down I need to call handleChange method with the value of input filed and list. but method is not getting called. I dont know what wrong I am doing?
can you please help me with the same?
onChange= {(e)=>handleChange(e)}> //you forgot to call the handleChange
OR
onChange={handleChange}
You need to call the anonymous function inside the onChange event.
Use the following code :
onChange= {(e)=>handleChange(e)}

React <Typeahead> set default value

I am trying to set default value in typeahead,
Here is my code::https://codesandbox.io/s/brave-sound-pzse0?file=/src/App.js
<FormGroup>
<label
className="form-control-label"
htmlFor="input-email"
>
Account
</label>
<Typeahead
id="input-account"
onChange={setSelected}
options={lookuplist}
placeholder="Choose a Account..."
selected={selected}
filterBy={['name']}
labelKey={lookuplist => `${lookuplist.name} (${lookuplist.id})`}
defaultValue={editcontacts.phone}
/>
</FormGroup>
The defaultValue is not rendering in typeahead,
according to the api, you can use the defaultInputValue prop if you want to set a default value for the Typeahead.
sandbox

react radio button doesn't work on the first click

I have a radio button using pure css, but it doesn't work on first click, it only work on the second click onward, not sure it has to do with my react prop or not:
const Radio = ({ id, name, value, checked, children }) => (
<div className="radioBtn">
<input type="radio" value={value} id={id} name={name} checked={checked} />
<label className={"radio"} htmlFor={id}>
<span className={"big"}>
<span className={"small"} />
</span>
<span>{children}</span>
</label>
</div>
);
https://codesandbox.io/s/react-sass-34b8w
Use defaultChecked instead of checked={checked}.

Return one item of string

There is an input in which there should be several additional attributes to help the user
I can insert these attributes, but the redux form will return a whole line, and I only need an email, how to make it return only email
<Field component={SelectUser} name="SendTo" validate={[required]} id="age-native-simple">
<option value="" />
{
props.initialValues.users.map((p, index) => (
<option key={index}>{p.FIO+" "+p.Email+" "+p.Otdel}</option>
))}
</Field>
try this:
<Field component={SelectUser} name="SendTo" validate={[required]} id="age-native-simple">
<option value="" />
{
props.initialValues.users.map((p, index) => (
<option value={p.Email} key={index}>{p.FIO+" "+p.Email+" "+p.Otdel}</option>
))}
</Field>
Make an array by splitting the string by white space, and return 4th element, given that it's always in the same position.

Categories

Resources