watch not working when setValue sets nested objects - react-hook-form

I pass a complete object to setValue and the input box is updated correctly, but my watch is not printing:
import { useForm } from "react-hook-form";
export default function App() {
const form = useForm({
defaultValues: {
detail: {
firstName: "",
lastName: ""
}
}
});
console.log("watch:", form.watch("detail.firstName"));
const setValueWhole = () => {
form.setValue("detail", {
firstName: "firstName",
lastName: "lastName"
});
};
const setValueEach = () => {
form.setValue("detail.firstName", "firstName1");
form.setValue("detail.lastName", "lastName1");
};
return (
<div className="App">
<form onSubmit={form.handleSubmit(console.log)}>
<input {...form.register("detail.firstName")} />
<input {...form.register("detail.lastName")} />
<div>
<button type="button" onClick={setValueWhole}>
setValue whole
</button>
<button type="button" onClick={setValueEach}>
setValue each
</button>
</div>
</form>
</div>
);
}
Initially, the console printed:
watch: ""
Clicking the setValue whole button, the value of the input box is updated, but the console is not printing again, am I doing something wrong?
watch: ""
# Nothing prints after clicking...
If I click setValue each, it will print correctly:
watch: ""
watch: "firstName1"

Related

react-hook-form: how to remove the item (which is mentioned in defautvalue) from submit data if its not mounted. Tried unregister its not working

I have simple form with firstName and lastName. I have added some defaultValues to them in useForm. I havent mounted the lastName using if condition.
Now when I try to submit, I am expecting it to show only the mounted components values i.e firstName. But it shows both firstName and lastName. I have created a button to try to unregister("lastName") but even after unregister and not being mounted it shows in the submit data.
If I dont provide defaultValues then it works well, like if not mounted initially it will not be shown in the submit data.
Below is the code
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { useForm } from "react-hook-form";
import "./styles.css";
const App = () => {
const { register, handleSubmit, unregister, watch } = useForm({
defaultValues: {
firstName: "test",
lastName: "test2"
}
});
const onSubmit = (data) => {
console.log("ON SUBMIT");
console.log(JSON.stringify(data, null, 4));
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>Last Name</label>
<input {...register("firstName")} />
{false && (
<>
<label>Last Name</label>
<input {...register("lastName")} />
</>
)}
<button
type="button"
onClick={() => {
console.log("unregistering lastName")
unregister("lastName");
}}
>
unregister lastName
</button>
<input type="submit" />
</form>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
And the codesandbox
For the first, you can't use unregister("lastName"); before register("lastName"); it's useless. Second, when you use defaultValues, method unregister does not remove them but simply set values to default. You just can filter submit data by conditions without unregister. Demo

TypeError: Cannot read property 'message' of undefined ---using react-hook-form

I am trying to display an error message when nothing is typed inside the message input form, but when I load the page I get this error 'TypeError: Cannot read property 'message' of undefined'. I am using react-hook-forms. This is my code down below.
import { Button } from "#material-ui/core";
import { Close } from "#material-ui/icons";
import React from "react";
import { useForm } from "react-hook-form";
import "./SendMail.css";
const SendMail = () => {
const { register, handleSubmit, watch, errors } = useForm();
const onSubmit = (formData) =>{
console.log(formData)
}
return (
<div className="sendMail">
<div className="sendMail__header">
<h3>New Message</h3>
<Close className="sendMail__close" />
</div>
<form onSubmit={handleSubmit(onSubmit)}>
<input name='to' placeholder="To" type="text" {...register('to',{required:true})}/>
<input name="subject" placeholder="Subject" type="text" {...register('subject',{required:true})} />
<input
name="message"
placeholder="Message..."
type="text"
className="sendMail__message"
{...register('message',{required:true})}
/>
{errors.message && <p>To is required!!</p>}
<div className="sendMail__send">
<Button
className="sendMail__send"
variant="contained"
color="primary"
type="submit"
>
Send
</Button>
</div>
</form>
</div>
);
};
export default SendMail;
Since v7 the errors object moved to the formState property, so you need to adjust your destructering:
const { register, handleSubmit, watch, formState: { errors } } = useForm();

How to register 'react-bootstrap-typeahead' component using React 'useForm' hook?

I'm building a simple html form using "react-hook-form" library: https://react-hook-form.com/
I've incorporated "react-bootstrap-typeahead" into the html form but haven't been able to register this component with 'useForm' hook. Hence, "react-bootstrap-typeahead" input data is ignored during onSubmit.
"react-bootstrap-typeahead" doesn't provide a "name" prop which makes it difficult to register the component.
I've read the 'useForm' documentation on the different options for registering this type of components but still don't understand how to achieve this: https://react-hook-form.com/get-started#Registerfields
Does anybody have faced such challenge before?
It would be great to see a working example to get a better idea on how to implement "react-bootstrap-typeahead" + "react-hook-form" in my application. Thanks!
Here's my sample code:
import useForm from 'react-hook-form';
import { Typeahead } from 'react-bootstrap-typeahead';
import 'react-bootstrap-typeahead/css/Typeahead.css';
const myForm = (props) => {
const { register, handleSubmit, errors } = useForm();
const onSubmit = data => {
// api post request with form data
})
};
const mydata = [ "one", "two", "three" ];
return (
<>
<form onSubmit={handleSubmit(onSubmit)} >
<div className="form-group">
{/* Here I'm registering text input using ref: */}
<input type="text" className="form-control" name="name" ref={register({ required: true })} />
</div>
<div className="form-group mb-0">
{/* How can I register the below component with useForm? */}
<Typeahead
id="multiple-typeahead"
clearButton
multiple
options={mydata}
/>
</div>
<button type="submit">Save</button>
</form>
</>
);
}
This is how i was able to register the component:
import useForm from 'react-hook-form';
import { useForm, Controller } from "react-hook-form";
import 'react-bootstrap-typeahead/css/Typeahead.css';
const myForm = (props) => {
const { register, handleSubmit, errors, control } = useForm();
const onSubmit = data => {
// api post request with form data
})
};
const mydata = [ "one", "two", "three" ];
return (
<>
<form onSubmit={handleSubmit(onSubmit)} >
<div className="form-group">
<input type="text" className="form-control" name="name" ref={register({ required: true })} />
</div>
<div className="form-group mb-0">
<Controller
as={Typeahead}
control={control}
name="typeahead_component"
rules={{ required: true }}
id="multiple-typeahead"
clearButton
multiple
options={mydata}
defaultValue=""
/>
</div>
<button type="submit">Save</button>
</form>
</>
);
}

