Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save nuxodin/73a2c2423cbbf6818c28ad803985d5c7 to your computer and use it in GitHub Desktop.
Save nuxodin/73a2c2423cbbf6818c28ad803985d5c7 to your computer and use it in GitHub Desktop.
Polyfill for reportValidity()
/* Copyright (c) 2016 Tobias Buschor https://goo.gl/gl0mbf | MIT License https://goo.gl/HgajeK */
if (!HTMLFormElement.prototype.reportValidity) {
HTMLFormElement.prototype.reportValidity = function() {
if (this.checkValidity()) return true;
var btn = document.createElement('button');
this.appendChild(btn);
btn.click();
this.removeChild(btn);
return false;
};
}
if (!HTMLInputElement.prototype.reportValidity) {
HTMLInputElement.prototype.reportValidity = function(){
if (this.checkValidity()) return true
var tmpForm;
if (!this.form) {
tmpForm = document.createElement('form');
tmpForm.style.display = 'inline';
this.before(tmpForm);
tmpForm.append(this);
}
var siblings = Array.from(this.form.elements).filter(function(input){
return input !== this && !!input.checkValidity && !input.disabled;
},this);
siblings.forEach(function(input){
input.disabled = true;
});
this.form.reportValidity();
siblings.forEach(function(input){
input.disabled = false;
});
if (tmpForm) {
tmpForm.before(this);
tmpForm.remove();
}
this.focus();
this.selectionStart = 0;
return false;
};
}
@mockdeep
Copy link

mockdeep commented Jun 2, 2019

I'm curious why we couldn't call submit() if it's invalid and avoid shuffling buttons:

if (!HTMLFormElement.prototype.reportValidity) {
    HTMLFormElement.prototype.reportValidity = function() {
      if (this.checkValidity()) return true;
      this.submit();
      return false;
    }
}

Calling this.checkValidity() should make sure we don't call this.submit() when it's valid, so it will only cause the validation messages to appear.

@nuxodin
Copy link
Author

nuxodin commented Jun 3, 2019

Hmm, I guess you're right, I don't remember what thoughts I had.

@nuxodin
Copy link
Author

nuxodin commented Jun 3, 2019

No sorry, you are wrong, this.submit() will submit the form, regardless of validity.

@mockdeep
Copy link

mockdeep commented Jun 3, 2019

@nuxodin hmm, yeah, I just tried it again and it submits. Something must have been wrong with whatever I tried yesterday.

@lukescott
Copy link

lukescott commented Jun 12, 2019

I needed a way to reportValidity on a specific input instead of just the form. Thought I would share:

function reportValidity(input) {
	if (input.checkValidity()) {
		return true
	}
	if (input.reportValidity) {
		input.reportValidity()
	} else if (input.form) {
		const form = input.form
		const siblings = Array.from(form.elements).filter(
			e => e !== input && !!e.checkValidity && !e.disabled
		)
		for (const sibling of siblings) {
			sibling.disabled = true
		}
		const button = document.createElement("button")
		form.appendChild(button)
		button.click()
		form.removeChild(button)
		for (const sibling of siblings) {
			sibling.disabled = false
		}
	} else {
		input.focus()
	}
	return false
}

It's based on the same concept, but takes advantage of the fact that the html5 form validation api ignores disabled inputs.

@nuxodin
Copy link
Author

nuxodin commented Jun 13, 2019

@lukescott
Great Work!
I updated my gist with a similiar polyfill.

  • handles Inputs without a form
  • extended Native HTMLInputElement
  • reused the form.reportValidity-polyfill
  • no es6 for ie11
  • but it needs some polyfills for ie11 (Array.from, Element-Methods: before, after and remove)
  • tested in ie11 but not in old safaris

@lukescott
Copy link

lukescott commented Jun 13, 2019

@nuxodin I think there is a bug. It looks like you still use this.form when it could be undefined. You probably want this:

if (!HTMLInputElement.prototype.reportValidity) {
    HTMLInputElement.prototype.reportValidity = function(){
        if (this.checkValidity()) return true
        var form = this.form;
        var tmpForm;
        if (!form) {
            tmpForm = document.createElement('form');
            tmpForm.style.display = 'inline';
            this.before(tmpForm);
            tmpForm.append(this);
        }
        var siblings = Array.from(form.elements).filter(function(input){
            return input !== this && !!input.checkValidity && !input.disabled;
        },this);
        siblings.forEach(function(input){
            input.disabled = true;
        });
       form.reportValidity();
        siblings.forEach(function(input){
            input.disabled = false;
        });
        if (tmpForm) {
            tmpForm.before(this);
            tmpForm.remove();
        }
        this.focus();
        this.selectionStart = 0;
        return false;
    };
}

Although as far as I know html5 validation doesn't work without a form tag anyway. So it probably isn't necessary to support inputs that aren't inside form tags.

Also the focus() in my implementation is a fallback. The submit/reportValidity already does this. I could probably remove it entirely.

@nuxodin
Copy link
Author

nuxodin commented Jun 13, 2019

My Polyfill works at least in IE.
I use this.form and if this.form is undefined, I wrap it into a newly created form.
So this.form is always defined.

I don't know exactly how it is in the specification, but validation works without forms in current browsers:
https://jsfiddle.net/7jode1g5/

focus() and selectionstart=0 is needed in IE11

@BrodaNoel
Copy link

In line 19 you are definingvar tmpForm , but it's already defined 2 lines above.

@BrodaNoel
Copy link

BrodaNoel commented Sep 10, 2019

I recommend wrapping all that code in:

if (typeof HTMLFormElement !== 'undefined') {
 // your polyfill
}

So then it'll be also compatible with server side rendering.

@mcshaz
Copy link

mcshaz commented Apr 17, 2020

this is the form version, which and seems to work in IE11, and accounts for the case the form has a novalidate attribute, in which case the form would submit.
https://gist.github.com/mcshaz/c65040c11e6daffe356cbedb7ec84ce4

@RodrigoNovais
Copy link

Is there anyway to intercept or listen if reportValidity has been called?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment