Skip to main content
A newer version of this page is available. .

Data Validation

  • 8 minutes to read

Overview

Client-side data validation allows you to validate input values before they are sent to the server and without reloading the page. DevExtreme-based ASP.NET Core controls use model properties’ Data Annotation validation attributes to validate input values. The following validation attributes are supported:

  • [Required]
  • [StringLength]
  • [Range]
  • [RegularExpression]
  • [Compare]
  • [Display] *
  • [DisplayName] *
  • [Custom]

* - Supported only for controls configured using strongly-typed helpers.

Note

We also provide the [DevExtremeRequired] attribute. When you set up this attribute, the validation engine works like standard validation for HTML5 elements. It considers false an invalid Boolean value, whereas the standard [Required] accepts true and false. You can find more information in this blog post.

Model properties that have at last one of these attributes can be validated. For example, a Person model contains a FirstName property that has three validation attributes:

using System.ComponentModel.DataAnnotations;

namespace ApplicationName.Models {
    public class Person {
        [Required(ErrorMessage = "First name is required")]
        [RegularExpression(@"^[a-zA-Z\s]+$", ErrorMessage = "Please, use letters in the first name. Digits are not allowed.")]
        [StringLength(int.MaxValue, MinimumLength = 2, ErrorMessage = "First name must have at least 2 characters")]
        public string FirstName { get; set; }
    }
}

To apply these validation attributes to a DevExtreme editor, use the EditorFor method to create this editor. Substitute “Editor” in EditorFor with the editor’s name. For example, to create the DevExtreme TextBox editor, call the TextBoxFor method:

@model ApplicationName.Models.Person

@(Html.DevExtreme().TextBoxFor(model => model.FirstName))

You can also use a more explicit syntax to bind an editor to a model property and apply validation attributes. Pass the property’s name to the Name method and an initial value to the Value method. The previous and following code samples produce the same result:

@model ApplicationName.Models.Person

@(Html.DevExtreme().TextBox()
    .Name("FirstName")
    .Value(Model.FirstName)
)

Note

Use the StartName and EndName methods instead of the Name method for the RangeSlider control.

The input value is validated each time the change event is raised. To change the DOM event that triggers validation, set the valueChangeEvent option.

@(Html.DevExtreme().TextBoxFor(model => model.FirstName)
    .ValueChangeEvent("keyup")
)

Note

If the [Range] attribute should limit a date or time range, use the RangeAttribute overload that accepts a type as the first argument. The date/time values should be strings. See an example in the following code:

namespace ApplicationName.Models {
    public class Person {
        // ...
        [Range(typeof(DateTime), "1/1/1901", "1/1/2016")]
        public DateTime BirthDate { get; set; }
    }
}    

Validate a Group of Editors

If several editors should be validated together, combine them in a validation group. Use the following syntax to declare it, and add a Button that validates this group.

@model ApplicationName.Models.Person

using (Html.DevExtreme().ValidationGroup()) {
    @(Html.DevExtreme().TextBoxFor(model => model.FirstName))
    @(Html.DevExtreme().TextBoxFor(model => model.LastName))

    @(Html.DevExtreme().Button()
        .Text("Validate")
        .OnClick("validate")
    )
}

<script>
    function validate (params) {
        params.validationGroup.validate();
    }
</script>

If the Button should be outside the group it validates, use the ValidationGroup method to bind the Button to the group. Note that in this case, the validation group should have a name.

@model ApplicationName.Models.Person

using (Html.DevExtreme().ValidationGroup("groupName")) {
    @(Html.DevExtreme().TextBoxFor(model => model.FirstName))
    @(Html.DevExtreme().TextBoxFor(model => model.LastName))
}

@(Html.DevExtreme().Button()
    .Text("Validate")
    .ValidationGroup("groupName")
    .OnClick("validate")
)

<script>
    function validate (params) {
        params.validationGroup.validate();
    }
</script>

Editors whose validation group is not specified explicitly are collected in a default validation group. To validate this group, do not include the Button in any validation group and do not specify the ValidationGroup.

@model ApplicationName.Models.Person

@(Html.DevExtreme().TextBoxFor(model => model.FirstName))
@(Html.DevExtreme().TextBoxFor(model => model.LastName))

@(Html.DevExtreme().Button()
    .Text("Validate")
    .OnClick("validate")
)

<script>
    function validate (params) {
        params.validationGroup.validate();
    }
</script>

Note

The DevExtreme Button control allows you to submit a collection of editors after they are validated on the client. See the Validate and Submit an HTML Form topic for more information.

Each editor displays validation errors that apply to it. If you want to display all errors relevant to a validation group in one place, add a ValidationSummary to your page.

using (Html.DevExtreme().ValidationGroup()) {
    // ...
    // Displays validation errors that apply to the group it is nested in
    @(Html.DevExtreme().ValidationSummary())
}
using (Html.DevExtreme().ValidationGroup("groupName")) {
    // ...
}

@(Html.DevExtreme().ValidationSummary()
    // Displays validation errors that apply to the "groupName" group
    .ValidationGroup("groupName")
)
// Displays validation errors that apply to the default group
@(Html.DevExtreme().ValidationSummary())

View Demo

Implement a Custom Validation Rule

