JavaScript/jQuery 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.

View Demo

Validate an Editor Value

Associate a DevExtreme editor with the Validator UI component and specify validationRules to validate the editor. The full list of predefined validation rules is available in the Validation Rules Reference section.

jQuery
JavaScript
HTML
$(function () {
    $("#login").dxTextBox({
        placeholder: 'Login'
    }).dxValidator({
        validationRules: [{
            type: 'required'
        }, {
            type: 'pattern',
            pattern: '^[a-zA-Z]+$',
            message: 'Do not use digits.'
        }]
    });
});
<div id="login"></div>
Angular
app.component.html
app.component.ts
app.module.ts
<dx-text-box [(value)]="login" placeholder="Login">
    <dx-validator>
        <dxi-validation-rule
            type="required">
        </dxi-validation-rule>
        <dxi-validation-rule
            type="pattern"
            pattern="^[a-zA-Z]+$"
            message="Do not use digits.">
        </dxi-validation-rule>
    </dx-validator>
</dx-text-box>
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    login: string;
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import { DxTextBoxModule, DxValidatorModule } from 'devextreme-angular';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        DxTextBoxModule,
        DxValidatorModule
    ],
    providers: [ ],
    bootstrap: [AppComponent]
})
export class AppModule { }
Vue
App.vue
<template>
    <DxTextBox v-model:value="login" placeholder="Login">
        <DxValidator>
            <DxRequiredRule />
            <DxPatternRule pattern="^[a-zA-Z]+$" message="Do not use digits." />
        </DxValidator>
    </DxTextBox>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxTextBox from 'devextreme-vue/text-box';
import DxValidator, {
    DxRequiredRule,
    DxPatternRule
} from 'devextreme-vue/validator';

export default {
    components: {
        DxTextBox,
        DxValidator,
        DxRequiredRule,
        DxPatternRule
    },
    data() {
        return {
            login: undefined
        }
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.light.css';

import TextBox from 'devextreme-react/text-box';
import Validator, {
    RequiredRule,
    PatternRule
} from 'devextreme-react/validator';

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            login: undefined
        }
        this.setLogin = this.setLogin.bind(this);
    }

    setLogin(e) {
        this.setState({ login: e.value });
    }
    render() {
        return (
            <TextBox
                value={this.state.login}
                placeholder="Login"
                onValueChanged={this.setLogin}>
                <Validator>
                    <RequiredRule />
                    <PatternRule
                        pattern="^[a-zA-Z]+$"
                        message="Do not use digits."
                    />
                </Validator>
            </TextBox>
        );
    }
}
export default App;

Validate Several Editor Values

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
JavaScript
HTML
$(function () {
    var loginGroup = "loginGroup";
    $("#login")
        .dxTextBox({ /* ... */ })
        .dxValidator({
            // ...
            validationGroup: loginGroup
        }); 
    $("#password")
        .dxTextBox({ /* ... */ })
        .dxValidator({
            // ...
            validationGroup: loginGroup
        });
});
<div id="login"></div>
<div id="password"></div>
Angular
app.component.html
app.component.ts
app.module.ts
<dx-validation-group name="loginGroup">
    <dx-text-box [(value)]="login" placeholder="Login">
        <dx-validator>
            <!-- Login validation rules are configured here -->
        </dx-validator>
    </dx-text-box>
    <dx-text-box [(value)]="password" placeholder="Password">
        <dx-validator>
            <!-- Password validation rules are configured here -->
        </dx-validator>
    </dx-text-box>
</dx-validation-group>
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    login: string;
    password: string;
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import { DxTextBoxModule, DxValidatorModule, DxValidationGroupModule } from 'devextreme-angular';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        DxTextBoxModule,
        DxValidatorModule,
        DxValidationGroupModule
    ],
    providers: [ ],
    bootstrap: [AppComponent]
})
export class AppModule { }
Vue
App.vue
<template>
    <DxValidationGroup name="loginGroup">
        <DxTextBox v-model:value="login" placeholder="Login">
            <DxValidator>
                <!-- Login validation rules are configured here -->
            </DxValidator>
        </DxTextBox>
        <DxTextBox v-model:value="password" placeholder="Password">
            <DxValidator>
                <!-- Password validation rules are configured here -->
            </DxValidator>
        </DxTextBox>
    </DxValidationGroup>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxTextBox from 'devextreme-vue/text-box';
import DxValidator, {
    DxRequiredRule,
    DxPatternRule
} from 'devextreme-vue/validator';
import DxValidationGroup from 'devextreme-vue/validation-group';

