Hallo,
Das Problem ist, dass mit field.setCustomValidity(msg) nicht der Inhalt der jeweils in der Schleife gesetzten Variable msg mit der richtigen Fehlermeldung gesetzt wird, sondern bei allen Durchgängen der Wert aus dem letzten Arrayelement.
Ja, richtig beobachtet. Das liegt daran, dass die erzeugte Handlerfunktion eine Closure ist und über msg auf die Variablen des äußeren Gültigkeitsbereichs zugreift. In dem Moment, in dem die Funktion ausgeführt wird, ist der äußere Code komplett durchgelaufen und damit hat msg den Wert der letzten Zuweisung.
Das liegt daran, dass das gesamte Variablenobjekt des äußeren Scopes in der Scope-Chain liegt. Es werden also keine einzelnen Variablen mit ihrem aktuellen Wert eingeschlossen, sondern das ganze Variablenobjekt wird konserviert und bleibt verfügbar, wie es ist. Zur Erklärung der Interna siehe http://molily.de/javascript-core/.
In deinem Code ist msg anscheinend eine globale Variable, was die Sache etwas ändert, aber das Grundprinzip ist dasselbe. Es sollte natürlich eine lokale Variable sein – nicht das »var« vergessen! Das würde aber nichts im Hinblick auf deine Frage ändern.
Es gibt hier verschiedene Lösungsmöglichkeiten. Eine einfache ist, für jeden Schleifendurchlauf eine Funktion auszuführen, die die Message als Parameter/Variable hat und deren Wert sich nicht ändert.
var setValidityMessage = function(id, msg) {
$('#' + id).on('change invalid', function() {
// Diese Funktion schließt die Variablen des setValidityMessage-Aufrufs ein,
// id und msg sind die richtigen und ändern sich nicht mehr
var field = $(this).get(0);
field.setCustomValidity('');
if (!field.validity.valid) {
field.setCustomValidity(msg);
}
});
};
$('#submit').on('click', function() {
for (var i = 0, l = fields.length; i < l; i++) {
var id = …;
var msg = …;
setValidityMessage(id, msg);
}
});
Mathias