borisbaer: JS-Code wird zu früh ausgeführt (fetch, async, await)

Beitrag lesen

problematische Seite

Hallo zusammen,

ich habe folgendes script zur Eingabe-Validierung:

document.addEventListener( 'DOMContentLoaded', () => {
	const forms = document.querySelectorAll( 'form' );
	for ( const form of forms ) {
		form.addEventListener( 'submit', event => {
			const errors = [];
			if ( form.name === 'sign-in' ) {
				errors.push( validate( form.username, [ { rule: 'required' } ] ) );
				errors.push( validate( form.password, [ { rule: 'required' } ] ) );
			}
			let skip;
			errors.forEach( ( error, index ) => {
				if ( error && !skip ) {
					form.querySelectorAll( 'input' )[index].focus();
					event.preventDefault();
					skip = true;
				}
			});
		});
	}
});

Nachdem die validate-Funktionen die Werte true (= es liegt ein Fehler vor) oder false (= es liegt kein Fehler vor) zurückgegeben und sie in das Array errors gepusht wurden, prüft der untere Teil des scripts die Werte dieses Arrays. Sind alle false, darf der Submit ganz normal ausgeführt werden, ansonsten erfolgt ein preventDefault und das erste ungültige Feld wird fokussiert.

Was mir jedoch Probleme bereitet, sind die fetch-Funktionen, die ich an zwei anderen Stellen habe: Einmal bei der Validierung bezüglich der Einzigartigkeit der Werte (ob z.B. der Benutzername schon vergeben ist) und einmal bei der Handhabung der Darstellung der Fehlermeldungen.

Die validate-Funktion habe ich als async definiert, denn andernfalls kommt es gar nicht zum preventDefault und der Submit geht jedesmal durch.

Die Error-Handling-Funktion mit der fetch-Funktion sieht folgendermaßen aus:

function manageError( input, rule, condition, errors, tooltip = null, param = null ) {
	fetch( '../pages/user/error-messages.json' )
	.then( response => {
		if ( !response.ok )
			throw `${response.status} ${response.statusText}`; 
		return response.json();
	})
	.then ( ( rules ) => {
		const name = input.name;
		let errorMessage;
		for ( let entry of rules[rule] )
			if ( entry[name] )
				errorMessage = entry[name].replace( '%s', param );
		if ( condition ) {
			errors.push( errorMessage );
			addErrorMessage( input, rule, errorMessage, tooltip );
		} else removeErrorMessage( input, rule, errorMessage, tooltip );
	})
	.catch( error => {
		console.log( error );
		return null;
	});
}

Hier gibt es ebenfalls ein errors-Array, das die Fehlermeldungen sammelt. Dieses Array wird an die übergeordnete validate-Funktion übergeben. Wenn mindestens eine Fehlermeldung vorliegt, dann gibt die validate-Funktion (wie oben beschrieben) ein true oder false aus:

if ( errors.length > 0 )
	return true;
else return false;

Jedenfalls kommt auf der obersten Ebene, nachdem alle validate-Funktionen durch sind, beim ersten errors-Array immer ein Array mit Promises mit dem Wert false heraus. Also: Alles okay, es liegen keine Fehler vor, obwohl Fehlermeldungen angezeigt werden. Trotzdem geht der Submit nicht durch.

Es muss an den fetch-Funktionen und deren Timing liegen. Ich habe versucht, mich in die fetch-Funktion einzulesen mit den Promises, async, await usw., aber ich blicke einfach nicht durch.

Hier kann man sich anschauen, was die Konsole ausgibt, wenn man auf den Submit-Button klickt.

errors[0].then( ( value ) => { console.log( value ) } );

Lange Rede, kurzer Sinn: Ich möchte, dass dieser Teil hier …

let skip;
errors.forEach( ( error, index ) => {
	if ( error && !skip ) {
		form.querySelectorAll( 'input' )[index].focus();
		event.preventDefault();
		skip = true;
	}
});

... erst feuert, wenn die fetch-Funktion alle Werte übergeben hat und ich möchte, dass die validate-Funktion auch wirklich den richtigen true/false-Wert zurückgibt.

Ich wäre sehr dankbar für jede Hilfe.

Grüße
Boris

akzeptierte Antworten