js/views/register.js — strength and async
In the code column — js/views/register.js, the most complex form in the course. Three new things.
1. Password strength. checkPassword (from validation.js) returns a score 0–4 and the gaps:
export function checkPassword(password) {
let score = 0; const errors = [];
if (password.length >= 8) score++; else errors.push('At least 8 characters.');
if (/[a-z]/.test(password) && /[A-Z]/.test(password)) score++; else errors.push('Mix of case.');
if (/\d/.test(password)) score++; else errors.push('A number.');
if (/[^A-Za-z0-9]/.test(password)) score++; else errors.push('A symbol.');
return { score, label: ['Very weak','Weak','Fair','Good','Strong'][score], errors };
}
On input, the meter bar and the checklist update live — the user watches the strength climb.
2. Confirmation matching — cross-field, checked live. matches(values.password, ...) is a rule. But there's a subtlety: if you already entered the confirmation and then change the first password, the confirmation must re-validate immediately:
passwordInput.addEventListener('input', () => {
const confirm = form.querySelector('[name="confirmPassword"]');
if (confirm.value) {
setFieldError(form, 'confirmPassword',
confirm.value === passwordInput.value ? '' : 'Passwords do not match.');
}
});
3. Async check. "Is the username taken?" on blur:
usernameInput.addEventListener('blur', async () => {
usernameInput.classList.add('checking'); // a spinner
const taken = await isUsernameTaken(value); // a simulated server request
usernameInput.classList.remove('checking');
if (taken) setFieldError(form, 'username', `"${value}" is already taken.`);
});
Verify. In the register form:
1. Type a password → the meter climbs, requirements get ✓.
2. Confirmation doesn't match → error; fix the first password → the error clears live.
3. Enter "admin" and leave the field → after ~half a second: "already taken".
Gotcha (async races). Async checks can race: type "admin" (a slow check in flight), then "adm002" (a fast check returns first). Unguarded, an older response can overwrite a newer one and show an error for the wrong name. Real fixes: debounce + "latest wins" (by a request sequence number). In lesson 17 we'll see how types help model that "loading / loaded / error" state safely.