Input validation message toggle for blur and focusIn - antd

I want to trigger the validation only for input "blur" instead of typing on it. So I have used the method validateTrigger:'onBlur' and its worked fine for me as expected. After user focus/click again the input, the validation message should disappear, any solution?
<FormItem>
{getFieldDecorator('email', {
rules: [
{
type: 'email', message: 'Valid E-mail required!',
},
{ required: true, message: 'E-mail required!', whitespace:true }
],
validateTrigger:'onBlur'
})(
<Input
placeholder="Email"
/>
)}

This can be done by using ant design validateStatus parameter. You can dynamically change the statuses from given sets, i.e, 'success', 'warning', 'error', 'validating'.
validateStatus: validate status of form components which could be 'success', 'warning', 'error', 'validating'.
You need to functions, one onBlur and other onFocus. FormItem can be written as:
<FormItem
validateStatus={this.state.showError && userNameError ? "error" : ""}
help={
this.state.showError && userNameError
? "Valid E-mail required!"
: ""
}
>
{getFieldDecorator("userName", {
validateTrigger: "onBlur",
rules: [
{ type: "email", message: "Valid E-mail required!" },
{ required: true, message: "Please input your username!" }
]
})(
<Input
placeholder="Email"
onBlur={this.handleBlur}
onFocus={this.handleFocus}
/>
)}
</FormItem>
And the two methods can be written as:
handleBlur = e => {
this.setState({ showError: true });
};
handleFocus = e => {
this.setState({ showError: false });
};
Working demo is on codesandbox.io.

Related

Yup compare fields validation with react hook form

I've been using React hook form and have a compare validation written on the input itself.
I need to move over to Yup validation lib as others on the project are using it so for consistency. Here is what I currently have that is working but having problems when I use a yup.schema.
const {
register,
setValue,
getValues,
formState: { errors, isValid },
clearErrors,
trigger,
} = useForm({
mode: 'onBlur',
defaultValues: {
password: '',
compare: '',
},
})
return(
<div>
<Input
name='password'
{...register('password', { required: true })}
<Input
name='compare'
{...register('compare', {
validate: (value: string) => {
const { password} = getValues()
return password === value || ''
},
})}
</div>
)
As I said this above works but now I thought I could add a schema but that breaks all what I have so I'm trying to figure out how I can achieve this using yup schema.
const schema = yup.object().shape({
password: yup.string().required(),
compare: yup.string().test(
'compare',
(field) => {
... not sure how to compare against another filed here ?
}
),
})
const {
register,
setValue,
getValues,
formState: { errors, isValid },
clearErrors,
trigger,
} = useForm({
mode: 'onBlur',
resolver: yupResolver(schema),
defaultValues: {
password: '',
compare: '',
},
})

How to dynamically disable the button of antd modal using button props