export default {
    components: {
        DxTextBox,
        DxValidator,
        DxRequiredRule,
        DxPatternRule,
        DxValidationGroup
    },
    data() {
        return {
            login: undefined,
            password: undefined
        }
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.light.css';

import TextBox from 'devextreme-react/text-box';
import Validator, { 
    // Validation rule types are imported here
} from 'devextreme-react/validator';
import ValidationGroup from 'devextreme-react/validation-group';

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            login: undefined,
            password: undefined
        }
        this.setLogin = this.setLogin.bind(this);
        this.setPassword = this.setPassword.bind(this);
    }

    setLogin(e) {
        this.setState({ login: e.value });
    }
    setPassword(e) {
        this.setState({ password: e.value });
    }
    render() {
        return (
            <ValidationGroup name="loginGroup">
                <TextBox
                    value={this.state.login}
                    placeholder="Login"
                    onValueChanged={this.setLogin}>
                    <Validator>
                        {/* Login validation rules are configured here */}
                    </Validator>
                </TextBox>
                <TextBox
                    value={this.state.password}
                    placeholder="Password"
                    onValueChanged={this.setPassword}>
                    <Validator>
                        {/* Password validation rules are configured here */}
                    </Validator>
                </TextBox>
            </ValidationGroup>
        );
    }
}
export default App;

Validate the Group

Call a group's validate() method in a Button's onClick event handler to validate the group. 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
JavaScript
HTML
$(function () {
    // var loginGroup = "loginGroup";
    $("#login")
        .dxTextBox({ /* ... */ })
        .dxValidator({
            // validationGroup: loginGroup,
            validationRules: [ /* ... */ ]
        });

    $("#password")
        .dxTextBox({ /* ... */ })
        .dxValidator({
            // validationGroup: loginGroup,
            validationRules: [ /* ... */ ]
        });

    $("#loginButton").dxButton({
        text: "Sign in",
        // 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
app.component.html
app.component.ts
app.module.ts
<!-- <dx-validation-group> -->
    <dx-text-box [(value)]="login">
        <dx-validator>
            <!-- Login validation rules are configured here -->
        </dx-validator>
    </dx-text-box>
    <dx-text-box [(value)]="password">
        <dx-validator>
            <!-- Password validation rules are configured here -->
        </dx-validator>
    </dx-text-box>
    <dx-button text="Sign in" (onClick)="signIn($event)"></dx-button>
<!-- </dx-validation-group> -->
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    login: string;
    password: string;
    signIn(e) {
        let result = e.validationGroup.validate();
        if (result.isValid) {
            // Submit values to the server
        }
    }
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import {
    DxTextBoxModule,
    DxValidatorModule,
    // DxValidationGroupModule,
    DxButtonModule
} from 'devextreme-angular';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        DxTextBoxModule,
        DxValidatorModule,
        // DxValidationGroupModule,
        DxButtonModule
    ],
    providers: [ ],
    bootstrap: [AppComponent]
})
export class AppModule { }
Vue
App.vue
<template>
    <!-- <DxValidationGroup> -->
        <DxTextBox v-model:value="login" placeholder="Login">
            <DxValidator>
                <!-- Login validation rules are configured here -->
            </DxValidator>
        </DxTextBox>
        <DxTextBox v-model:value="password" placeholder="Password">
            <DxValidator>
                <!-- Password validation rules are configured here -->
            </DxValidator>
        </DxTextBox>
        <DxButton text="Sign in" @click="signIn" />
    <!-- </DxValidationGroup> -->
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxTextBox from 'devextreme-vue/text-box';
import DxValidator, {
    DxRequiredRule,
    DxPatternRule
} from 'devextreme-vue/validator';
// import DxValidationGroup from 'devextreme-vue/validation-group';
import DxButton from 'devextreme-vue/button';

export default {
    components: {
        DxTextBox,
        DxValidator,
        DxRequiredRule,
        DxPatternRule,
        // DxValidationGroup,
        DxButton
    },
    data() {
        return {
            login: undefined,
            password: undefined
        }
    },
    methods: {
        signIn(e) {
            let result = e.validationGroup.validate();
            if (result.isValid) {
                // Submit values to the server
            }
        }
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.light.css';

import TextBox from 'devextreme-react/text-box';
import Validator, { 
    // Validation rule types are imported here
} from 'devextreme-react/validator';
import ValidationGroup from 'devextreme-react/validation-group';
import Button from 'devextreme-react/button';

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            login: undefined,
            password: undefined
        }
        this.setLogin = this.setLogin.bind(this);
        this.setPassword = this.setPassword.bind(this);
        this.signIn = this.signIn.bind(this);
    }

    setLogin(e) {
        this.setState({ login: e.value });
    }
    setPassword(e) {
        this.setState({ password: e.value });
    }

    signIn(e) {
        let result = e.validationGroup.validate();
        if (result.isValid) {
            // Submit values to the server
        }
    }

    render() {
        return (
            {/* <ValidationGroup> */}
                <TextBox
                    value={this.state.login}
                    placeholder="Login"
                    onValueChanged={this.setLogin}>
                    <Validator>
                        {/* Login validation rules are configured here */}
                    </Validator>
                </TextBox>
                <TextBox
                    value={this.state.password}
                    placeholder="Password"
                    onValueChanged={this.setPassword}>
                    <Validator>
                        {/* Password validation rules are configured here */}
                    </Validator>
                </TextBox>
                <Button
                    text="Sign in"
                    onClick={this.signIn}
                />
            {/* </ValidationGroup> */}
        );
    }
}
export default App;
jQuery

