Validate the avatar upload
Angular · Angular · intermediate · greenfield
Adds the standalone `AvatarUploadComponent`: validates the picked file's MIME type and size, shows a specific `role="alert"` error for each failure mode, and emits valid files through a signal output. Resets the input value after every pick so re-selecting the same file works. Tried a GIF, an 8 MB JPEG, and a 5 MB-on-the-nose PNG.
Requirements
- Add an avatar picker: a single-file input that accepts only PNG or JPEG images up to 5 MB (5 * 1024 * 1024 bytes, inclusive — a file of exactly 5 MB is allowed).
- Validation is by the file's MIME type (`image/png` / `image/jpeg`); the input's `accept` attribute is a convenience, not the enforcement.
- An invalid pick shows a specific error message (wrong type vs too large) announced to assistive technology; a valid pick clears any error and emits the file to the parent.
- Picking the same file again after a failed attempt must re-trigger validation (native inputs don't fire `change` for the same path unless the value is reset).
- Cancelling the file dialog changes nothing.
Files touched
- src/app/profile/avatar-upload.component.ts
--- src/app/profile/avatar-upload.component.ts
+import { Component, output, signal } from '@angular/core';
+
+const MAX_BYTES = 5 * 1024 * 1024;
+const ALLOWED_TYPES = ['image/png', 'image/jpeg'];
+
+@Component({
+ selector: 'app-avatar-upload',
+ standalone: true,
+ template: `
+ <label>
+ Avatar (PNG or JPEG, max 5 MB)
+ <input type="file" accept="image/png,image/jpeg" (change)="onPick($event)" />
+ </label>
+ @if (error(); as message) {
+ <p class="error" role="alert">{{ message }}</p>
+ }
+ `,
+ styles: `
+ .error {
+ color: var(--danger-fg);
+ }
+ `,
+})
+export class AvatarUploadComponent {
+ readonly fileSelected = output<File>();
+
+ protected readonly error = signal<string | null>(null);
+
+ protected onPick(event: Event): void {