React Hook Form Dynamic Require - validation

Good Day All,
Im using react hook form and I want set required dynamically on one text-input. I have a useState that tracks the delivery method and radio buttons that update that state. And then the text-input required should be based dynamically on that state. So if the delivery method is "Delivery" we require your address if its "Pickup" we dont require your address. I hope that makes sense.
In the code below the show/hide functionality works as expected however the dynamic require does not.
const [ delivery, setDelivery ] = useState(false);
<InfoBlock>
<strong>Delivery Method</strong>
<RadioGroup>
<RadioBlock>
<input type="radio" id="pickup" name="pickup" {...register("deliveryMethod", {required: true})}
value="pickup" onClick={() => setDelivery(false)} />
<h5>Pickup</h5>
</RadioBlock>
<RadioBlock>
<input type="radio" id="deliver" name="delivery" {...register("deliveryMethod", {required: true})}
value="delivery" onClick={() => setDelivery(true)} />
<h5>Delivery</h5>
</RadioBlock>
</RadioGroup>
</InfoBlock>
<ErrorMsg>
{errors.deliveryMethod && errors.deliveryMethod.type === 'required' && "Please select delivery method"}
</ErrorMsg>
{delivery ?
<div>
<InfoBlock>
<strong>Address</strong>
**<input type="text" id="address" name="address"
{...register("address", {required: delivery })} />**
</InfoBlock>
<ErrorMsg>
{errors.address && errors.address.type === 'required' && "Address is required"}
</ErrorMsg>
</div> : null}

You don't need useState here, as you can use RHF for handling the state of your radio input value - you can just use watch, provided by useForm, to watch for changes of that field
As you conditionally render the 'address' input only for a certain delivery method, you can also just set required to true for the rules of that field
There is one important thing: since v7 there is no automatically removal of fields which will unmount (in your case, due to conditional rendering). So for now, you have to unregister the field manually. This is why in the CodeSandbox there is the unregister call, when clicking the 'pickup' radio option.
However, there is currently a discussion ongoing, as this new behaviour brings disadvantages in some cases (such as conditional rendering of fields). So maybe it will be possible again in the future to unregister fields automatically on unmount.

Related

Razor: hidden password control (2 page registration)