Alternatively, you can use the DevExpress.validationEngine.validateGroup method to validate a group.

index.js
$(function() {
    $("#login").dxTextBox({})
        .dxValidator({
            validationGroup: "loginGroup",
            validationRules: [{
                type: "required"
            }]
        });

    $("#password").dxTextBox({})
        .dxValidator({
            validationGroup: "loginGroup",
            validationRules: [{
                type: "required"
            }]
        });

    $("#button").dxButton({
        text: "Sign in",
        onClick: function() {
            DevExpress.validationEngine.validateGroup("loginGroup");
        }
    });
});
Angular

Alternatively, you can get a group's instance and call its validate method to validate this group:

app.component.html
app.component.ts
app.module.ts
<dx-validation-group #targetGroup>
    <dx-text-box>
        <dx-validator>
            <dxi-validation-rule type="required">
            </dxi-validation-rule>
        </dx-validator>
    </dx-text-box>

    <dx-text-box>
        <dx-validator>
            <dxi-validation-rule type="required">
            </dxi-validation-rule>
        </dx-validator>
    </dx-text-box>
</dx-validation-group>

<dx-button
    text="Sign in"
    (onClick)="validateGroup($event)">
</dx-button>
import { Component } from '@angular/core';
import { DxValidationGroupComponent } from 'devextreme-angular/ui/validation-group';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    @ViewChild('targetGroup', {static: false}) validationGroup: DxValidationGroupComponent

    validateGroup() {
        this.validationGroup.instance.validate();
    }
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import { 
    DxTextBoxModule, 
    DxButtonModule, 
    DxValidatorModule, 
    DxValidationGroupModule
} from "devextreme-angular";

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        DxButtonModule,
        DxTextBoxModule, 
        DxValidatorModule,
        DxValidationGroupModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
Vue

Alternatively, you can get a group's instance and call its validate method to validate this group:

App.vue
<template>
    <div>
        <DxValidationGroup
            :ref="groupRefKey">
            <DxTextBox>
                <DxValidator>
                    <DxRequiredRule />
                </DxValidator>
            </DxTextBox>

            <DxTextBox>
                <DxValidator>
                    <DxRequiredRule />
                </DxValidator>
            </DxTextBox>
        </DxValidationGroup>

        <DxButton
            text="Sign in"
            @click="validateGroup"
        />
    </div>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxTextBox from 'devextreme-vue/text-box';
import DxValidator, { DxRequiredRule } from 'devextreme-vue/validator';
import DxValidationGroup from 'devextreme-vue/validation-group';
import DxButton from 'devextreme-vue/button';

export default {
    components: {
        DxTextBox,
        DxValidator,
        DxRequiredRule,
        DxValidationGroup,
        DxButton
    },
    data() {
        groupRefKey: 'targetGroup'
    },
    methods: {
        validateGroup() {
            this.validationGroup.validate();
        }
    },
    computed: {
        validationGroup: function() {
            return this.$refs[this.groupRefKey].instance;
        }
    }
}
</script>
React

Alternatively, you can get a group's instance and call its validate method to validate this group:

App.js
import React from 'react';

import 'devextreme/dist/css/dx.light.css';

import { TextBox } from 'devextreme-react/text-box';
import { Button } from 'devextreme-react/button';
import { ValidationGroup } from 'devextreme-react/validation-group';
import {
    Validator,
    RequiredRule
} from 'devextreme-react/validator';

