Vertraging HTML5: ongeldige pseudo-klasse tot de eerste gebeurtenis

Ik heb onlangs ontdekt dat de : ongeldige pseudo-class van toepassing is op vereiste formulierelementen zodra de pagina wordt geladen. Als u bijvoorbeeld deze code heeft:


…
<input name="foo" required />

Uw pagina wordt vervolgens geladen met een leeg roze invoerelement erop. De validatie die is ingebouwd in HTML5 is geweldig, maar ik denk niet dat de meeste gebruikers verwachten dat het formulier wordt gevalideerd voordat ze de kans hebben gekregen om waarden in te voeren. Is er een manier om de toepassing van de pseudo-klasse uit te stellen tot de eerste gebeurtenis die van invloed is op dat element (formulierinzending, vervagen, wijzigen, wat dan ook van toepassing is)? Is het mogelijk om dit zonder JavaScript te doen?

48
Ik kan geen commentaar geven, dus ik zal dit supplement toevoegen aan @ user3284463 De makeDirty mag de vuile class niet omschakelen, het moet het behouden op toekomstige (blauwe, ongeldige, geldige) evenementen functie makeDirty (e ) {if (! e.target.classList.contains ('dirty')) e.target.classList.add ('dirty'); }
toegevoegd de auteur Abir Stolov, de bron

9 antwoord

http://www.alistapart.com/articles/forward-thinking-form-validation/

Omdat we alleen willen aangeven dat een veld ongeldig is zodra het veld ongeldig is   focus, gebruiken we de focus pseudo-klasse om de ongeldige stijl te activeren.   (Uiteraard worden alle verplichte velden vanaf het begin als ongeldig gemarkeerd   zou een slechte ontwerpkeuze zijn.)

Als u deze logica volgt, ziet uw code er ongeveer zo uit ...


<script>
  document.addEventListener('DOMContentLoaded', function() {
    var required = document.querySelectorAll('input:required');
    for (var i = 0; i < required.length; ++i) {
      (function(elem) {
        function removeClass(name) {
          if (elem.classList) elem.classList.remove(name);
          else
            elem.className = elem.className.replace(
              RegExp('(^|\\s)\\s*' + name + '(?:\\s+|$)'),
              function (match, leading) {return leading;}
          );
        }

        function addClass(name) {
          removeClass(name);
          if (elem.classList) elem.classList.add(name);
          else elem.className += ' ' + name;
        }

       //If you require a class, and you use JS to add it, you end up
       //not showing pink at all if JS is disabled.
       //One workaround is to have the class on all your elements anyway,
       //and remove it when you set up proper validation.
       //The main problem with that is that without JS, you see what you're
       //already seeing, and stuff looks hideous.
       //Unfortunately, you kinda have to pick one or the other.


       //Let non-blank elements stay "touched", if they are already,
       //so other stuff can make the element :invalid if need be
        if (elem.value == '') addClass('touched');

        elem.addEventListener('blur', function() {
          addClass('touched');
        });

       //Oh, and when the form submits, they need to know about everything
        if (elem.form) {
          elem.form.addEventListener('submit', function() {
            addClass('touched');
          });
        };
      })(required[i]);
    }
  });
</script>

En natuurlijk werkt het niet zoals in IE8 of lager, omdat (a) DOMContentLoaded relatief nieuw is en niet standaard was toen IE8 uitkwam, (b) IE8 gebruikt attachEvent in plaats van de DOM-standaard addEventListener , en (c) IE8 zal sowieso niet om : required geven, omdat het HTML technisch niet ondersteunt 5.

1
toegevoegd

I created a small shim to deal with this in my codebase. I just start off with my <form/> element having the novalidate property along with a data-validate-on="blur" attribute. This watches for the first event of that type. This way you can still use the native :invalid CSS selectors for the form styling.

$(function() {
    $('[data-validate-on]').each(function() {
        var $form = $(this);
        var event_name = $form.data('validate-on');

        $form.one(event_name, ':input', function (event) {
            $form.removeAttr('novalidate');
        });
    });
});
1
toegevoegd

Een goede manier is om : invalid,: valid abstract te maken met een CSS-klassen en vervolgens met wat JavaScript om te controleren of het invoerveld is gefocust of niet.

CSS:

input.dirty:invalid{ color: red; }
input.dirty:valid{ color: green; }

JS:

// Function to add class to target element
function makeDirty(e){
  e.target.classList.toggle('dirty');
}

// get form inputs
var inputs = document.forms[0].elements;

// bind events to all inputs
for(let input of inputs){
  input.addEventListener('invalid', makeDirty);
  input.addEventListener('blur', makeDirty);
  input.addEventListener('valid', makeDirty);
}

DEMO

0
toegevoegd