I'm creating a 2-page registration process in razor. The difficulty here is gathering data (username, passwd, etc) on the first page and using hidden input variables to store the first page's data on the second.
here is my hidden code:
<div id="hidden vals" style="display:none;">
#Html.HiddenFor(model => model.userRegisterModel.UserName)
#Html.HiddenFor(model => model.userRegisterModel.studentFirstName)
#Html.HiddenFor(model => model.userRegisterModel.studentlastName)
#Html.HiddenFor(model => model.userRegisterModel.Email)
#Html.PasswordFor(model => model.userRegisterModel.Password)
#Html.PasswordFor(model => model.userRegisterModel.ConfirmPassword)
</div>
the challenge is in password and confirmpassword. I don't want to use a hidden field of password type but i want my password persisted but not revealed in page-source. but the "PasswordFor" has a side problem that it "depopulates" the values and makes the user re-populate.
So to re-state, I need my password and confirm persisted and preferably not shown to the user. Moist importantly I need my password and confirm values not hidden from "view source"
My alternative strategy is to use a session variable to store all "page 1 values" but this has other pitfalls id prefer to avoid.
Can I suggest a different approach? Instead of two-page, use two-DIV.
You can still leverage things like validation (client & remote) and make sure the user can't advance without a valid form. If there are things that need to be loaded and/or created for the second page, you can do that with Ajax and your form could still live on the page, without the use of the hidden fields or the session variables/timeouts.
<form ...>
<div id="part-one">
<!-- content... -->
</div>
<div id="part-two" style="display:none;">
<!-- content... -->
</div>
<div>
<button type="button" id="prev-div">Previous</button>
<button type="button" id="next-div">Next</button>
<button disabled="disabled" id="next-div">Submit</button>
</div>
</form>
The buttons stay visible, you can toggle the state of them with jQuery, and if your requirements change an update to your model class and view are all that is required (if you're using model binding).
Yes. Keep them in Session and access it in the second page / action method.
And Make sure to clear that particular Session variable once you read from that for persistant storage.

ASP.NET MVC 3 Razor view returning multiple values for a Html.CheckBoxFor

I have a View that contains the following Line of code:
//(DaysOfWeek is a bool[])
#Html.CheckBoxFor(m => m.Data.DaysOfWeek[0])
It starts off as false. When the user "checks" the box and returns, it returns a value for both true and false;
Here is what is being passed back as part of the form data
Data.DaysOfWeek[0]:true
Data.DaysOfWeek[0]:false
Why is it doing that?
This is because standard HTML checkboxes return no value if unchecked. To make this annoying behaviour more intuitive, the CheckBoxFor method creates a checkbox and a hidden control with the same name, with a value of false, something like this:
<input type="checkbox" name="myControl" value="True" /> My control
<input type="hidden" name="myControl" value="False" />
What you will see when the form is posted is either:
False // checkbox unchecked
True,False // checkbox was checked
Therefore, to test if the box was checked you should use Contains('True'):
bool checkboxChecked = formCollection["myControl"].Contains("True");

Validate a Hidden Field

I'm using MVC3 with unobtrusive validation. I have a field that the user is expected to fill with some data and then press a "search" button. If search has never been pressed or the user has changed the input field after pressing search, the form should not be possible to submit.
I've added a hidden field that is set to true by the click() event of the button and emptied by the keyup() event of the input box. Now I would like to add a validation rule that requires the hidden field to be true to allow submit.
Preferably I would like to use unobtrusive validation, but if that doesn't work it is ok with something that requires some javascript, as long as it doesn't spoil the unobtrusive validation for the rest of the form.
The following code snippet does exactly what I want, until I add type="hidden".
<input class="required" id="client-searched" data-val="true"
name="ClientSearched" data-val-required="Press search!"/>
<span class="field-validation-valid" data-valmsg-replace="true"
data-valmsg-for="ClientSearched"/>
try
var validator = $("#myFormId").data('validator');
validator.settings.ignore = "";
Here is an informative blog post
EDIT
#RAM suggested a better solution please FOLLOW
I had a similar problem, and I used this code to change defaults, in MVC 4:
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$.validator.setDefaults({
ignore: ""
})
</script>
Source:
JQuery validate
In some cases you want just ignore validation on one or several
hidden fields (not all hidden field) in client side and also you want validate them and other hidden fields in server side.
In these cases you have validation attributes for all hidden fields in your ViewModel and they will be used to validate the form when you post it (server side).
Now you need a trick to just validate some of the hidden fields in client side (not all of them). In these cases i recommend you to use my mechanism!
Set data-force-val as true in the target hidden input tags. It's our custom attribute that we use to detect target hidden inputs witch we want validate them in client side.
// This hidden input will validate both server side & client side
<input type="hidden" value="" name="Id" id="Id"
data-val-required="The Id field is required."
data-val="true"
data-force-val="true">
// This hidden input will validate both server side & client side
<input type="hidden" value="" name="Email" id="Email"
data-val-required="The Email field is required."
data-val="true"
data-force-val="true">
// This hidden input just will validate server side
<input type="hidden" value="" name="Name" id="Name"
data-val-required="The Neme field is required."
data-val="true">
Also you can set data_force-val for your hidden inputs by jQuery:
$("#Id").attr("data-force-val", true); // We want validate Id in client side
$("#Email").attr("data-force-val", true); // We want validate Email in client side
$("#Name").attr("data-force-val", false); // We wont validate Name in client side (This line is not necessary, event we can remove it)
Now, active data-force-val="true" functionality by some simple codes like these:
var validator = $("#TheFormId").data('validator');
validator.settings.ignore = ":hidden:not([data-force-val='true'])";
Note: validator.settings.ignore default value is :hidden

Client side validation not working for hidden field in asp.net mvc 3

I have got a hidden field with a validation for it as below
#Html.HiddenFor(m => m.Rating)
#Html.ValidationMessageFor(m => m.Rating)
The Rating property has Range validator attribute applied with range being 1-5. This is put inside a form with a submit button.
I have then got following jquery that sets the value in hidden field on some user event (Basically user clicks on some stars to rate)
$(".star").click(function(){
$("#Rating").val(2);
});
Now if I submit the form without the user event that sets the hidden field, the validation works. The error messages is displayed properly and it works all client side.
Now, in this situation, if I click on stars, that invokes the above javascript a sets the hidden field, the validation error message would not go away. I can submit the form after the hidden variable has some valid value. But I'm expecting that the client side validation should work. (When the hidden variable has been set with some valid value, the validation error should go away)
Initially I thought, the jquery validation would be invoked on some special events so I tried raising click, change, keyup, blur and focusout events myself as below
$(".star").click(function(){
$("#Rating").val(2);
$("#Rating").change();
});
But this is still not working. The error messages once appeared, does not go away at all.
You can wrap your hidden field with a div put somewhere but still inside the <form>. Add css to kick it to outer space.
<div style="position:absolute; top:-9999px; left:-9999px">
<input id="Rating" type="hidden" name="rating" >
</div>
Then add the following label to where you want to show the error:
<label for="rating" class="error" style="display:none">I am an an error message, please modify me.</label>
Client-side validation ignores hidden fields. You can set the "ignore" option dynamically but just to get it to work I did the following directlyl in the .js file.
For now this should do the trick.
In my aspx...
<%: Html.HiddenFor(model => model.age, new { #class="formValidator" }) %>
In jquery.validate.js
ignore: ":hidden:not('.formValidator')",
This turned out to be a very interesting issue. the default "ignore" setting is ignores hidden fields. The field was hidden in a jQuery ui plug-in. I simply added a class called "includeCheckBox" to the rendered input I wanted to validate and put the following line of code in...
var validator = $('#formMyPita').validate();
validator.settings.ignore = ':hidden:not(".includeCheckBox")';
if ($('#formMyPita').valid()) {....
In the code which sets the hidden field's value, manually invoke validation for the form, like so:
$("form").validate().form();
I think it is because hidden inputs don't fire any of these events.
What you could do instead would be to use a <input type="text" style="display:none" /> instead of the hidden field;
#html.TextBoxFor(m => m.Rating, new {display = "display:none"})

Toggle validation in MVC 3 Razor

I'm using MVC 3 with razor as the view engine and the unobtrusive client validation enabled.
I'm trying to create a form where the user has a radio button group to select their preferred contact method - either phone or email. Depending on the option selected, I want to show the appropriate textbox, but then also enable/disable the required validator for the appropriate textbox.
My markup looks something like this at the moment (Just starting out with MVC so please point out any obvious mistakes):
<div id="prefferedContact">
<p>Preferred Contact Method *</p>
<input type="radio" id="contactMethodEmail" name="PreferredContactMethod" value="email" #if (Model.PreferredContactMethod != "phone"){<text>checked="checked"</text>} /> <label for="contactMethodEmail">by email</label>
<input type="radio" id="contactMethodPhone" name="PreferredContactMethod" value="phone" #if (Model.PreferredContactMethod == "phone"){<text>checked="checked"</text>} /> <label for="contactMethodPhone">by phone</label>
</div>
<div id="contactMethodDetails" class="formItem">
<div id="emailAddressBox">
#Html.LabelFor(x => x.Email, "Email address")
#Html.TextBoxFor(x => x.Email, new { #class = "textbox" })
</div>
<div id="phoneNumberBox">
#Html.LabelFor(x => x.PhoneNumber, "Phone number")
#Html.TextBoxFor(x => x.PhoneNumber, new { #class = "textbox" })
</div>
</div>
</div>
</div>
There's some jquery function that adds an onclick event to the radio buttons to toggle between the two boxes depending on the selected value.
The Model - for these specific fields - doesn't have any required validation on it at the moment but is binding fine. Also, validation is working on other fields as expected
I really just need to get an idea of:
(a) is it possible to toggle validation on and off
(b) does this impact the ModelState validation in anyway (or do I need to customise it)
I had also thought of having the one textbox for the contact data, but I wanted to have regular expression validation for the email and for the phone number separately. If I was to have a single textbox, could I switch the validation rules on the textbox depending on the selected option???
Hope that's clear enough with enough information.
Thanks
Joel
You can perform class-level validation if you need to enforce rules based on multiple properties:
http://weblogs.asp.net/scottgu/archive/2010/12/10/class-level-model-validation-with-ef-code-first-and-asp-net-mvc-3.aspx
Unfortunately, this seems to only work server-side, so you'd have to implement custom client-side validation.
Another option would be to have two different models, one for each scenario (with common properties in a base class), but this might be a little more complicated.

Resources