class App extends React.Component {
    constructor(props) {
        super(props);
        this.validateGroup = this.validateGroup.bind(this);
        this.validationGroup = null;
    };

    validateGroup() {
        this.validationGroup.instance.validate();
    }

    render() {
        return (
            <React.Fragment>
                <ValidationGroup
                    ref={ref => this.validationGroup = ref}>
                    <TextBox>
                        <Validator>
                            <RequiredRule />
                        </Validator>
                    </TextBox>

                    <TextBox>
                        <Validator>
                            <RequiredRule />
                        </Validator>
                    </TextBox>

                    <Button
                        text="Sign in"
                        onClick={this.validateGroup}
                    />
                </ValidationGroup>
            <React.Fragment>
        );
    }
}
export default App;

Display Validation Errors

All group validation errors can be displayed in the ValidationSummary UI component. The following code shows how to add this UI component to a page. The commented-out codelines associate the Validation Summary with a named Validation Group.

jQuery
JavaScript
HTML
$(function () {
    // var loginGroup = "loginGroup";
    $("#summary").dxValidationSummary({
        // validationGroup: loginGroup
    });
});
...
<div id="summary"></div>
Angular
app.component.html
app.module.ts
<!-- <dx-validation-group name="loginGroup"> -->
    ...
    <dx-validation-summary></dx-validation-summary>
<!-- </dx-validation-group> -->
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import {
    // ...
    // DxValidationGroupModule,
    DxValidationSummaryModule
} from 'devextreme-angular';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        // ...
        // DxValidationGroupModule,
        DxValidationSummaryModule
    ],
    providers: [ ],
    bootstrap: [AppComponent]
})
export class AppModule { }
Vue
App.vue
<template>
    <!-- <DxValidationGroup name="loginGroup"> -->
        ...
        <DxValidationSummary />
    <!-- </DxValidationGroup> -->
</template>

<script>
// ...
import DxValidationSummary from 'devextreme-vue/validation-summary';
// import DxValidationGroup from 'devextreme-vue/validation-group';

