render form to input values:
return (
handleSubmit will check if the form is valid and ready to be submit, it call the callback function
// that is in our case, the onSubmit()
The name property specifies what piece of state is being edited
<Field
label="Email"
type="email"
name="Email"
component={this.renderField}
/>
<Field name="city"
label="Cidade"
value={this.state.value}
onChange={this.handleChange}
options={options}
component="select">
</Field>
<Field
label="Password"
type="password"
name="password"
component={this.renderField}
/>
<button type="submit" className="btn btn-primary">Submit</button>
<Link to="/register" className="btn btn-danger">Already registered?</Link>
</form>
);
I'm getting the values from json but the field it's empty
Your initial state might not be set, so this.state.cities is actually empty.
Do something like this in your render function:
render() {
const options = ( this.state.cities || [] ).map( (city) => ( {
value: city.name,
label: city.id
} );
return (
-- other components --
{ options.length ? (
<Field name="city"
label="Cidade"
value={this.state.value}
onChange={this.handleChange}
options={options}
component="select"
/>
) : null }
-- other components --
);
}
( this.state.cities || [] ) will check if this.state.cities is available, otherwise it uses an empty array.
A little more detail: Your axios call is asynchronous. That means, that React doesn't wait for axios to fetch your data but instead just tries to render something.
Your state has not been set (probably) and therefore you get this error.
Related
I'm working with react-hook-form, and I have the following code
const array = ['foo', 'bar']
const Form = () => {
const { handleSubmit, register } = useForm();
return (
<div>
<form onSubmit={handleSubmit(submitFunction)}>
<input
type="text"
{...register("value", {
required: true,
})}
/>
<input type="submit" />
</form>
</div>
);
};
Is there a way to check if a registered input value is included in the array?
Something like
array.includes(value)
Thanks in advance
From offical doc:
You can pass a callback function as the argument to validate, or you can pass an object of callback functions to validate all of them. This function will be executed on its own without depending on other validation rules included in the required attribute. Note: for object or array input data, it's recommended to use the validate function for validation as the other rules mos tly apply to string, string[], number and boolean data types.
<input
{...register("test", {
validate: value => value === '1' || 'error message' // JS only: <p>error message</p> TS only support string
})}
/>
For the error message
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("singleErrorInput", { required: "This is required." })} />
<ErrorMessage errors={errors} name="singleErrorInput" />
<ErrorMessage
errors={errors}
name="singleErrorInput"
render={({ message }) => <p>{message}</p>}
/>
<input type="submit" />
</form>
multi call backs
// object of callback functions
<input
{...register("test1", {
validate: {
positive: v => parseInt(v) > 0,
lessThanTen: v => parseInt(v) < 10,
validateNumber: (_, values) =>
!!(values.number1 + values.number2),
checkUrl: async () => await fetch(),
}
})}
/>
you can pass callback funcation in validate
I am developing a React frontend to send form data back to my API. I have decided to use formik to create the required forms for my app. While testing the array field and trying to add validation errors only at the in question array element input field. I have run into this error.
Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info:
I have successfully implemented my form and errors for other fields except the array field, so I tried to add the ErrorMessage tag with the correct array element index as the name and this is when the error showed its fangs first.
Here is my component code:
I tried to dig into the error and find the solution my self, but all the other stack overflow answers I saw discussing this error were too complicated for me to understand. If anyone can help would be much appreciated also if you have any tips on how I could clean up this code I'll take it its not the prettiest.
import { useDispatch } from "react-redux";
import {Formik, Form, Field, FieldArray, ErrorMessage} from 'formik'
import * as Yup from 'yup'
const Sign = () => {
const ciscoDomainRegex = new RegExp('.*\.cisco\.com')
const SignSchema = Yup.object({
hostname:Yup.string().matches(ciscoDomainRegex, 'Hostname Must Be A Cisco Domain').required('required'),
sans:Yup.array().of(Yup.string().matches(ciscoDomainRegex)),
csr:Yup.mixed()
})
const dispatch = useDispatch()
const showError = (errors, field)=>{
switch (field){
case 'hostname':
return <p>{errors.hostname}</p>
case 'sans':
return <p>{errors.sans}</p>
case 'csr':
return <p>{errors.csr}</p>
default:
return false
}
}
return (
<div>
Sign Page
<Formik
initialValues={{
hostname:'',
sans:[''],
csr:null
}}
validationSchema={SignSchema}
onSubmit={(values)=>console.log(values)}
>
{({errors, touched, setFieldValue})=>{
return(
<Form className="form-center">
<Field className="form-control mt-1" name='hostname' placeholder="Enter Hostname"/>
{/* {errors && touched.hostname ? showError(errors, 'hostname') : null} */}
<ErrorMessage name="hostname"/>
<FieldArray name="sans" placeholder='Enter Sans'>
{({push, remove, form})=>{
const {sans} = form.values
return (
<div>
{
sans.map((san, i)=>{
return (
<div className="input-group" key={i}>
<Field className="form-control mt-1" name={`sans${i}`} placeholder="Enter San"/>
{/* {errors && touched.sans ? showError(errors, 'sans') : null} */}
<ErrorMessage name={`sans${i}`}/>
<div className="input-group-append">
<button className="btn btn-secondary float-end" type="button" onClick={()=>remove(i)}>-</button>
<button className="btn btn-secondary" type="button" onClick={()=>push('')}>+</button>
</div>
</div>
)
})
}
</div>
)
}}
</FieldArray>
<input className="form-control mt-1" type="file" name='csr' onChange={(e)=>setFieldValue('csr',e.currentTarget.files[0])}/>
{errors && console.log(errors)}
<button className="btn btn-primary" type="submit">Submit</button>
</Form>
)
}}
</Formik>
</div>
);
}
export default Sign;
You are passing the wrong field name for each of the fields that will be added dynamucally.
Each field name should be name[index] like so...
<Field name={san[$(index)]/>
or u can as well use the dot notation to reference the particular field in the field array
PS: don't forget to use backticks
I'm trying to create separate input component and use React Hook Forms, Here is component:
export default function TextInput({label, id, placeholder, name, ...params}) {
return (
<FormGroup>
<Label htmlFor={id}> {label} </Label>
<Input
className="form-control"
placeholder={placeholder}
name={name}
id={id}
{...params}
/>
</FormGroup>
);
}
and I'm calling it like this:
const {register, handleSubmit} = useForm();
const onSubmit = (data) => {
console.log(data);
}
<form onSubmit={handleSubmit(onSubmit)}>
<TextInput
label="input password"
placeholder="password"
name="password"
{...register("password")}
id="password"
type="password"
/>
<button type="submit">submit</button>
</form>
But when I click submit, password seems to be undefined
React-hook-version is 7.33, any ideas about what is the problem?
lets say you passed the a varible to get value from Input Field.
and next step will be to give this input field a function so that it can update the value of that variable in your case passowrd.
to do that I will use onChange.
<input onChange={(event)=>{resister.password = event.target.value}}/>
or
<input onChange={(event)=>{resister['password'] = event.target.value}}/>
and according to useForm documentation
you should be using resister in <input/> not in <TextInput/>
const { onChange, onBlur, name, ref } = register('firstName');
// include type check against field path with the name you have supplied.
<input
onChange={onChange} // assign onChange event
onBlur={onBlur} // assign onBlur event
name={name} // assign name prop
ref={ref} // assign ref prop
/>
// same as above
<input {...register('firstName')} />
https://react-hook-form.com/api/useform/register
I am trying to render the field based on condition that is passed to the component like as below
return (
<FieldArray name={`spaceType.mechanicalData.${mappedLibrarySourceArray}`}>
{({ fields }) => {
const dataSource = fields.map((name, index) => ({
rowKey: index,
...values.spaceType.mechanicalData[mappedLibrarySourceArray][index],
{ isProjectSystem && (select ( // getting error at this line (compile errors)
<Field
name="airSystem.isEquipmentIncluded"
component={AntdCheckboxAdapter}
type="checkbox"
label="Included"
disabled={isReadOnly}
/>
)),
},
id: (
<Field
name={name}
component={AntdSelectSectionAdapter}
isProjectSystem={isProjectSystem}
section={section}
disabled={isReadOnly}
placeholder="Select source"
render={sourceRender}
/>
),
}));
return (
<div>
<Table
columns={tableColumns}
dataSource={dataSource}
rowKey="rowKey"
/>
</div>
);
}}
</FieldArray>
);
and i am not sure where i am doing wrong with above code and isProjectSystem is boolean variable passed onto this component
I am using react JS with final form adapters plugin
Could any one please suggest any ideas on this that would be very grateful.
thanks in advance
You could do:
const dataSource = fields.map((name, index) => ({
rowKey: index,
...values.spaceType.mechanicalData[mappedLibrarySourceArray][index],
select: isProjectSystem ? (
<Field
name="airSystem.isEquipmentIncluded"
component={AntdCheckboxAdapter}
type="checkbox"
label="Included"
disabled={isReadOnly}
/>
) : null,
id: (
<Field
name={name}
component={AntdSelectSectionAdapter}
isProjectSystem={isProjectSystem}
section={section}
disabled={isReadOnly}
placeholder="Select source"
render={sourceRender}
/>
),
}));
that will have the select property there regardless. Alternately, you could change your map to conditionally add that property after.
const dataSource = fields.map((name, index) => {
const output = {
rowKey: index,
...values.spaceType.mechanicalData[mappedLibrarySourceArray][index],
id: (
<Field
name={name}
component={AntdSelectSectionAdapter}
isProjectSystem={isProjectSystem}
section={section}
disabled={isReadOnly}
placeholder="Select source"
render={sourceRender}
/>
),
};
if (isProjectSystem) {
output.select = (
<Field
name="airSystem.isEquipmentIncluded"
component={AntdCheckboxAdapter}
type="checkbox"
label="Included"
disabled={isReadOnly}
/>
);
}
return output;
});
I am not able to access the value of <TextField />, if i don't write <input type='password'/> then it works fine, but for this i am getting a TypeError, 'this.refs[this._getRef(...)].getInputNode is not a function'.
dialogAction(tag,e){
console.log(this.refs.password);
console.log(this.refs.password.getValue());
this.refs.dialog.dismiss();
}
render(){
let self = this;
let row = this.row,col = this.column;
let standardActions = [
{ text: 'Cancel',onTouchTap: this.dialogAction.bind(this,ProductConstants.CANCEL)},
{ text: 'Submit',onTouchTap: this.dialogAction.bind(this,ProductConstants.SUBMIT)}
];
return (
<div className="ProductRepository">
<Dialog ref = 'dialog'
title="Dialog With Standard Actions"
actions={standardActions}
actionFocus="submit"
modal={true}>
<TextField ref='password'
hintText="Password"
floatingLabelText="Password">
<input type="password" />
</TextField>
</Dialog>
</div>
);}
}
image below is the console output of the above code.
This solved my issue:
<TextField ref='password'
hintText="Password"
floatingLabelText="Password"
type="password">
</TextField>
After that
this.refs.password.getValue()
gives the desired output.
For React v >= 15.6
<TextField ref={x => this.password = x}
hintText="Password"
floatingLabelText="Password"
type="password">
</TextField>
in inputHandler function
this.password.value
For material 1.0 and react 16.1.1
Use inputRef
<TextField autoFocus={true} inputRef={el => this.fv = el}
placeholder="Required" size="30"></TextField >
To read the value use below line
console.log(this.fv.value);
Assign ref="password" to the input itself instead of the TextField. Currently you are executing getValue() on some abstract (probably some container) tag (TextField), not on the input itself.
Here's how it's done.
You can get the input value like this :
this.refs.password.input.value;