Usage
Server check uses the AJAX rule type. The server method is routed via
customParameters on validator.ajax.validate, set once in an
onPostInit handler rather than on every attempt; ui-validator-ajax-onbeforevalidation
just returns that call's field name and value. The response needs an isValid
boolean and, when invalid, a msg string, see the .NET tab for a working handler.
Where a field's HTML already expresses a constraint natively, required,
minlength/maxlength, pattern or a type
like email, Validator defers to the browser's checkValidity()
instead of duplicating the check. ui-validator-*-msg still registers the rule
and supplies the message, but the constraint value is only declared once, as seen below on
every required check, the SSN's length and digits-only pattern, the postal code's pattern,
and the email format.
Birthdate stays non-native on purpose: its range compares parsed dates against
dateFormat, which a native date input can't express, so
ui-validator-range-min/-max and
ui-validator-datatype-datatype="datetime" are doing real work here.
Confirm Password demonstrates COMPARE via ui-validator-compare-fields, matched
against Password (comma-separate for more fields; ui-validator-compare-operators
defaults to equality).
SSN, Password, Postal code and Server check use ui-tooltip-manager-id/ui-tooltip-id,
a FormField feature rather than Validator's, added only where the constraint isn't obvious.
FormField wires its own info icon as a tooltip trigger automatically, just add a matching
ui-template on the TooltipManager for each tooltipId.
<div
id="demoValidator"
ui-type="Validator"
ui-summary-container-id="summary"
ui-feedback-identifying-css-class="feedback"
ui-show-valid-fields="2"
ui-show-valid-fields-in-summary="true"
ui-message-display="3"
ui-summary-message-display="3"
ui-validating-field-message="Busy validating..."
ui-invalid-field-message="Invalid field value."
ui-friendly-field-names='{
"SocialSecurityNumber": "Social Security Number",
"Address.PostalCode": "Postal code",
"Address.Street": "Street",
"Address.StreetNumber": "Street number",
"Address.City": "City",
"ServerCheck": "Server check",
"ConfirmPassword": "Confirm password"
}'
ui-ajax='{ "validate": { "url": "DataServer" } }'
ui-events='{ "onPostInit": "$bindary.controller.validator.setup" }'>
</div>
<div id="tooltipManager" ui-type="TooltipManager"
ui-selectable-tooltip-content="true" ui-show-on-focus="true">
<div ui-template="ssnTooltip" ui-cloneable="false">
Must be exactly 9 digits, with no dashes or spaces.
</div>
<div ui-template="passwordTooltip" ui-cloneable="false">
Must be at least 6 characters long.
</div>
<div ui-template="postalCodeTooltip" ui-cloneable="false">
4 digits, optionally followed by a space and 2 letters, e.g. 1234 AB.
</div>
<div ui-template="serverCheckTooltip" ui-cloneable="false">
Only the value "test" is accepted, checked live against the server.
</div>
</div>
<div class="component-demo-columns">
<div>
<div id="name" ui-type="FormField"
ui-label="Name" ui-required="true" ui-label-display="3">
<div ui-template="Field">
<div>
<input type="text" name="Name" required
ui-validator-required-msg="This is a required field." />
<span class="feedback"></span>
</div>
</div>
</div>
<div id="surname" ui-type="FormField"
ui-label="Surname" ui-required="true" ui-label-display="3">
<div ui-template="Field">
<div>
<input type="text" name="Surname" required
ui-validator-required-msg="This is a required field." />
<span class="feedback"></span>
</div>
</div>
</div>
<div id="ssn" ui-type="FormField"
ui-label="Social Security Number" ui-required="true" ui-label-display="3"
ui-tooltip-manager-id="tooltipManager" ui-tooltip-id="ssnTooltip">
<div ui-template="Field">
<div>
<input type="text" name="SocialSecurityNumber" required
minlength="9" maxlength="9" pattern="\d+"
ui-validator-required-msg="This is a required field."
ui-validator-regex-msg="The SSN must consist of digits only."
ui-validator-length-msg="The SSN must consist of 9 digits." />
<span class="feedback"></span>
</div>
</div>
</div>
<div id="birthdate" ui-type="FormField"
ui-label="Birthdate" ui-required="true" ui-label-display="3">
<div ui-template="Field">
<div>
<input type="text" name="Birthdate"
ui-validator-required-msg="This is a required field."
ui-validator-datatype-datatype="datetime"
ui-validator-datatype-msg="Enter a valid date."
ui-validator-range-min="01/01/1900"
ui-validator-range-max="01/01/2010"
ui-validator-range-msg="Birthdate must fall
between 01/01/1900 and 01/01/2010." />
<span class="feedback"></span>
</div>
</div>
</div>
<div id="email" ui-type="FormField"
ui-label="Email" ui-label-display="3">
<div ui-template="Field">
<div>
<input type="email" name="Email"
ui-validator-datatype-msg="The email address is invalid." />
<span class="feedback"></span>
</div>
</div>
</div>
<div id="password" ui-type="FormField"
ui-label="Password" ui-required="true" ui-label-display="3"
ui-tooltip-manager-id="tooltipManager" ui-tooltip-id="passwordTooltip">
<div ui-template="Field">
<div>
<input type="password" name="Password" required minlength="6"
ui-validator-required-msg="This is a required field."
ui-validator-length-msg="Password must be at least 6 characters." />
<span class="feedback"></span>
</div>
</div>
</div>
<div id="confirmPassword" ui-type="FormField"
ui-label="Confirm Password" ui-required="true" ui-label-display="3">
<div ui-template="Field">
<div>
<input type="password" name="ConfirmPassword" required
ui-validator-required-msg="This is a required field."
ui-validator-compare-msg="Passwords do not match."
ui-validator-compare-fields="Password" />
<span class="feedback"></span>
</div>
</div>
</div>
</div>
<div>
<div id="postalCode" ui-type="FormField"
ui-label="Postal code" ui-required="true" ui-label-display="3"
ui-tooltip-manager-id="tooltipManager" ui-tooltip-id="postalCodeTooltip">
<div ui-template="Field">
<div>
<input type="text" name="Address.PostalCode" required
pattern="\d{4}|\d{4}\s?[A-Za-z]{2}"
ui-validator-required-msg="This is a required field."
ui-validator-regex-msg="The postal code is invalid." />
<span class="feedback"></span>
</div>
</div>
</div>
<div id="street" ui-type="FormField"
ui-label="Street" ui-required="true" ui-label-display="3">
<div ui-template="Field">
<div>
<input type="text" name="Address.Street" required
ui-validator-required-msg="This is a required field." />
<span class="feedback"></span>
</div>
</div>
</div>
<div id="streetNumber" ui-type="FormField"
ui-label="Street number" ui-required="true" ui-label-display="3">
<div ui-template="Field">
<div>
<input type="text" name="Address.StreetNumber" required
ui-validator-required-msg="This is a required field." />
<span class="feedback"></span>
</div>
</div>
</div>
<div id="city" ui-type="FormField"
ui-label="City" ui-required="true" ui-label-display="3">
<div ui-template="Field">
<div>
<input type="text" name="Address.City" required
ui-validator-required-msg="This is a required field." />
<span class="feedback"></span>
</div>
</div>
</div>
<div id="serverCheck" ui-type="FormField"
ui-label="Server check" ui-label-display="3"
ui-tooltip-manager-id="tooltipManager" ui-tooltip-id="serverCheckTooltip">
<div ui-template="Field">
<div>
<input name="ServerCheck" type="text"
ui-validator-ajax-msg="Only 'test' is accepted."
ui-validator-ajax-onbeforevalidation=
"$bindary.controller.validator.checkServerValue" />
<span class="feedback"></span>
</div>
</div>
</div>
</div>
</div>
<div id="submit" ui-type="Button"
ui-text="Submit" ui-command="$UI.store.demoValidator.validate"
style="margin-top: 20px; margin-bottom: 20px">
</div>
<div id="summary">
<h2>Summary</h2>
</div>
const validator = $UI.createComponent(componyx.UI.Validator,
{
id: 'demoValidator',
summaryContainerId: 'summary',
feedbackIdentifyingCssClass: 'feedback',
showValidFields: componyx.UI.Validator.ShowValidFieldsOption.FILLED,
showValidFieldsInSummary: true,
messageDisplay:
componyx.UI.Validator.MessageDisplayOption.FEEDBACKFIRST_TOOLTIPALL,
summaryMessageDisplay:
componyx.UI.Validator.MessageDisplayOption.FEEDBACKFIRST_TOOLTIPALL,
validatingFieldMessage: 'Busy validating...',
invalidFieldMessage: 'Invalid field value.',
friendlyFieldNames:
{
SocialSecurityNumber: 'Social Security Number',
'Address.PostalCode': 'Postal code',
'Address.Street': 'Street',
'Address.StreetNumber': 'Street number',
'Address.City': 'City',
ServerCheck: 'Server check',
ConfirmPassword: 'Confirm password'
},
ajax:
{
validate: { url: 'DataServer' }
},
rules:
[
{
fieldName: 'Name',
type: 0,
msg: 'This is a required field.'
},
{
fieldName: 'Surname',
type: 0,
msg: 'This is a required field.'
},
{
fieldName: 'SocialSecurityNumber',
type: 0,
msg: 'This is a required field.'
},
{
fieldName: 'SocialSecurityNumber',
type: 4,
msg: 'The SSN must consist of digits only.',
pattern: '^\\d+$'
},
{
fieldName: 'SocialSecurityNumber',
type: 2,
msg: 'The SSN must consist of 9 digits.',
min: 9,
max: 9
},
{
fieldName: 'Birthdate',
type: 0,
msg: 'This is a required field.'
},
{
fieldName: 'Birthdate',
type: 1,
msg: 'Enter a valid date.',
dataType: componyx.UI.Validator.DataTypeOption.DATETIME
},
{
fieldName: 'Birthdate',
type: 3,
msg: 'Birthdate must fall between 01/01/1900 and 01/01/2010.',
min: '01/01/1900',
max: '01/01/2010'
},
{
fieldName: 'Email',
type: 1,
msg: 'The email address is invalid.',
dataType: componyx.UI.Validator.DataTypeOption.EMAIL
},
{
fieldName: 'Password',
type: 0,
msg: 'This is a required field.'
},
{
fieldName: 'Password',
type: 2,
msg: 'Password must be at least 6 characters.',
min: 6
},
{
fieldName: 'ConfirmPassword',
type: 0,
msg: 'This is a required field.'
},
{
fieldName: 'ConfirmPassword',
type: 5,
msg: 'Passwords do not match.',
fields: ['Password']
},
{
fieldName: 'Address.PostalCode',
type: 0,
msg: 'This is a required field.'
},
{
fieldName: 'Address.PostalCode',
type: 4,
msg: 'The postal code is invalid.',
pattern: '(^\\d{4}$)|(^\\d{4}\\s?[A-Za-z]{2}$)'
},
{
fieldName: 'Address.Street',
type: 0,
msg: 'This is a required field.'
},
{
fieldName: 'Address.StreetNumber',
type: 0,
msg: 'This is a required field.'
},
{
fieldName: 'Address.City',
type: 0,
msg: 'This is a required field.'
},
{
fieldName: 'ServerCheck',
type: 7,
msg: "Only 'test' is accepted.",
onBeforeValidation: (sender, args) =>
({
validationFields:
[
{ fieldName: args.fieldName, value: args.fieldValue }
]
})
}
],
containerElement: document.body
});
validator.events.onPostInit.add($bindary.controller.validator.setup);
validator.show();
const tooltipManager = $UI.createComponent(componyx.UI.TooltipManager,
{
id: 'tooltipManager',
selectableTooltipContent: true,
showOnFocus: true,
containerElement: document.body
});
tooltipManager.addTooltip(
'ssnTooltip', 'Must be exactly 9 digits, with no dashes or spaces.');
tooltipManager.addTooltip(
'passwordTooltip', 'Must be at least 6 characters long.');
tooltipManager.addTooltip(
'postalCodeTooltip',
'4 digits, optionally followed by a space and 2 letters, e.g. 1234 AB.');
tooltipManager.addTooltip(
'serverCheckTooltip',
'Only the value "test" is accepted, checked live against the server.');
tooltipManager.show();
function createFormField(
container, label, required, template, tooltipId)
{
const formField = $UI.createComponent(componyx.UI.FormField,
{ containerElement: container });
formField.required = required || false;
formField.label = label;
formField.labelDisplay = componyx.UI.FormField.LabelDisplayOption.ABOVE;
formField.setFieldTemplate(template);
if (tooltipId)
{
formField.tooltipManagerId = 'tooltipManager';
formField.tooltipId = tooltipId;
}
formField.show();
return formField;
}
const nameTemplate =
'<div><input name="Name" type="text" />' +
'<span class="feedback"></span></div>';
createFormField(document.body, 'Name', true, nameTemplate);
const surnameTemplate =
'<div><input name="Surname" type="text" />' +
'<span class="feedback"></span></div>';
createFormField(document.body, 'Surname', true, surnameTemplate);
const ssnTemplate =
'<div><input name="SocialSecurityNumber" type="text" />' +
'<span class="feedback"></span></div>';
createFormField(
document.body, 'Social Security Number', true, ssnTemplate, 'ssnTooltip');
const birthdateTemplate =
'<div><input name="Birthdate" type="text" />' +
'<span class="feedback"></span></div>';
createFormField(document.body, 'Birthdate', true, birthdateTemplate);
const emailTemplate =
'<div><input name="Email" type="text" />' +
'<span class="feedback"></span></div>';
createFormField(document.body, 'Email', false, emailTemplate);
const passwordTemplate =
'<div><input name="Password" type="password" />' +
'<span class="feedback"></span></div>';
createFormField(
document.body, 'Password', true, passwordTemplate, 'passwordTooltip');
const confirmPasswordTemplate =
'<div><input name="ConfirmPassword" type="password" />' +
'<span class="feedback"></span></div>';
createFormField(document.body, 'Confirm Password', true, confirmPasswordTemplate);
const postalCodeTemplate =
'<div><input name="Address.PostalCode" type="text" />' +
'<span class="feedback"></span></div>';
createFormField(
document.body, 'Postal code', true, postalCodeTemplate, 'postalCodeTooltip');
const streetTemplate =
'<div><input name="Address.Street" type="text" />' +
'<span class="feedback"></span></div>';
createFormField(document.body, 'Street', true, streetTemplate);
const streetNumberTemplate =
'<div><input name="Address.StreetNumber" type="text" />' +
'<span class="feedback"></span></div>';
createFormField(document.body, 'Street number', true, streetNumberTemplate);
const cityTemplate =
'<div><input name="Address.City" type="text" />' +
'<span class="feedback"></span></div>';
createFormField(document.body, 'City', true, cityTemplate);
const serverCheckTemplate =
'<div><input name="ServerCheck" type="text" />' +
'<span class="feedback"></span></div>';
createFormField(
document.body, 'Server check', false, serverCheckTemplate, 'serverCheckTooltip');
const submit = $UI.createComponent(componyx.UI.Button,
{
text: 'Submit',
command: () => $UI.store.demoValidator.validate(),
style: 'margin-top: 20px; margin-bottom: 20px',
containerElement: document.body
});
submit.show();
const summary = document.body.appendChild(document.createElement('div'));
summary.id = 'summary';
summary.appendChild(document.createElement('h2')).textContent = 'Summary';
public static async Task CheckServerValue(
Client client, DataRequest request)
{
ValidatorAjaxRequest ajaxRequest =
JsonConvert.DeserializeObject<ValidatorAjaxRequest>(
request.Message);
ValidationField field =
ajaxRequest.ValidationFields?.FirstOrDefault();
bool isValid = field?.Value == "test";
var result = new
{
isValid,
msg = isValid ? null : "Only 'test' is accepted."
};
await Server.Send(
client, JsonConvert.SerializeObject(result), request.XhrRequestId);
}
public class ValidatorAjaxRequest
{
public List<ValidationField> ValidationFields { get; set; }
}
public class ValidationField
{
public string FieldName { get; set; }
public string Value { get; set; }
}
messageDisplay and summaryMessageDisplay accept the numeric
componyx.UI.Validator.MessageDisplayOption enum: 0 None, 1 FeedbackFirst,
2 FeedbackAll, 3 FeedbackFirst_TooltipAll, 4 TooltipFirst, 5 TooltipAll.
showValidFields accepts componyx.UI.Validator.ShowValidFieldsOption:
0 None, 1 Required, 2 Filled, 3 All.
The JS API doesn't read per-field ui-validator-* attributes, rules are
assigned centrally via the rules array on the Validator itself instead
(each entry's type is the numeric componyx.UI.Validator.TypeOption:
0 Required, 1 DataType, 2 Length, 3 Range, 4 Regex, 5 Compare, 6 Custom, 7 Ajax). Native
HTML attributes like required or pattern can still be put
directly in the template strings above, Validator picks them up the same way either way.