export default {
    components: {
        // ...
        // DxValidationGroup,
        DxValidationSummary
    },
    // ...
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.light.css';

// ...
// import ValidationGroup from 'devextreme-react/validation-group';
import ValidationSummary from 'devextreme-react/validation-summary';

class App extends React.Component {
    // ...
    render() {
        return (
            {/* <ValidationGroup name="loginGroup"> */}
                ...
                <ValidationSummary />
            {/* </ValidationGroup> */}
        );
    }
}
export default App;

Disable Validation Dynamically

All the rules, except the CustomRule and AsyncRule, are always applied and cannot be disabled at runtime.

If you need to disable validation dynamically, implement a CustomRule or AsyncRule in which you should simulate the validation logic of a target rule but apply it only under certain conditions.

The following example illustrates this case. A page contains two TextBoxes and a CheckBox. The first TextBox has proper RequiredRule; the second TextBox has a CustomRule that simulates the RequiredRule logic but applies it only when the CheckBox is selected. The reevaluate property is enabled to re-check the TextBox value after the CheckBox value was changed.

jQuery
index.js
$(function() {
    $("#firstName").dxTextBox({ })
        .dxValidator({
            validationRules: [{
                type: "required"
            }]
        });

    $("#lastName").dxTextBox({ })
        .dxValidator({
            validationRules: [{
                type: "custom",
                message: "Required",
                reevaluate: true,
                validationCallback: function(e) {
                    if ($("#checkBox").dxCheckBox("option", "value")) {
                        return !!e.value;
                    }
                    return true; 
                }        
            }]
        });

    $("#validationButton").dxButton({
        text: "Validate",
        onClick: function (params) {
            params.validationGroup.validate();
        }
    });

    $("#checkBox").dxCheckBox({
        text: "Validate last name",
        value: false
    });
});
Angular
app.component.html
app.component.ts
app.module.ts
<dx-text-box>
    <dx-validator>
        <dxi-validation-rule type="required">
        </dxi-validation-rule>
    </dx-validator>
</dx-text-box>

<dx-text-box>
    <dx-validator>
        <dxi-validation-rule 
            type="custom"
            message="Required" 
            [validationCallback]="customCallback"
            [reevaluate]="true">
        </dxi-validation-rule>
    </dx-validator>
</dx-text-box>

<dx-button
    text="Validate group"
    (onClick)="validateGroup($event)">
</dx-button>

<dx-check-box
    [(value)]="checkBoxValue">
</dx-check-box>
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    constructor() {
        this.customCallback = this.customCallback.bind(this);
    }

    checkBoxValue = false;

    customCallback(e) {
        if (this.checkBoxValue) {
            return !!e.value;
        }
        return true;
    }

    validateGroup(params) {
        params.validationGroup.validate();
    }
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

import { 
    DxTextBoxModule, 
    DxButtonModule, 
    DxCheckBoxModule, 
    DxValidatorModule 
} from "devextreme-angular";

@NgModule({
declarations: [
    AppComponent
],
imports: [
    BrowserModule,
    DxCheckBoxModule,
    DxButtonModule,
    DxTextBoxModule, 
    DxValidatorModule 
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Vue
App.vue
<template>
    <div id="root">
        <DxTextBox>
            <DxValidator>
                <DxRequiredRule />                
            </DxValidator>
        </DxTextBox>

        <DxTextBox>
            <DxValidator>
                <DxCustomRule 
                    message="Required" 
                    :validation-callback="customCallback"
                    :reevaluate="true"
                />
            </DxValidator>
        </DxTextBox>

        <DxButton
            text="Validate group"
            @click="validateGroup"
        />

        <DxCheckBox 
            v-model:value="checkBoxValue" 
        />
    </div>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import { DxTextBox, DxButton, DxCheckBox } from 'devextreme-vue';
import {
    DxValidator,
    DxRequiredRule,
    DxCustomRule
} from 'devextreme-vue/validator';

export default {
    components: {
        DxTextBox,
        DxButton,
        DxCheckBox,
        DxValidator,        
        DxRequiredRule,
        DxCustomRule
    },
    data() {
        return {
            checkBoxValue: false
        };
    },
    methods: {
        customCallback(e) {
            if (this.checkBoxValue) {
                return !!e.value;
            }
            return true;
        },

        validateGroup(params) {
            params.validationGroup.validate();
        }
    }    
};
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.light.css';

import { 
    CheckBox, 
    TextBox, 
    Button 
} from 'devextreme-react';
import {
    Validator,
    RequiredRule,
    CustomRule
} from 'devextreme-react/validator';

class App extends React.Component {
    constructor(props) {
        super(props);
        this.handleCheckBoxChange = this.handleCheckBoxChange.bind(this);
        this.customCallback = this.customCallback.bind(this);
        this.validateGroup = this.validateGroup.bind(this);
        this.state = { checkBoxValue: false };
    };

    handleCheckBoxChange(e) {
        this.setState({ checkBoxValue: e.value });
    }

    render() {
        return (
            <div id="root">
                <TextBox>
                    <Validator>
                        <RequiredRule />
                    </Validator>
                </TextBox>

                <TextBox>
                    <Validator>
                        <CustomRule 
                            message="Required" 
                            validationCallback={this.customCallback}
                            reevaluate={true}
                        />
                    </Validator>
                </TextBox>

                <Button
                    text="Validate group"
                    onClick={this.validateGroup}
                />

                <CheckBox
                    value={this.state.checkBoxValue}
                    onValueChanged={this.handleCheckBoxChange}
                />
            </div>
        );
    }

    customCallback(e) {
        if (this.state.checkBoxValue) {
            return !!e.value;
        }
        return true;
    }

    validateGroup(params) {
        params.validationGroup.validate();
    }
}

export default App;

Custom Validation

To implement custom validation, use the CustomRule. Refer to the validationCallback function's description for an example.

Server-Side Validation

To implement server-side validation, use the AsyncRule. Refer to the validationCallback function's description for an example.

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 property. 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 provided by the getValue function.

jQuery
JavaScript
HTML
$(function() {
    var callbacks = [];
    var revalidate = function() {
        callbacks.forEach(func => {
            func();
        });
    }
    var phone = $("#phone").dxTextBox({
        placeholder: "Phone",
        onValueChanged: revalidate
    }).dxTextBox("instance");
    var email = $("#email").dxTextBox({
        type: "email",
        placeholder: "Email",
        onValueChanged: revalidate
    }).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) {
            const { isValid } = e.validationGroup.validate();
            if (isValid) {
                // Submit values to the server
            }
        }
    });
    $("#summary").dxValidationSummary({ });
});
<div id="contacts">
    <div id="phone"></div>
    <div id="email"></div>
</div>
<div id="validator"></div>
<div id="summary"></div>
<div id="button"></div>
Angular
app.component.html
app.component.ts
app.module.ts
<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>
</div>
<dx-validator
    [adapter]="adapterConfig">
    <dxi-validation-rule
        type="required"
        message="Specify your phone or email.">
    </dxi-validation-rule>
</dx-validator>
<dx-validation-summary></dx-validation-summary>
<dx-button
    text="Contact me"
    (onClick)="submit($event)">
</dx-button>
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    callbacks = [];
    phone: string;
    email: string;
    borderStyle: string = "none";
    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) {
        const { isValid } = e.validationGroup.validate();
        if (isValid) {
            // Submit values to the server
        }
    }
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import {
    DxTextBoxModule,
    DxValidatorModule,
    DxValidationSummaryModule,
    DxButtonModule
} from 'devextreme-angular';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        DxTextBoxModule,
        DxValidatorModule,
        DxValidationSummaryModule,
        DxButtonModule
    ],
    providers: [ ],
    bootstrap: [AppComponent]
})
export class AppModule { }
Vue
App.vue
<template>
    <div>
        <div id="contacts" :style="{ border: borderStyle }">
            <DxTextBox
                v-model:value="phone"
                placeholder="Phone"
                @value-changed="revalidate"
            />
            <DxTextBox
                v-model:value="email"
                placeholder="Email"
                @value-changed="revalidate"
                type="email"
            />
        </div>
        <DxValidator :adapter="adapterConfig">
            <DxRequiredRule message="Specify your phone or email." />
        </DxValidator>
        <DxValidationSummary />
        <DxButton text="Contact me" @click="submit" />
    </div>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxTextBox from "devextreme-vue/text-box";