I have an antd Modal, i am trying to validate a field and provided validation to it. How can i enable/disable the Ok button based on the validation. If the validation is successful then button should be enabled else disabled.
<Form>
<Modal
title={modalHeader}
okText="ADD FIELD"
cancelText="CANCEL"
visible={visible}
onCancel={onCancelHandler}
onOk={() => onAddFieldHandler(fieldName)}
width={600}
okButtonProps={{disabled:true}}
>
<p>Please provide name</p>
<Form.Item
name="fieldName"
rules={[{ required: true, message: 'Please enter name' }]}
>
<FieldNameInput
placeholder="Field name..."
value={fieldName}
onChange={(event) => setFieldName(event.target.value)}
/>
</Form.Item>
</Modal>
</Form>
You can use onFieldsChange from Antd Forms API togehter with geFieldsError and the okButtonProps from Antd Modal API.
const [form] = Form.useForm();
const [buttonDisabled, setButtonDisabled] = useState(true);
return (
<Modal
...
okButtonProps={{ disabled: buttonDisabled }}
>
<Form
form={form}
...
onFieldsChange={() =>
setButtonDisabled(
form.getFieldsError().some((field) => field.errors.length > 0)
)
}
>
Here is a working Stackblitz.
In my case I had Form inside modal and there is onFieldChange prop when you can pass function to perform some operations due to changes on from so you can sth like that:
const SomeModal = ({ visible }) => {
const [form] = Form.useForm();
const [buttonDisabled, setButtonDisabled] = useState(true);
const handleOk = () => form.submit();
const handleAfterClose = () => {
setButtonDisabled(true);
form.resetFields();
}
const handleCancel = () => ...some action to hide modal;
const handleFormFinish = (values) => {
... some logic here
}
return (
<Modal
title={"Some title..."}
visible={visibile}
onOk={handleOk}
onCancel={handleCancel}
afterClose={handleAfterClose}
okButtonProps={{ disabled: buttonDisabled }}
>
<Form
form={form}
layout="vertical"
name="acceptform"
onFinish={handleFormFinish}
initialValues={{
...initial values here
}}
onFieldsChange={() => {
const actualFieldValues = form.getFieldsValue();
const anyError = form.getFieldsError().some((field) => field.errors.length > 0);
.. some logic if error etc..
if (anyError) {
setButtonDisabled(true);
}
else {
setButtonDisabled(false);
}
}}
>
and of course there is need to have some validators on fields
<Form.Item
label={"someLabel"}
id="field"
name="field"
hasFeedback
rules={[
{
type: "string",
validator: async (rule, value) => inputFieldValidate(value, "custom message")
},
]}
>
and validator looks alike:
const inputFieldValidate = async (value, message) => {
if (someCondition)) {
return Promise.reject(message);
}
return Promise.resolve();
};
here is some nice to know that validator isasync and to make it work without any warnings just handle promises
Having the Form inside the Modal, a way to update modal button status would be just running form instance's validateFields, but there are two things to take into account:
This function is a Promise, so the state must update after an await with the validation results.
I've experienced some looping issues when using onFieldsChange (maybe the validation triggers some kind of field update). Instead, onValuesChange has worked good enough for me.
Running the validation into a setTimeout callback seems to be mandatory. Doing it without the setTimeout returns a validation error even when all the fields are valid because of an outOfDate: true. It seems to be because of how the Antd Form update lifecycle works, and waiting until this process has ended (what we can easily achieve with the setTimeout) solves that problem.
A succesful validation returns the form values object, a failed one returns an errorInfo object with the errors list, the outOfDate status and the current form values. You can use the errors list in the latter to get the validation messages returned by Antd to display more descriptive and specific feedback.
In the end, my approach has this structure:
const MyModal = ({onFinish, ...otherProps}) => {
const [canSubmit, setCanSubmit] = useState(false);
const [form] = Form.useForm();
return (
<Modal
{...otherProps}
okButtonProps={{
disabled: !canSubmit
}}
>
<MyFormComponent
form={form}
onFinish={onFinish}
onValuesChange={() => {
setTimeout(() => {
form
.validateFields()
.then(() => {
/*
values:
{
username: 'username',
password: 'password',
}
*/
setCanSubmit(true);
})
.catch((err) => {
/*
errorInfo:
{
values: {
username: 'username',
password: 'password',
},
errorFields: [
{ name: ['password'], errors: ['Please input your Password!'] },
],
outOfDate: false,
}
*/
setCanSubmit(false);
});
});
}}
/>
</Modal>
);
};

filter the ui grid value based on the row check box is selected

This is the ui grid code( minimal)
//js file
vm.gridOptions1 = {
enableColumnResizing: true,
enableAutoResizing: false,
columnDefs: [
{
field: 'createdDate',
displayName: 'Created Date',
type: 'date',
cellFilter: 'date:"dd-MM-yyyy"',
enableHiding: false, headerTooltip: 'Created Date'
},{
name: 'Refer',
displayName: 'Refer', enableSorting: false, headerTooltip: 'Refer',
cellTemplate: '<input type="checkbox" ng-model="row.entity.isReferred" />'
}
]});
On click of this byutton I need to filter, get only rows which check box is selected(isReferred = true)
//html file
<button type="button" class="btn btn-primary-joli " ng-click="srchctrl.send">Send</button>
This is the file trying to get the filtered list based on the redeffered check box value, but its not working.
//JS file
vm.send = function () {
if (vm.gridApi.selection.data != null && vm.gridApi.selection.data != undefined) {
vm.referredList = filterFilter(vm.gridApi.selection.data, {
isReferred: true
});
console.log("referredList :"+JSON.stringify(referredList));
}
};
How can I get all the value ticked. I don't want to invoke method on each click event on check box.
I think the easiest way to achieve this is by using the gridApi.grid.registerRowsProcessor function. I have adapted a Plunker to show what I mean:
http://plnkr.co/edit/lyXcb90yQ0ErUJnSH7yF
Apps.js:
var app = angular.module('plunker', ['ui.grid']);
app.controller('MainCtrl', ['$scope', 'uiGridConstants', function($scope, uiGridConstants) {
$scope.gridOptions = {
columnDefs: [
{field: 'col1', displayName: 'Column 1', width: 175},
{field: 'col2', displayName: 'isReferred', width: '*'}
],
data: [
{ col1: "Hello 1",col2: true},
{ col1: "Hello 2", col2: false},
{ col1: "Hello 3", col2: true},
{ col1: "Hello 4", col2: false},
{ col1: "Hello 5", col2: true}
],
enableFiltering: true,
onRegisterApi: function(gridApi) {
$scope.gridApi = gridApi;
}
};
$scope.Filter = Filter;
$scope.ShowAll = ShowAll;
function ShowAll() {
$scope.gridApi.grid.removeRowsProcessor(myFilter);
$scope.gridApi.core.queueGridRefresh();
}
function Filter() {
$scope.gridApi.grid.registerRowsProcessor(myFilter, 150);
$scope.gridApi.core.queueGridRefresh();
}
function myFilter(renderableRows) {
renderableRows.forEach( function(row) {
row.visible = row.entity.col2;
});
return renderableRows;
}
}]);
Clicking the Filter button will register the myFilter RowsProcessor, which will iterate through all rows to alter the visible attribute.
Clicking the ShowAll button will remove the RowsProcessor, thus showing all previously hidden rows again.
Whenever an isReferred value changes, the filter will cause the grid to automatically update this change.

Ant Design. How to set form field error message dynamically?

A form field has many asynchronous check rules, since a composited api can check these rules one time by return different result, i do not want to fire so many api request.
the syntax is updated in v4
new syntax is:
setFields. | Set fields status | (fields: FieldData[]) => void
example :
form.setFields([
{
name: 'field-to-update',
errors: ['error-string'],
},
]);
Use form.setFields
Syntax
Function({ fieldName: { value: any, errors: Error } })
Example from here -
this.props.form.setFields({
user: {
value: values.user,
errors: [new Error('forbid ha')],
},
});
When you need to add a custom error message just use validateStatus && help attributes.
For example, you've got an error as loginError (string) in your props:
<Form.Item
{ ...props.loginError && {
help: props.loginError,
validateStatus: 'error',
}}>
{getFieldDecorator('email', {
rules: [
{ required: true, message: 'You have to write the email' },
],
})(
<Input size="large"/>,
)}
</Form.Item>
form.setFields([
{
name: "email", // required
value: "myemail##gmail.com",//optional
errors: ["Invalid email"],
},
]);
I used it in v4.16.11

jQuery Validation error

I have been struggling with this jQuery Validation Plugin.
Here is the code:
<script type="text/javascript">
$(function() {
var validator = $('#signup').validate({
errorElement: 'span',
rules: {
username: {
required: true,
minlenght: 6
//remote: "check-username.php"
},
password: {
required: true,
minlength: 5
},
confirm_password: {
required: true,
minlength: 5,
equalTo: "#password"
},
email: {
required: true,
email: true
},
agree: "required"
},
messages: {
username: {
required: "Please enter a username",
minlength: "Your username must consist of at least 6 characters"
//remote: "Somenoe have already chosen nick like this."
},
password: {
required: "Please provide a password",
minlength: "Your password must be at least 5 characters long"
},
confirm_password: {
required: "Please provide a password",
minlength: "Your password must be at least 5 characters long",
equalTo: "Please enter the same password as above"
},
email: "Please enter a valid email address",
agree: "Please accept our policy"
}
});
var root = $("#wizard").scrollable({size: 1, clickable: false});
// some variables that we need
var api = root.scrollable();
$("#data").click(function() {
validator.form();
});
// validation logic is done inside the onBeforeSeek callback
api.onBeforeSeek(function(event, i) {
if($("#signup").valid() == false){
return false;
}else{
return true;
}
$("#status li").removeClass("active").eq(i).addClass("active");
});
//if tab is pressed on the next button seek to next page
root.find("button.next").keydown(function(e) {
if (e.keyCode == 9) {
// seeks to next tab by executing our validation routine
api.next();
e.preventDefault();
}
});
$('button.fin').click(function(){
parent.$.fn.fancybox.close()
});
});
</script>
And here is the error:
$.validator.methods[method] is undefined
/js/jquery-validate/jquery.validate.min.js
Line 15
I am completely confused... Maybe some kind of handler is needed?
I would be grateful for any kind of answer.
I think it is simply a typo:
minlenght: 6
should be
minlength: 6

Resources