Issue in react final form

I am using react final form for validation purpose for login page which has forgot password and register link as well, now when I am clicking forgot password or register link ,it should not trigger any validation even though I am not filling my user name and password .I have tried t keep forgot password and register link away from tag but it is still triggering the validation on click of forgot password and register link .It should only trigger the validation when I m hitting submit button.
It should not ask to validate the form when I am clicking on any hyper link on the page as hyperlinks does not have any validations.
Here is the code sample
loginPage = () => {
const {t: translate} = this.props;
const {
match: {
params: {
authUrlKey = ''
} = {},
} = {},
} = this.props;
return (
<Form
onSubmit={ (values)=> this.validateUserCredentials(values)}
render={({ handleSubmit}) => (
<form onSubmit={handleSubmit}>
<button className="hidden" type="submit"/>
<h1 className="hw-block--pb">{translate('login.heading')}</h1>
<p className="hw-text-lead hw-block--pb-small">{translate('login.text')}</p>
{ this.state.description !=='' && <p className="hw-text-lead hw-block--pb-small">{this.state.description}</p> }
<div className="hw-grid">
<div className="hw-grid__item hw-one-whole hw-medium--one-fifth hw-large--one-sixth">
<label className="hw-label">{translate('login.landcode')}
<Field name="landcode" component={Dropdown} options={getCountryList()} onOptionSelect={this.onCountrySelect}/>
</label>
</div>
<div className="hw-grid__item hw-one-whole hw-medium--four-fifths hw-large--five-sixths">
<label className="hw-label">{translate('login.mobileNumber')}
<Field type="text" component={InputType}
validate={composeValidators(mobileNumberRequired, validMobileNumberWithISDCode)}
placeholder={translate('login.mobileNumberPlaceHolder')} name="phoneNumber"/>
</label>
</div>
</div>
<label className="hw-label">{translate('login.password')}
<Field type="password" component={InputType} validate={passwordRequired} placeholder={translate('login.passwordPlaceHolder')} name="password"/>
</label>
<Link className="hw-link" to={{ pathname: '/password/reset', state: {authUrlKey} }}>{translate('login.forgotPassword')}</Link>
<ErrorInfo error={this.state.error} errorMessage={this.state.errorMessage} translate={translate}/>
<div className="hw-block hw-block--mt-small">
<div className="hw-grid">
<div className="hw-grid__item hw-small--one-whole hw-medium--one-quarter hw-block--mb-smaller">
<button className="hw-button hw-button--primary hw-button--full" type="submit">{translate('login.loginButton')}</button>
</div>
<div className="hw-grid__item hw-one-whole hw-medium--three-quarters hw-block--mt-smaller">
<Link className="hw-link"
to={{ pathname: '/register', state: {authUrlKey} }}>{translate('login.registerButton')}</Link>
</div>
</div>
</div>
</form>)}
/>
)}
validations function used in code
export const validMobileNumberWithISDCode = (fieldValue='') => {
const value = trimValue(fieldValue);
const regex1 = /^\+?((45)|(46)|(47))?( )?\d{8,10}$/
return (regex1.test(value))? undefined : message[root.lang].validMobileNumber;
}
export const validMobileNumber = (fieldValue='') => {
const value = trimValue(fieldValue);
const regex1 = /^\d{8,10}$/;
return (regex1.test(value))? undefined : message[root.lang].validMobileNumber;
}
export const mobileNumberRequired = (fieldValue='') => {
const value = trimValue(fieldValue);
return value ? undefined : message[root.lang].mobileNumberRequired;
}
export const passwordRequired = (fieldValue='') => {
const value = trimValue(fieldValue);
return value ? undefined: message[root.lang].passwordRequired;
}
export const required =(fieldValue)=> {
const value = trimValue(fieldValue);
return value ? undefined : message[root.lang].required;
}```
validateUserCredentials -> This function does not contains any validation.It is used to retrieve form values and send it to server
React Final Form calls your validation function on every value change in the form, to ensure that the form validity is always up to date. Since you did not include the code for your validation function, I cannot ascertain what you are attempting to do. Your validation function should be very cheap to run (e.g. required fields, value length, etc.). The actual authentication should happen on submit.

Use Devextreme js Widget in ASP.NET Core

I'm trying to find a way to use Devextreme RadioGroup js widget with ASP.NET Core.
I've created this simple View:
<form asp-action="SelectSourceData" asp-controller="Home" method="post">
<div class="form-group">
<label for="rg-mode">Please Choose Migration Mode</label>
<div id="rg-mode"></div>
</div>
<button type="submit" class="btn btn-primary">Proceed</button>
</form>
#section Scripts {
<script>
$(function () {
$("#rg-mode").dxRadioGroup({
dataSource: modes,
displayExpr: "text",
valueExpr: "val",
value: "by-org"
})
});
var modes = [
{ text: "By Organisation", val: "by-org" },
{ text: "By Contract Type", val: "by-contr" },
{ text: "By Employee", val: "by-emp" },
{ text: "Mixed Mode", val: "mm" }
];
</script>
}
When user presses Proceed button SelectSourceData action method is invoked:
[HttpPost]
public ViewResult SelectSourceData(string val)
{
// get selected value here ... ?
return View();
}
My question is: is it possible to somehow obtain the value selected in dxRadioGroup widget?
Following #Stephen's advice I added a hidden input field:
<div class="form-group">
<input id="hdnMode" name="mode" type="hidden" value="by-org" class="form-control" />
<label for="rg-mode">Please Choose Migration Mode</label>
<div id="rg-mode"></div>
</div>
and registered a handling function for value changed event:
$(function () {
$("#rg-mode").dxRadioGroup({
dataSource: modes,
displayExpr: "text",
valueExpr: "val",
value: "by-org",
onValueChanged: function (e) {
var previousValue = e.previousValue;
var newValue = e.value;
// Event handling commands go here
$("#hdnMode").val(newValue);
}
})
});
The action method now correctly obtains the value submitted by the form:
[HttpPost]
public ViewResult SelectSourceData(string mode)
{
// mode argument successfully set to submitted value
var t = mode;
....

Resources