Skip to content

Commit da04d3c

Browse files
authored
Merge pull request #31 from dahlbyk/form-submit
Prevent Recursive Validation
2 parents 4ba3e3a + 4c6e0c3 commit da04d3c

File tree

10 files changed

+56
-46
lines changed

10 files changed

+56
-46
lines changed

Controllers/Validations.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ namespace DemoWeb.Controllers;
55
public class ValidationsController : Controller
66
{
77
[HttpPost]
8-
public IActionResult CheckRemote()
8+
public IActionResult CheckRemote(string id)
99
{
10-
return Ok(false);
10+
return Ok(id == "42");
1111
}
1212

1313
[HttpGet]

Pages/Index.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
<script src="/dist/aspnet-validation.js"></script>
3131
<script>
32-
const service = new aspnetValidation.ValidationService();
32+
const service = new aspnetValidation.ValidationService(console);
3333
service.bootstrap();
3434
</script>
3535
</body>

Pages/Index.cshtml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public class IndexModel : PageModel
1010
public string? StatusMessage { get; set; }
1111

1212
[BindProperty]
13+
[Display(Name = "Id (42)")]
1314
[Required]
1415
[Remote("CheckRemote", "Validations", HttpMethod = "Post")]
1516
public string? Id { get; set; }

dist/aspnet-validation.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,12 @@ var ValidationService = /** @class */ (function () {
717717
if (this.elementEvents[formUID]) {
718718
return;
719719
}
720+
var validating = false;
720721
var cb = function (e, callback) {
722+
// Prevent recursion
723+
if (validating) {
724+
return;
725+
}
721726
if (!_this.shouldValidate(e)) {
722727
return;
723728
}
@@ -730,7 +735,10 @@ var ValidationService = /** @class */ (function () {
730735
e.preventDefault();
731736
e.stopImmediatePropagation();
732737
}
738+
validating = true;
739+
_this.logger.log('Validating', form);
733740
validate.then(function (success) {
741+
_this.logger.log('Validated (success = %s)', success, form);
734742
var isProgrammaticValidate = !e;
735743
if (success) {
736744
if (isProgrammaticValidate) {
@@ -756,7 +764,9 @@ var ValidationService = /** @class */ (function () {
756764
_this.focusFirstInvalid(form);
757765
}
758766
}).catch(function (error) {
759-
console.log(error);
767+
_this.logger.log('Validation error', error);
768+
}).finally(function () {
769+
validating = false;
760770
});
761771
};
762772
form.addEventListener('submit', cb);

dist/aspnet-validation.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/aspnet-validation.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "aspnet-client-validation",
3-
"version": "0.8.2",
3+
"version": "0.8.3",
44
"description": "Enables ASP.NET MVC client-side validation, without jQuery!",
55
"main": "dist/aspnet-validation.js",
66
"style": "dist/aspnet-validation.css",

src/index.ts

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface Logger {
2121
}
2222

2323
const nullLogger = new (class implements Logger {
24-
log(_: string, ...args: any[]): void {}
24+
log(_: string, ...args: any[]): void { }
2525
})();
2626

2727
/**
@@ -685,57 +685,67 @@ export class ValidationService {
685685
return;
686686
}
687687

688+
let validating = false;
688689
let cb = (e: Event, callback?: Function) => {
690+
// Prevent recursion
691+
if (validating) {
692+
return;
693+
}
694+
689695
if (!this.shouldValidate(e)) {
690696
return;
691697
}
692698

693699
let validate = this.getFormValidationTask(formUID);
694700
if (!validate) {
695701
return;
696-
}
702+
}
697703

698-
//Prevent the submit before validation
699-
if (e) {
700-
e.preventDefault();
701-
e.stopImmediatePropagation();
702-
}
704+
//Prevent the submit before validation
705+
if (e) {
706+
e.preventDefault();
707+
e.stopImmediatePropagation();
708+
}
709+
710+
validating = true;
711+
this.logger.log('Validating', form);
703712

704713
validate.then(success => {
714+
this.logger.log('Validated (success = %s)', success, form);
705715
let isProgrammaticValidate = !e;
706716
if (success) {
707717
if (isProgrammaticValidate) {
708718
callback(true);
709719
return;
710720
}
711721
const validationEvent = new CustomEvent('validation',
712-
{
713-
detail: { valid: true }
714-
});
715-
form.dispatchEvent(validationEvent);
722+
{
723+
detail: { valid: true }
724+
});
725+
form.dispatchEvent(validationEvent);
716726

717-
//Resubmit the form here, after the async validation is completed.
718-
form.requestSubmit();
727+
//Resubmit the form here, after the async validation is completed.
728+
form.requestSubmit();
719729

720730
return;
721-
}
722-
731+
}
723732

724733
const validationEvent = new CustomEvent('validation',
725-
{
726-
detail: { valid: false }
727-
});
734+
{
735+
detail: { valid: false }
736+
});
728737
form.dispatchEvent(validationEvent);
729738

730-
731739
if (isProgrammaticValidate) {
732740
callback(false);
733741
}
734742
else {
735743
this.focusFirstInvalid(form);
736744
}
737745
}).catch(error => {
738-
console.log(error);
746+
this.logger.log('Validation error', error);
747+
}).finally(() => {
748+
validating = false;
739749
});
740750
};
741751

@@ -936,8 +946,7 @@ export class ValidationService {
936946
return async () => {
937947

938948
// only validate visible fields
939-
if (!this.isHidden(input))
940-
{
949+
if (!this.isHidden(input)) {
941950
for (let key in directives) {
942951
let directive = directives[key];
943952
let provider = this.providers[key];
@@ -986,7 +995,7 @@ export class ValidationService {
986995
* @returns
987996
*/
988997
private isHidden(input: HTMLElement) {
989-
return !(this.allowHiddenFields || input.offsetWidth || input.offsetHeight || input.getClientRects().length );
998+
return !(this.allowHiddenFields || input.offsetWidth || input.offsetHeight || input.getClientRects().length);
990999
}
9911000

9921001
/**
@@ -1024,7 +1033,7 @@ export class ValidationService {
10241033
}
10251034

10261035
// If the document is done loading, scan it now.
1027-
if(document.readyState === 'complete' || document.readyState === 'interactive') {
1036+
if (document.readyState === 'complete' || document.readyState === 'interactive') {
10281037
init();
10291038
}
10301039
else {
@@ -1061,15 +1070,15 @@ export class ValidationService {
10611070
}
10621071

10631072
private observed(mutation: MutationRecord) {
1064-
if(mutation.type === 'childList') {
1065-
for(let i = 0; i < mutation.addedNodes.length; i++) {
1073+
if (mutation.type === 'childList') {
1074+
for (let i = 0; i < mutation.addedNodes.length; i++) {
10661075
let node = mutation.addedNodes[i];
10671076
this.logger.log('Added node', node);
10681077
if (node instanceof HTMLElement) {
10691078
this.scan(node);
10701079
}
10711080
}
1072-
} else if(mutation.type === 'attributes') {
1081+
} else if (mutation.type === 'attributes') {
10731082
if (mutation.target instanceof HTMLElement) {
10741083
const oldValue = mutation.oldValue ?? '';
10751084
const newValue = mutation.target.attributes[mutation.attributeName]?.value ?? '';

yarn.lock

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -908,11 +908,6 @@
908908
"resolved" "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz"
909909
"version" "3.5.2"
910910

911-
912-
"integrity" "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
913-
"resolved" "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz"
914-
"version" "1.0.0"
915-
916911
"fill-range@^4.0.0":
917912
"integrity" "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc="
918913
"resolved" "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz"
@@ -999,11 +994,6 @@
999994
"resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
1000995
"version" "1.0.0"
1001996

1002-
"fsevents@~2.1.2":
1003-
"integrity" "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ=="
1004-
"resolved" "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz"
1005-
"version" "2.1.3"
1006-
1007997
"get-caller-file@^2.0.1":
1008998
"integrity" "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
1009999
"resolved" "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"

0 commit comments

Comments
 (0)