You can implement custom rules if the built-in validation rules do not meet your requirements:

  1. Create a class that is inherited from the ValidationAttribute and IClientModelValidator. In this class, implement the following methods:

    • AddValidation Adds the custom validation attribute to the validation attribute collection.

    • MergeAttribute Checks that the key of the custom validation attribute is unique within the collection. Note that the key should have the “data-val-custom-“ prefix. The key that ends with “validationcallback” should point to a JavaScript function that implements the validation logic. This function is declared in step 3.

    • IsValid Validates data on the server to ensure invalid values are not sent when JavaScript is switched off on the client.

    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
    namespace ApplicationName.Models
    {
        public class VerifyAgeAttribute : ValidationAttribute, IClientModelValidator
        {
            public VerifyAgeAttribute()
                : base("The value of the {0} field is not valid") {
            }
            public void AddValidation(ClientModelValidationContext context) {
                MergeAttribute(context.Attributes, "data-val-custom-verifyage",
                        FormatErrorMessage(context.ModelMetadata.GetDisplayName()));
                MergeAttribute(context.Attributes, "data-val-custom-verifyage-validationcallback", "verifyAge");
            }
            bool MergeAttribute(IDictionary<string, string> attributes, string key, string value) {
                if(attributes.ContainsKey(key)) {
                    return false;
                }
                attributes.Add(key, value);
                return true;
            }
            protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
                DateTime? date = (DateTime?)value;
                if(date <= DateTime.Now.AddYears(-21)) {
                    return ValidationResult.Success;
                }
                return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
            }
        }
    }
    
  2. Attach the custom attribute to a model property.

    using System.ComponentModel.DataAnnotations;
    namespace ApplicationName.Models {
        public class Person {
            // ...
            [VerifyAge(ErrorMessage = "Persons under 21 are not allowed")]
            public DateTime? BirthDate { get; set; }
        }
    }
    
  3. In the view, declare a JavaScript function that implements all validation logic.

    <script>
        function verifyAge(options) {
            return options.value && new Date(Date.now()).getFullYear() - options.value.getFullYear() >= 21;
        }
    </script>
    

To use a custom validation rule, create a DevExtreme editor for the model property from step 2 in the same view where the JavaScript function is declared. The following code shows how to create the DevExtreme DateBox:

@model ApplicationName.Models.Person

@(Html.DevExtreme().DateBoxFor(model => model.BirthDate))

View Demo

Validate and Submit an HTML Form

The DevExtreme Button control allows you to submit editors that are nested in an HTML form to the server after they are validated on the client. To do this, place the Button on the HTML form and pass true to the UseSubmitBehavior method.

@model Application1.ViewModels.LoginViewModel

@using (Html.BeginForm("LoginValidation", "Home", FormMethod.Post, new { id = "login" })) {

    using(Html.DevExtreme().ValidationGroup()) {

        // Creates a TextBox for the "Login" model property
        @(Html.DevExtreme().TextBoxFor(model => model.Login))

        // Creates a TextBox for the "Password" model property
        @(Html.DevExtreme().TextBoxFor(model => model.Password))
            .Mode(TextBoxMode.Password)
        )

        @(Html.DevExtreme().Button()
            .ID("logIn")
            .Text("Log In")
            .Type(ButtonType.Success)
            // Instructs the Button to validate the TextBoxes and submit the form
            .UseSubmitBehavior(true)
        )
    }
}

Note that the Button validates the TextBox controls in the previous code if the “Login” and “Password” model properties have Data Annotation validation attributes.

Note

The Button can validate different validation groups, but it always submits the HTML form in which it is nested. To avoid mixing up validated and submitted values, we recommend that a HTML form contain only one validation group.

View Demo

Validate and Submit the Form Control

Editors nested in the Form control can be validated only if they are bound to model properties that have Data Annotation validation attributes. To bind such editors, use the DataField method. You do not have to specify the editor explicitly if you can use the TextBox with default settings.

@(Html.DevExtreme().Form()
    .FormData(Model)
    .Items(formItems => {
        formItems.AddSimple()
            .DataField("EmployeeID")
            .Editor(e => e.TextBox().ReadOnly(true));

        // Uses the default TextBox
        formItems.AddSimple()
            .DataField("FirstName")
            .IsRequired(true);

        // Uses the default TextBox   
        formItems.AddSimple()
            .DataField("LastName")
            .IsRequired(true);

        formItems.AddSimple()
            .DataField("HireDate")
            .Editor(e => e.DateBox());
    })
)

A Form editor is validated each time its value changes. However, you should validate all the Form editors simultaneously if you want to submit multiple editors. This case is illustrated in the following code. All Form editors are collected in the “employee” validation group that is validated when a user clicks the “Validate and Submit” Button. If the validation is successful, the “editEmployee” HTML form with all editors is submitted.

@using (Html.BeginForm("EditEmployee", "Home", FormMethod.Post, new { id = "editEmployee" })) {

    @(Html.DevExtreme().Form()
        .FormData(Model)
        .Items(formItems => {
            formItems.AddSimple()
                .DataField("EmployeeID")
                .Editor(e => e.TextBox().ReadOnly(true));

            formItems.AddSimple()
                .DataField("FirstName")
                .IsRequired(true);

            formItems.AddSimple()
                .DataField("LastName")
                .IsRequired(true);

            formItems.AddSimple()
                .DataField("HireDate")
                .Editor(e => e.DateBox());
        })
        // Gives a name to the internal validation group
        .ValidationGroup("employee")
    )

    // Validates the "employee" validation group and submits the "editEmployee" HTML form
    @(Html.DevExtreme().Button()
        .Text("Validate and Submit")
        .ValidationGroup("employee")
        .UseSubmitBehavior(true)
    )
}

You can find an expanded code example in the following demo:

View Demo