Skip to content

Commit

Permalink
Listen for removed inputs and unregister them
Browse files Browse the repository at this point in the history
  • Loading branch information
LiteracyFanatic committed Aug 11, 2023
1 parent ab9ef9c commit 4e551a9
Showing 1 changed file with 71 additions and 9 deletions.
80 changes: 71 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -518,13 +518,17 @@ export class ValidationService {
/**
* Scans document for all validation message <span> generated by ASP.NET Core MVC, then tracks them.
*/
private scanMessages(root: ParentNode) {
private scanMessages(root: ParentNode, remove: boolean = false) {
/* If a validation span explicitly declares a form, we group the span with that form. */
let validationMessageElements = Array.from(root.querySelectorAll<HTMLElement>('span[form]'));
for (let span of validationMessageElements) {
let form = document.getElementById(span.getAttribute('form'));
if (form) {
this.pushValidationMessageSpan(form, span);
if (remove) {
this.removeValidationMessageSpan(form, span);
} else {
this.pushValidationMessageSpan(form, span);
}
}
}

Expand All @@ -540,7 +544,11 @@ export class ValidationService {
let validationMessageElements = Array.from(form.querySelectorAll<HTMLElement>('[data-valmsg-for]'));

for (let span of validationMessageElements) {
this.pushValidationMessageSpan(form, span);
if (remove) {
this.removeValidationMessageSpan(form, span);
} else {
this.pushValidationMessageSpan(form, span);
}
}
}
}
Expand All @@ -557,6 +565,19 @@ export class ValidationService {
}
}

private removeValidationMessageSpan(form: HTMLElement, span: HTMLElement) {
let formId = this.getElementUID(form);
let name = `${formId}:${span.getAttribute('data-valmsg-for')}`;
let spans = this.messageFor[name] || (this.messageFor[name] = []);
let index = spans.indexOf(span);
if (index >= 0) {
spans.splice(index, 1);
}
else {
this.logger.log("Validation element for '%s' was already removed", name, span);
}
}

/**
* Given attribute map for an HTML input, returns the validation directives to be executed.
* @param attributes
Expand Down Expand Up @@ -649,7 +670,10 @@ export class ValidationService {

for (let i = 0; i < formInputUIDs.length; i++) {
let inputUID = formInputUIDs[i];
formValidators.push(this.validators[inputUID]);
const validator = this.validators[inputUID];
if (validator) {
formValidators.push(validator);
}
}

let tasks = formValidators.map(factory => factory());
Expand Down Expand Up @@ -895,6 +919,20 @@ export class ValidationService {
this.elementEvents[formUID] = cb;
}

private untrackFormInput(form: HTMLFormElement, inputUID: string) {
let formUID = this.getElementUID(form);
if (!this.formInputs[formUID]) {
this.formInputs[formUID] = [];
}
let indexToRemove = this.formInputs[formUID].indexOf(inputUID);
if (indexToRemove >= 0) {
this.formInputs[formUID].splice(indexToRemove, 1);
}
else {
this.logger.log("Form input for UID '%s' was already removed", inputUID);
}
}

/**
* Adds an input element to be managed and validated by the service.
* Triggers a debounced live validation when input value changes.
Expand Down Expand Up @@ -935,10 +973,22 @@ export class ValidationService {
this.elementEvents[uid] = cb;
}

removeInput(input: ValidatableElement) {
let uid = this.getElementUID(input);

delete this.summary[uid];
delete this.elementEvents[uid];
delete this.validators[uid];

if (input.form) {
this.untrackFormInput(input.form, uid);
}
}

/**
* Scans the entire document for input elements to be validated.
*/
private scanInputs(root: ParentNode) {
private scanInputs(root: ParentNode, remove: boolean = false) {
let inputs = Array.from(root.querySelectorAll<ValidatableElement>(validatableSelector('[data-val="true"]')));

// querySelectorAll does not include the root element itself.
Expand All @@ -949,7 +999,12 @@ export class ValidationService {

for (let i = 0; i < inputs.length; i++) {
let input = inputs[i];
this.addInput(input);
if (remove) {
this.removeInput(input);
}
else {
this.addInput(input);
}
}
}

Expand Down Expand Up @@ -1210,10 +1265,10 @@ export class ValidationService {
/**
* Scans the provided root element for any validation directives and attaches behavior to them.
*/
scan(root: ParentNode) {
scan(root: ParentNode, remove: boolean = false) {
this.logger.log('Scanning', root);
this.scanMessages(root);
this.scanInputs(root);
this.scanMessages(root, remove);
this.scanInputs(root, remove);
}

/**
Expand Down Expand Up @@ -1243,6 +1298,13 @@ export class ValidationService {
this.scan(node);
}
}
for (let i = 0; i < mutation.removedNodes.length; i++) {
let node = mutation.removedNodes[i];
this.logger.log('Removed node', node);
if (node instanceof HTMLElement) {
this.scan(node, true);
}
}
} else if (mutation.type === 'attributes') {
if (mutation.target instanceof HTMLElement) {
const oldValue = mutation.oldValue ?? '';
Expand Down

0 comments on commit 4e551a9

Please sign in to comment.