@model DevExtreme.MVC.Demos.ViewModels.EditorsViewModel
@using(Html.BeginForm()) {
using(Html.DevExtreme().ValidationGroup()) {
@Html.AntiForgeryToken()
<div class="dx-fieldset">
<div class="dx-fieldset-header">Credentials</div>
<div class="dx-field">
<div class="dx-field-label">
@Html.LabelFor(m => m.Email)
</div>
<div class="dx-field-value">
@Html.DevExtreme().TextBoxFor(m => m.Email)
</div>
</div>
<div class="dx-field">
<div class="dx-field-label">
@Html.LabelFor(m => m.Password)
</div>
<div class="dx-field-value">
@(Html.DevExtreme().TextBoxFor(m => m.Password)
.Mode(TextBoxMode.Password)
.ID("Password")
.OnValueChanged("onPasswordChanged")
.Buttons(buttons =>
{
buttons.Add()
.Name("password")
.Location(TextEditorButtonLocation.After)
.Widget(w => w.Button()
.StylingMode(ButtonStylingMode.Text)
.Icon("eyeopen")
.OnClick("() => changePasswordMode('Password')"));
})
)
</div>
</div>
<div class="dx-field">
<div class="dx-field-label">
@Html.LabelFor(m => m.ConfirmPassword, "Confirm Password")
</div>
<div class="dx-field-value">
@(Html.DevExtreme().TextBoxFor(m => m.ConfirmPassword)
.Mode(TextBoxMode.Password)
.ID("ConfirmPassword")
.Buttons(buttons =>
{
buttons.Add()
.Name("password")
.Location(TextEditorButtonLocation.After)
.Widget(w => w.Button()
.StylingMode(ButtonStylingMode.Text)
.Icon("eyeopen")
.OnClick("() => changePasswordMode('ConfirmPassword')"));
})
)
</div>
</div>
</div>
<div class="dx-fieldset">
<div class="dx-fieldset-header">Personal Data</div>
<div class="dx-field">
<div class="dx-field-label">
@Html.LabelFor(m => m.Name)
</div>
<div class="dx-field-value">
@Html.DevExtreme().TextBoxFor(m => m.Name)
</div>
</div>
<div class="dx-field">
<div class="dx-field-label">
@Html.LabelFor(m => m.Date, "Date of birth")
</div>
<div class="dx-field-value">
@(Html.DevExtreme().DateBoxFor(m => m.Date)
.InvalidDateMessage("The date must have the following format: MM/dd/yyyy")
)
</div>
</div>
<div class="dx-field">
<div class="dx-field-label">
@Html.LabelFor(m => m.VacationDates, "Vacation Dates")
</div>
<div class="dx-field-value">
@(Html.DevExtreme().DateRangeBoxFor(m => m.VacationDates)
.ID("DateRangeBox")
.OnValueChanged("onVacationDatesChange")
)
</div>
</div>
</div>
<div class="dx-fieldset">
<div class="dx-fieldset-header">Billing address</div>
<div class="dx-field">
<div class="dx-field-label">
@Html.LabelFor(m => m.Country)
</div>
<div class="dx-field-value">
@(Html.DevExtreme().SelectBoxFor(m => m.Country)
.DataSource(d => d.WebApi().RouteName("GeoNames").LoadAction("Countries").Key("this"))
.ValidationMessagePosition(Position.Left)
)
</div>
</div>
<div class="dx-field">
<div class="dx-field-label">
@Html.LabelFor(m => m.City)
</div>
<div class="dx-field-value">
@(Html.DevExtreme().TextBoxFor(m => m.City)
.ValidationMessagePosition(Position.Left)
)
</div>
</div>
<div class="dx-field">
<div class="dx-field-label">
@Html.LabelFor(m => m.Address)
</div>
<div class="dx-field-value">
@(Html.DevExtreme().TextBoxFor(m => m.Address)
.ValidationMessagePosition(Position.Left)
)
</div>
</div>
<div class="dx-field">
<div class="dx-field-label">
@Html.LabelFor(m => m.Phone) <i>(optional)</i>
</div>
<div class="dx-field-value">
@(Html.DevExtreme().TextBoxFor(m => m.Phone)
.Mask("+1 (X00) 000-0000")
.MaskRules(new { X = new JS("/[02-9]/") })
.MaskInvalidMessage("The phone must have a correct USA phone format")
.ValidationMessagePosition(Position.Left)
)
</div>
</div>
</div>
<div class="dx-fieldset">
<div class="dx-field">
<div class="dx-field-label">
@(Html.DevExtreme().CheckBoxFor(m => m.Accepted)
.ID("check")
.Text("I agree to the Terms and Conditions")
.ValidationMessagePosition(Position.Right)
)
</div>
<div class="dx-field-value">
@(Html.DevExtreme().Button()
.Width("120px")
.Text("Register")
.Type(ButtonType.Default)
.UseSubmitBehavior(true)
)
</div>
</div>
@(Html.DevExtreme().ValidationSummary()
.ID("summary")
)
</div>
}
}
<script>
function changePasswordMode(name) {
let editor = $(`#${name}`).dxTextBox("instance");
editor.option('mode', editor.option('mode') === 'text' ? 'password' : 'text');
}
function onPasswordChanged(e) {
let editor = $("#ConfirmPassword").dxTextBox("instance");
if(editor.option("value")) {
editor.element().dxValidator("validate")
}
}
function onVacationDatesChange(e) {
const editor = $("#DateRangeBox").dxDateRangeBox("instance");
const [startDate, endDate] = editor.option("value");
let isValid;
if (startDate === null && endDate === null) {
isValid = true;
} else {
isValid = startDate !== null && endDate !== null;
}
if (!isValid) {
editor.option({
validationStatus: "invalid",
validationErrors: [{ message: "Both start and end dates must be selected" }]
});
}
}
</script>
<p>The submitted data has been successfully accepted.</p>
<br />
@(Html.DevExtreme().Button()
.Text("Reload demo")
.Type(ButtonType.Default)
.Icon("refresh")
.OnClick(@<text>
function() {
window.location = window.location;
}
</text>)
)
using System;
using System.Linq;
using System.Web.Mvc;
using DevExtreme.MVC.Demos.Models.DataGrid;
namespace DevExtreme.MVC.Demos.Controllers {
public class RemoteValidationController : Controller {
InMemoryEmployeesValidationDataContext db = new InMemoryEmployeesValidationDataContext();
[HttpPost]
public JsonResult CheckUniqueEmailAddress(EmployeeValidation model) {
var isValid = !db.Employees.Any(emp => {
var equals = string.Equals(emp.Email, model.Email, StringComparison.OrdinalIgnoreCase);
return model.ID != emp.ID && equals;
});
return Json(isValid);
}
[HttpPost]
public JsonResult CheckEmailAddress(string email) {
var isValid = !string.Equals(email, "test@dx-email.com", StringComparison.OrdinalIgnoreCase);
return Json(isValid);
}
}
}
using DevExtreme.MVC.Demos.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace DevExtreme.MVC.Demos.Controllers {
public class ValidationController : Controller {
[HttpGet]
public ActionResult Overview() {
return View(new EditorsViewModel {
Name = "Peter",
VacationDates = new DateTime?[] { null, null }
});
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Overview(EditorsViewModel userInfo) {
if(ModelState.IsValid) {
return View("SuccessValidation");
}
return View(userInfo);
}
}
}
using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using DevExtreme.MVC.Demos.Models.SampleData;
using System;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
namespace DevExtreme.MVC.Demos.Controllers.ApiControllers {
[Route("api/GeoNames/{action}", Name = "GeoNames")]
public class GeoNamesController : ApiController {
[HttpGet]
public HttpResponseMessage Countries(DataSourceLoadOptions loadOptions) {
return Request.CreateResponse(DataSourceLoader.Load(SampleData.Countries, loadOptions));
}
[HttpGet]
public HttpResponseMessage Cities(DataSourceLoadOptions loadOptions) {
return Request.CreateResponse(DataSourceLoader.Load(SampleData.Cities, loadOptions));
}
}
}
using DevExtreme.AspNet.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace DevExtreme.MVC.Demos.ViewModels {
public class EditorsViewModel {
[Required(ErrorMessage = "Email is required")]
[RegularExpression(@"^[\d\w._-]+@[\d\w._-]+\.[\w]+$", ErrorMessage = "Email is invalid")]
[Remote("CheckEmailAddress", "RemoteValidation", ErrorMessage = "Email is already registered", HttpMethod = "POST")]
public string Email { get; set; } = string.Empty;
[Required(ErrorMessage = "Name is required")]
[RegularExpression(@"^[^0-9]+$", ErrorMessage = "Do not use digits in the Name.")]
[StringLength(int.MaxValue, MinimumLength = 2, ErrorMessage = "Name must have at least 2 symbols")]
public string Name { get; set; } = string.Empty;
[Required(ErrorMessage = "Password is required")]
public string Password { get; set; } = string.Empty;
[Required(ErrorMessage = "Confirm Password is required")]
[System.ComponentModel.DataAnnotations.Compare("Password", ErrorMessage = "'Password' and 'Confirm Password' do not match.")]
public string ConfirmPassword { get; set; } = string.Empty;
[RegularExpression(@"^[02-9]\d{9}$", ErrorMessage = "The phone must have a correct USA phone format")]
public string Phone { get; set; } = string.Empty;
public string Extension { get; set; }
[Required(ErrorMessage = "Country is required")]
public string Country { get; set; }
[Required(ErrorMessage = "Address is required")]
public string Address { get; set; } = string.Empty;
public string Description { get; set; }
public int Age { get; set; }
public string Drink { get; set; }
[Required(ErrorMessage = "City is required")]
[RegularExpression("^[^0-9]+$", ErrorMessage = "Do not use digits in the City name.")]
[StringLength(int.MaxValue, MinimumLength = 2, ErrorMessage = "City must have at least 2 symbols")]
public string City { get; set; }
public IEnumerable<string> Colors { get; set; }
public IEnumerable<string> SelectedColors { get; set; }
public string Color { get; set; }
[Display(Name = "Date of birth")]
[Required(ErrorMessage = "Date of birth is required")]
[VerifyAge(21, ErrorMessage = "You must be at least {1} years old")]
public DateTime? Date { get; set; }
[VerifyDateRange(25, ErrorMessage = "The vacation period must not exceed {1} days")]
public DateTime?[] VacationDates { get; set; }
[DevExtremeRequired(ErrorMessage = "You must agree to the Terms and Conditions")]
public bool Accepted { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
namespace DevExtreme.MVC.Demos.ViewModels {
public class VerifyAgeAttribute : ValidationAttribute, IClientValidatable {
public VerifyAgeAttribute(int age) {
Age = age;
}
public int Age { get; private set; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
if((DateTime?)value <= DateTime.Now.AddYears(-Age)) {
return ValidationResult.Success;
}
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
IEnumerable<ModelClientValidationRule> IClientValidatable.GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
var rule = new ModelClientValidationRule();
rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
rule.ValidationParameters.Add(
"validationcallback",
$@"function(options) {{
var now = new Date();
return options.value && options.value <= now.setFullYear(now.getFullYear() - {Age});
}}");
rule.ValidationType = "custom";
yield return rule;
}
public override string FormatErrorMessage(string name) {
return string.Format(ErrorMessageString, name, Age);
}
}
}
#summary {
padding-left: 10px;
margin-top: 20px;
margin-bottom: 10px;
}