import DxValidator, { DxRequiredRule } from "devextreme-vue/validator";
import DxButton from "devextreme-vue/button";
import DxValidationSummary from "devextreme-vue/validation-summary";

export default {
    components: {
        DxTextBox,
        DxValidator,
        DxRequiredRule,
        DxButton,
        DxValidationSummary,
    },
    data() {
        const callbacks = [];
        const adapterConfig = {
            getValue: () => {
                return this.phone || this.email;
            },
            applyValidationResults: (e) => {
                this.borderStyle = e.isValid ? "none" : "1px solid red";
            },
            validationRequestsCallbacks: callbacks,
        };
        const revalidate = () => {
            callbacks.forEach((func) => {
                func();
            });
        };
        return {
            phone: undefined,
            email: undefined,
            borderStyle: "none",
            adapterConfig,
            revalidate
        };
    },
    methods: {
        submit (e) {
            const { isValid } = e.validationGroup.validate();
            if (isValid) {
                // Submit values to the server
            }
        }
    },
};
</script>
React
App.js
import { useState, useCallback } from 'react';

import 'devextreme/dist/css/dx.light.css';
import { TextBox } from 'devextreme-react/text-box';
import { Button } from 'devextreme-react/button';
import { Validator, RequiredRule } from 'devextreme-react/validator';
import { ValidationSummary } from 'devextreme-react/validation-summary';

export default function App() {
    const [phone, setPhone] = useState();
    const [email, setEmail] = useState();
    const [borderStyle, setBorderStyle] = useState("none");
    const callbacks = [];
    const adapterConfig = {
        getValue: () => {
            return phone || email;
        },
        applyValidationResults: (e) => {
            setBorderStyle(e.isValid ? "none" : "1px solid red");
        },
        validationRequestsCallbacks: callbacks,
    };
    const revalidate = useCallback(() => {
        callbacks.forEach((func) => {
            func();
        });
    }, []);
    const handlePhoneChange = useCallback((e) => {
        setPhone(e.value);
        revalidate();
    }, []);
    const handleEmailChange = useCallback((e) => {
        setEmail(e.value);
        revalidate();
    }, []);
    const submit = useCallback((e) => {
        const { isValid } = e.validationGroup.validate();
        if (isValid) {
            // Submit values to the server
        }
    }, []);

    return (
        <div>
            <div id="contacts" style={{ border: borderStyle }}>
                <TextBox
                    value={phone}
                    placeholder="Phone"
                    onValueChanged={handlePhoneChange}
                />
                <TextBox
                    value={email}
                    placeholder="Email"
                    onValueChanged={handleEmailChange}
                    type="email"
                />
            </div>
            <Validator adapter={adapterConfig}>
                <RequiredRule message="Specify your phone or email." />
            </Validator>
            <ValidationSummary />
            <Button text="Contact me" onClick={submit} />
        </div>
    );
}