React Common - Data Validation
This guide provides the detailed information on validation capabilities of DevExtreme editors. It describes how to validate a single editor or a group of editors, display the validation summary, perform remote validation, use a custom validation engine, etc.
Validate an Editor Value
Associate a DevExtreme editor with the Validator widget and specify validationRules to validate the editor. The full list of predefined validation rules is available in the Validation Rules Reference section.
jQuery
$(function () { $("#login").dxTextBox({ value: '', placeholder: 'Login' }).dxValidator({ validationRules: [{ type: 'required' }, { type: 'pattern', pattern: '^[a-zA-Z]+$', message: 'Do not use digits.' }] }); });
<div>Login:</div> <div id="login"></div>
Angular
import { DxTextBoxModule, DxValidatorModule } from "devextreme-angular"; // ... export class AppComponent { login: string = ''; loginRules = [{ type: 'required' }, { type: 'pattern', pattern: '^[a-zA-Z]+$', message: 'Do not use digits.' }]; } @NgModule({ imports: [ // ... DxTextBoxModule, DxValidatorModule ], // ... })
<dx-text-box [(value)]="login" placeholder="Login"> <dx-validator [validationRules]="loginRules"></dx-validator> </dx-text-box>
AngularJS
function Controller ($scope) { $scope.login = ''; $scope.loginRules = [{ type: 'required' }, { type: 'pattern', pattern: '^[a-zA-Z]+$', message: 'Do not use digits.' }]; }
<div dx-text-box="{ value: login, placeholder: 'Login' }", dx-validator="{ validationRules: loginRules }"> </div>
Knockout
var viewModel = { login: ko.observable(""), loginRules: [{ type: 'required' }, { type: 'pattern', pattern: '^[a-zA-Z]+$', message: 'Do not use digits.' }] }; ko.applyBindings(viewModel);
<div data-bind="dxTextBox: { value: login, placeholder: 'Login' }, dxValidator: { validationRules: loginRules }"> </div>
Group the Editors
Editors belonging to a single Validation Group can be validated together. All editors on a page are automatically collected in a Default Validation Group, which is suitable when you do not need to validate collections of editors separately. In other cases, define Validation Groups as shown in the following code:
jQuery
$(function () { var loginGroup = "loginGroup"; $("#login") .dxTextBox({ /* ... */ }) .dxValidator({ // ... validationGroup: loginGroup }); $("#password") .dxTextBox({ /* ... */ }) .dxValidator({ // ... validationGroup: loginGroup }); });
<div id="login"></div> <div id="password"></div>
Angular
<dx-validation-group id="loginGroup"> <dx-text-box [(value)]="login" ... > <dx-validator ... ></dx-validator> </dx-text-box> <dx-text-box [(value)]="password" ... > <dx-validator ... ></dx-validator> </dx-text-box> </dx-validation-group>
import { DxTextBoxModule, DxValidatorModule, DxValidationGroupModule } from "devextreme-angular"; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxTextBoxModule, DxValidatorModule, DxValidationGroupModule ], // ... })
AngularJS
<div id="loginGroup" dx-validation-group="{ }"> <div dx-text-box="{ value: login, ... }", dx-validator="{ ... }"> </div> <div dx-text-box="{ value: password, ... }", dx-validator="{ ... }"> </div> </div>
Knockout
<div id="loginGroup" data-bind="dxValidationGroup: { }"> <div data-bind="dxTextBox: { value: login, ... }, dxValidator: { ... }"> </div> <div data-bind="dxTextBox: { value: password, ... }, dxValidator: { ... }"> </div> </div>
Validate the Group
You can validate any group by calling its validate() method in a Button's onClick event handler. You can access the Validation Group via the handler's argument. The Button always validates the group to which it belongs. If the membership is not specified, the Button validates the Default Validation Group.
jQuery
$(function () { // var loginGroup = "loginGroup"; $("#login") .dxTextBox({ /* ... */ }) .dxValidator({ // validationGroup: loginGroup, validationRules: [ /* ... */ ] }); $("#password") .dxTextBox({ /* ... */ }) .dxValidator({ // validationGroup: loginGroup, validationRules: [ /* ... */ ] }); $("#loginButton").dxButton({ text: "Login", // validationGroup: loginGroup onClick: function (e) { var result = e.validationGroup.validate(); if (result.isValid) { // ... } } }); });
<div id="login"></div> <div id="password"></div> <div id="loginButton"></div>
Angular
<!-- dx-validation-group id="loginGroup" --> <dx-text-box [(value)]="login" ... > <dx-validator [validationRules]="..."></dx-validator> </dx-text-box> <dx-text-box [(value)]="password" ... > <dx-validator [validationRules]="..."></dx-validator> </dx-text-box> <dx-button text="Login" (onClick)="loginClick($event)"></dx-button> <!-- /dx-validation-group -->
import { DxTextBoxModule, DxValidatorModule, /* DxValidationGroupModule */ } from "devextreme-angular"; // ... export class AppComponent { // ... loginClick: function (e) { var result = e.validationGroup.validate(); if (result.isValid) { // ... } } } @NgModule({ imports: [ // ... DxTextBoxModule, DxValidatorModule, // DxValidationGroupModule ], // ... })
AngularJS
<!-- div id="loginGroup" dx-validation-group="{ }" --> <div dx-text-box="{ value: login, ... }", dx-validator="{ validationRules: [ ... ] }"> </div> <div dx-text-box="{ value: password, ... }", dx-validator="{ validationRules: [ ... ] }"> </div> <div dx-button="{ text: 'Login', onClick: loginClick }"></div> <!-- /div -->
function Controller($scope) { // ... $scope.loginClick = function (e) { var result = e.validationGroup.validate(); if (result.isValid) { // ... } }; }
Knockout
<!-- div id="loginGroup" data-bind="dxValidationGroup: { }" --> <div data-bind="dxTextBox: { value: login, ... }, dxValidator: { validationRules: [ ... ] }"> </div> <div data-bind="dxTextBox: { value: password, ... }, dxValidator: { validationRules: [ ... ] }"> </div> <div data-bind="dxButton: { text: 'Login', onClick: loginClick }></div> <!-- /div -->
var viewModel = { // ... loginClick: function (e) { var result = e.validationGroup.validate(); if (result.isValid) { // ... } } }; ko.applyBindings(viewModel);
Alternatively, you can validate a group using the DevExpress.validationEngine.validateGroup method. Call it without arguments to validate the Default Validation Group:
DevExpress.validationEngine.validateGroup();
... or pass the group instance to validate a named group:
DevExpress.validationEngine.validateGroup($("#loginGroup").dxValidationGroup("instance"));
Pass the group name instead of the instance if you have created widgets using jQuery.
DevExpress.validationEngine.validateGroup("loginGroup");
Display Validation Errors
All group validation errors can be displayed in the ValidationSummary widget. The following code shows how to add this widget to a page. The commented-out codelines associate the Validation Summary with a named Validation Group.
jQuery
$(function () { // var loginGroup = "loginGroup"; $("#summary").dxValidationSummary({ // validationGroup: loginGroup }); });
... <div id="summary"></div>
Angular
<!-- dx-validation-group id="loginGroup" --> ... <dx-validation-summary></dx-validation-summary> <!-- /dx-validation-group -->
import { ..., /* DxValidationGroupModule */, DxValidationSummaryModule } from "devextreme-angular"; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... // DxValidationGroupModule, DxValidationSummaryModule ], // ... })
AngularJS
<!-- div id="loginGroup" dx-validation-group="{ }" --> ... <div dx-validation-summary="{ }"></div> <!-- /div -->
Knockout
<!-- div id="loginGroup" data-bind="dxValidationGroup: { }" --> <div data-bind="dxValidationSummary: { }"></div> <!-- /div -->
Server-Side Validation
Use the "custom" validation rule that allows you to implement a custom validation function for server-side validation. In this function, perform an AJAX request and, when it succeeds, update the validation state and error message.
jQuery
$(function() { var validateLogin = function (params) { $.ajax({ url: "http://www.example.com/services/validate-login", method: "POST", data: { login: params.value }, success: function (result) { params.rule.isValid = result.Result; params.rule.message = result.Message; params.validator.validate(); } }) // Validation result until the response is received return false; }; $("#login").dxTextBox({ value: "", placeholder: 'Login' }).dxValidator({ validationRules: [{ type: 'required', message: 'Login is required' }, { type: 'custom', validationCallback: validateLogin }] }); });
<div id="login"></div>
Angular
import { HttpClient } from '@angular/common/http'; import { DxTextBoxModule, DxValidatorModule } from "devextreme-angular"; // ... export class AppComponent { constructor(private http: HttpClient) { this.validateLogin = this.validateLogin.bind(this); } login: string = ""; validateLogin(params) { this.http.post( "http://www.example.com/services/validate-login", { login: params.value } ).subscribe(response => { params.rule.isValid = response["Result"]; params.rule.message = response["Message"]; params.validator.validate(); }); // Validation result until the response is received return false; } } @NgModule({ imports: [ // ... DxTextBoxModule, DxValidatorModule ], // ... })
<dx-text-box [(value)]="login" placeholder="Login"> <dx-validator> <dxi-validation-rule type="required" message="Login is required"> </dxi-validation-rule> <dxi-validation-rule type="custom" [validationCallback]="validateLogin"> </dxi-validation-rule> </dx-validator> </dx-text-box>
AngularJS
angular.module('DemoApp', ['dx']) .controller('demoController', function ($scope) { $scope.validateLogin = function (params) { $.ajax({ url: "http://www.example.com/services/validate-login", method: "POST", data: { login: params.value }, success: function (result) { params.rule.isValid = result.Result; params.rule.message = result.Message; params.validator.validate(); } }) // Validation result until the response is recieved return false; }; $scope.login = ""; $scope.loginRules = [{ type: 'required', message: 'Login is required' }, { type: "custom", validationCallback: validateLogin }]; });
<div ng-controller="demoController"> <div dx-text-box="{ placeholder: 'Login' bindingOptions: { value: 'login' } }", dx-validator="{ validationRules: loginRules }"> </div> </div>
Knockout
var viewModel = { validateLogin: function (params) { $.ajax({ url: "http://www.example.com/services/validate-login", method: "POST", data: { login: params.value }, success: function (result) { params.rule.isValid = result.Result; params.rule.message = result.Message; params.validator.validate(); } }) // Validation result until the response is recieved return false; }, login: ko.observable(""), loginRules: [{ type: 'required', message: 'Login is required' }, { type: "custom", validationCallback: validateLogin }] } ko.applyBindings(viewModel);
<div data-bind="dxTextBox: { value: login, placeholder: 'Login' }, dxValidator: { validationRules: loginRules }"> </div>
Validate a Custom Value
You can use the DevExtreme validation engine to validate a custom value, for example, a non-DevExtreme editor value or a concatenation of several editor values, by configuring the Validator's adapter option. The following example creates two text boxes and a button. A button click checks that at least one of these text boxes is filled. Their values are concatenated in the getValue function.
jQuery
$(function () { var callbacks = []; var phone = $("#phone").dxTextBox({ placeholder: "Phone", onValueChanged: function (e) { callbacks.forEach(func => { func(); }); // Commences validation } }).dxTextBox("instance"); var email = $("#email").dxTextBox({ type: "email", placeholder: "Email", onValueChanged: function (e) { callbacks.forEach(func => { func(); }); // Commences validation } }).dxTextBox("instance"); $("#validator").dxValidator({ validationRules: [{ type: "required", message: "Specify your phone or email" }], adapter: { getValue: function () { return phone.option("value") + email.option("value"); }, applyValidationResults: function (e) { $("#contacts").css({ "border": e.isValid ? "none" : "1px solid red" }); }, validationRequestsCallbacks: callbacks } }); $("#button").dxButton({ text: "Contact me", onClick: function (e) { e.validationGroup.validate(); } }); $("#summary").dxValidationSummary({ }); });
<div id="contacts"> <div id="phone"></div> <div id="email"></div> <div id="validator"></div> <div id="summary"></div> <div id="button"></div> </div>
Angular
import { DxTextBoxModule, DxValidatorModule, DxValidationSummaryModule, DxButtonModule } from "devextreme-angular"; // ... export class AppComponent { callbacks = []; phone: string = ""; email: string = ""; borderStyle: string = "none"; rules = [{ type: "required", message: "Specify your phone or email" }]; adapterConfig = { getValue: () => { return this.phone + this.email; }, applyValidationResults: (e) => { this.borderStyle = e.isValid ? "none" : "1px solid red"; }, validationRequestsCallbacks: this.callbacks }; revalidate () { this.callbacks.forEach(func => { func(); }); }; submit (e) { e.validationGroup.validate(); } } @NgModule({ imports: [ // ... DxTextBoxModule, DxValidatorModule, DxValidationSummaryModule, DxButtonModule ], // ... })
<div id="contacts" [style.border]="borderStyle"> <dx-text-box [(value)]="phone" placeholder="Phone" (onValueChanged)="revalidate()"> </dx-text-box> <dx-text-box [(value)]="email" type="email" placeholder="Email" (onValueChanged)="revalidate()"> </dx-text-box> <dx-validator [validationRules]="rules" [adapter]="adapterConfig"> </dx-validator> <dx-validation-summary></dx-validation-summary> <dx-button text="Contact me" (onClick)="submit($event)"> </dx-button> </div>
AngularJS
angular.module('DemoApp', ['dx']) .controller('demoController', function ($scope) { $scope.callbacks = []; $scope.phone = ""; $scope.email = ""; $scope.borderStyle = "none"; $scope.rules = [{ type: "required", message: "Specify your phone or email" }]; $scope.adapterConfig = { getValue: function () { return $scope.phone + $scope.email; }, applyValidationResults: function (e) { $scope.borderStyle = e.isValid ? "none" : "1px solid red"; }, validationRequestsCallbacks: $scope.callbacks }; $scope.revalidate = function () { $scope.callbacks.forEach(func => { func(); }) }; $scope.submit = function (e) { e.validationGroup.validate(); } });
<div ng-controller="demoController"> <div id="contacts" ngStyle="borderStyle"> <div dx-text-box="{ placeholder: 'Phone', onValueChanged: revalidate, bindingOptions: { value: 'phone' } }"></div> <div dx-text-box="{ placeholder: 'Email', onValueChanged: revalidate, bindingOptions: { value: 'email' } }"></div> <div dx-validator="{ validationRules: rules, adapter: adapterConfig }"></div> <div dx-validation-summary="{ }"></div> <div dx-button= "{ text: 'Contact me', onClick: submit }"></div> </div> </div>
Knockout
callbacks = []; var viewModel = { phone: ko.observable(""), email: ko.observable(""), borderStyle: ko.observable("none"), rules: [{ type: "required", message: "Specify your phone or email" }], adapterConfig: { getValue: function () { return viewModel.phone() + viewModel.email(); }, applyValidationResults: function (e) { viewModel.borderStyle(e.isValid ? "none" : "1px solid red"); }, validationRequestsCallbacks: callbacks }, revalidate: function () { callbacks.forEach(func => { func(); }) }, submit: function (e) { e.validationGroup.validate(); } } ko.applyBindings(viewModel);
<div id="contacts" data-bind="style: { border: borderStyle }"> <div data-bind="dxTextBox: { placeholder: 'Phone', onValueChanged: revalidate, value: phone }"></div> <div data-bind="dxTextBox: { placeholder: 'Email', onValueChanged: revalidate, value: email }"></div> <div data-bind="dxValidator: { validationRules: rules, adapter: adapterConfig }"></div> <div data-bind="dxValidationSummary: { }"></div> <div data-bind="dxButton:{ text: 'Contact me', onClick: submit }"></div> </div>
Use a Custom Validation Engine
Each DevExtreme editor allows changing its validation state and error message using the isValid and validationError options, which enables you to use any validation engine or custom validation logic. The following example shows a custom function called validateLogin validating a text box value:
jQuery
$(function () { var validateLogin = function (params) { if (params.value === "") { params.component.option({ validationError: { message: "Login cannot be empty" }, isValid: false }); return; } if (!e.value.match(/^[a-zA-Z0-9]+$/)) { params.component.option({ validationError: { message: "Login contains unexpected characters" }, isValid: false }); return; } params.component.option("isValid", true); } $("#login").dxTextBox({ placeholder: "Enter login", onValueChanged: validateLogin }) });
<div id="login"></div>
Angular
import { DxTextBoxModule } from "devextreme-angular"; // ... export class AppComponent { login: string = ""; isLoginValid: boolean = true; loginValidationError: Object = {}; validateLogin = function (params) { if (login === "") { loginValidationError = { message: "Login cannot be empty" }; isLoginValid = false; return; } if (!login.match(/^[a-zA-Z0-9]+$/)) { loginValidationError = { message: "Login contains unexpected characters" }; isLoginValid = false; return; } isLoginValid = true; }; } @NgModule({ imports: [ // ... DxTextBoxModule ], // ... })
<dx-text-box [(value)]="login" placeholder="Login" [(isValid)]="isLoginValid" [(validationError)]="loginValidationError" (onValueChanged)="validateLogin($event)"> </dx-text-box>
AngularJS
angular.module('DemoApp', ['dx']) .controller('demoController', function ($scope) { $scope.login = ""; $scope.isLoginValid = true; $scope.loginValidationError = {}; $scope.validateLogin = function (params) { if ($scope.login === "") { $scope.loginValidationError = { message: "Login cannot be empty" }; $scope.isLoginValid = false; return; } if (!$scope.login.match(/^[a-zA-Z0-9]+$/)) { $scope.loginValidationError = { message: "Login contains unexpected characters" }; $scope.isLoginValid = false; return; } $scope.isLoginValid = true; }; });
<div ng-controller="demoController"> <div dx-text-box="{ placeholder: 'Login', onValueChanged: 'validateLogin($event)' bindingOptions: { value: 'login', isValid: 'isLoginValid', validationError: 'loginValidationError' } }"></div> </div>
Knockout
var viewModel = { login: ko.observable(""), isLoginValid: ko.observable(true), loginValidationError: ko.observable({}), validateLogin: function (params) { if (this.login () === "") { this.loginValidationError({ message: "Login cannot be empty" }); this.isLoginValid(false); return; } if (!this.login ().match(/^[a-zA-Z0-9]+$/)) { this.loginValidationError({ message: "Login contains unexpected characters" }); this.isLoginValid(false); return; } this.isLoginValid(true); } } ko.applyBindings(viewModel);
<div data-bind="dxTextBox: { value: login, placeholder: 'Login', onValueChanged: validateLogin isValid: isLoginValid, validationError: loginValidationError }"> </div>
Knockout Only - Validate a View Model
Validating the view model object rather than the editors allows you to separate validation logic from the UI, reuse it between multiple views and unit-test the implementation. To validate a view model's observable, extend it with an object whose dxValidator field contains the validator configuration. After that, associate a target editor with the validator using the isValid and validationError options.
$(function () { var viewModel = { login: ko.observable("").extend({ dxValidator: { validationRules: [{ type: 'required', message: 'Login is required' }] } }), password: ko.observable("").extend({ dxValidator: { name: "Password", validationRules: [{ type: 'required' }] } }) }; ko.applyBindings(viewModel); });
<div data-bind="dxTextBox: { value: login, placeholder: 'Login', isValid: login.dxValidator.isValid, validationError: login.dxValidator.validationError }"></div> <div data-bind="dxTextBox: { value: password, mode: 'password', placeholder: 'Password', isValid: password.dxValidator.isValid, validationError: password.dxValidator.validationError }"></div>
Finally, pass the to the DevExpress.validationEngine.registerModelForValidation(model) method to register it in the validation engine. The registered view model can be validated at any point in your application by calling the DevExpress.validationEngine.validateModel(model) method.
var viewModel = { //... validateAndLogin: function (params) { var result = DevExpress.validationEngine.validateModel(this); if (result.isValid) { // ... } } }; DevExpress.validationEngine.registerModelForValidation(viewModel); ko.applyBindings(viewModel);
If you have technical questions, please create a support ticket in the DevExpress Support Center.