Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#97 Implemented delayed validation by introducing delayedValidation o… #119

Merged
merged 3 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions Pages/Demos/ImmediateValidation.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@page
@model DemoWeb.Pages.Demos.ImmediateValidation
@{
Layout = "Shared/_Layout";
}

<div asp-validation-summary="All">
<span>Please correct the following errors</span>
</div>

<fieldset>
<legend>Required Email input with data-val-event specified for immediate validation as you type.</legend>
<form method="post">
<legend>Input with immediate validation (<code>data-val-event="input"</code>)</legend>
<div class="form-field">
<label asp-for="EmailAddress"></label>
<input asp-for="EmailAddress" data-val-event="input" />
<span asp-validation-for="EmailAddress"></span>
</div>
<legend>Input with default behavior</legend>
<div class="form-field">
<label asp-for="AnotherEmailAddress"></label>
<input asp-for="AnotherEmailAddress" />
<span asp-validation-for="AnotherEmailAddress"></span>
</div>
<input type="submit" value="Submit"/>
</form>
</fieldset>

@section Scripts {
<script>
const service = new aspnetValidation.ValidationService(console);
service.bootstrap();
</script>
}
18 changes: 18 additions & 0 deletions Pages/Demos/ImmediateValidation.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;

namespace DemoWeb.Pages.Demos;

public class ImmediateValidation : PageModel
{
[BindProperty]
[Required]
[EmailAddress]
public string? EmailAddress { get; set; }

[BindProperty]
[Required]
[EmailAddress]
public string? AnotherEmailAddress { get; set; }
}
1 change: 1 addition & 0 deletions Pages/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<li><a asp-page="Demos/FormAction">Form Action</a></li>
<li><a asp-page="Demos/DisabledInputsWithWatch">Disabled inputs (<code>{watch: true}</code>)</a></li>
<li><a asp-page="Demos/DisabledInputsNoWatch">Disabled inputs (no watch)</a></li>
<li><a asp-page="Demos/ImmediateValidation">Immediate Validation (<code>data-val-event="input"</code>)</a></li>
</ul>

@if (Model.StatusMessage != null) {
Expand Down
21 changes: 18 additions & 3 deletions dist/aspnet-validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,7 @@ var ValidationService = /** @class */ (function () {
*/
ValidationService.prototype.addInput = function (input) {
var _this = this;
var _a;
var uid = this.getElementUID(input);
var directives = this.parseDirectives(input.attributes);
this.validators[uid] = this.createValidator(input, directives);
Expand All @@ -1096,6 +1097,12 @@ var ValidationService = /** @class */ (function () {
validate = this.validators[uid];
if (!validate)
return [2 /*return*/, true];
if (!input.dataset.valEvent &&
event && event.type === 'input' &&
!input.classList.contains(this.ValidationInputCssClassName)) {
// When no data-val-event specified on a field, "input" event only takes it back to valid. "Change" event can make it invalid.
return [2 /*return*/, true];
}
this.logger.log('Validating', { event: event });
_a.label = 1;
case 1:
Expand All @@ -1120,9 +1127,17 @@ var ValidationService = /** @class */ (function () {
cb(event, callback);
}, _this.debounce);
};
var validateEvent = input.dataset.valEvent || input instanceof HTMLSelectElement ? 'change' : 'input';
input.addEventListener(validateEvent, cb.debounced);
cb.remove = function () { return input.removeEventListener(validateEvent, cb.debounced); };
var defaultEvent = input instanceof HTMLSelectElement ? 'change' : 'input change';
var validateEvent = (_a = input.dataset.valEvent) !== null && _a !== void 0 ? _a : defaultEvent;
var events = validateEvent.split(' ');
events.forEach(function (eventName) {
input.addEventListener(eventName, cb.debounced);
});
cb.remove = function () {
events.forEach(function (eventName) {
input.removeEventListener(eventName, cb.debounced);
});
};
this.inputEvents[uid] = cb;
};
ValidationService.prototype.removeInput = function (input) {
Expand Down
2 changes: 1 addition & 1 deletion dist/aspnet-validation.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/aspnet-validation.min.js.map

Large diffs are not rendered by default.

25 changes: 22 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,15 @@ export class ValidationService {
const cb: ValidationEventCallback = async (event, callback) => {
let validate = this.validators[uid];
if (!validate) return true;

if (
!input.dataset.valEvent &&
event && event.type === 'input' &&
!input.classList.contains(this.ValidationInputCssClassName)
) {
Comment on lines +1072 to +1076
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit, but I prefer the logical operators in a multi-line conditional to align on the left. Makes it easier to see all the component conditionals.

Suggested change
if (
!input.dataset.valEvent &&
event && event.type === 'input' &&
!input.classList.contains(this.ValidationInputCssClassName)
) {
if (!input.dataset.valEvent
&& event
&& event.type === 'input'
&& !input.classList.contains(this.ValidationInputCssClassName)
) {

// When no data-val-event specified on a field, "input" event only takes it back to valid. "Change" event can make it invalid.
return true;
}

this.logger.log('Validating', { event });
try {
Expand All @@ -1089,9 +1098,19 @@ export class ValidationService {
}, this.debounce);
};

const validateEvent = input.dataset.valEvent || input instanceof HTMLSelectElement ? 'change' : 'input';
input.addEventListener(validateEvent, cb.debounced);
cb.remove = () => input.removeEventListener(validateEvent, cb.debounced);
const defaultEvent = input instanceof HTMLSelectElement ? 'change' : 'input change';
const validateEvent = input.dataset.valEvent ?? defaultEvent;
const events = validateEvent.split(' ');

events.forEach((eventName) => {
input.addEventListener(eventName, cb.debounced);
});

cb.remove = () => {
events.forEach((eventName) => {
input.removeEventListener(eventName, cb.debounced);
});
};

this.inputEvents[uid] = cb;
}
Expand Down
Loading