Search code examples
htmlnode.jsangulartypescript

Why my form validation while logging in is not working?


my ts component file :

import { Component, inject } from '@angular/core';
import { HeaderComponent } from "../header/header.component";
import { FormBuilder, Validators } from '@angular/forms';
import { timer } from 'rxjs';
import { Router, RouterModule } from '@angular/router';
import { AuthService } from '../../auth.service';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
@Component({
    selector: 'app-login',
    standalone: true,
    templateUrl: './login.component.html',
    styleUrl: './login.component.css',
    imports: [HeaderComponent,CommonModule,ReactiveFormsModule]
})
export class LoginComponent {
  
    isLoginInProgress: boolean | undefined;
    errorMessage: string | null = null; 
    
    form = this.fb.nonNullable.group({ 
      email: ['', Validators.required],
      password: ['', Validators.required],
    });
    
    constructor(
      private fb: FormBuilder, 
      private authService: AuthService,
      ) {
      
      const accessToken = localStorage.getItem('accessToken');
      if (accessToken) {
        window.history.back();
      }
    }
     router = inject(Router);
  
    // fb = inject(FormBuilder);
    // http = inject(HttpClient);
    //  authService = inject(AuthService);
    data: any[] = [];
    
    validateEmail(email: string): boolean {
      if (!email) {
        return true; // Consider email field valid if empty (adjust if needed)
      }
      const emailRegex = /^\S+@\S+\.\S+$/; 
      return emailRegex.test(email);
    }
    

    noemail=false;
    noform=false;
    nopwd=false;
    login=false;
  
    onSubmit(): void {
      this.errorMessage = null;
        this.noemail = false;
        this.noform = false;
        this.nopwd = false;
        console.log('Form submitted');
        const rawform = this.form.getRawValue();
        const email = rawform.email.trim();
        this.isLoginInProgress = true;
        this.authService
          .login(email, rawform.password.trim())
          .subscribe({
            next: (response) => {
              console.log(response!.user!.uid);
              const accessToken = response!.user!.accessToken;
              const user_uid = response!.user!.uid;
              localStorage.setItem('accessToken', accessToken);
              localStorage.setItem('user_uid', user_uid);
              this.router.navigateByUrl('/');
              window.location.reload();
              this.isLoginInProgress = false;
            },
            error: (err: any) => {
              this.handleAuthError(err);
              this.isLoginInProgress = false;
            },
          });
        if (!email) {
          this.noemail = true 
  
          this.noform=false
          // Email not entered
        } 
        if (!this.validateEmail(email)) {
          this.noemail=false
          this.nopwd=false
          this.noform=true 
          // Invalid email format
        }
        else
        {
          
          this.noform=false
        }
  
        
        const mdp=rawform.password.trim();
        if(!mdp ) 
          {
            this.nopwd=true
          }  
    }
  
    handleAuthError(err: any): void {
      console.error('Authentication Error:', err); 
      const rawform = this.form.getRawValue();// Log the error object for inspection
      const email = rawform.email.trim();
      switch (err.code) {
        case 'auth/invalid-credential':
          this.errorMessage = 'Invalid password or email';
          this.nopwd=false
          this.noemail=false
          this.noform=false
          break;
        case 'auth/invalid-email' :
          if (email)
            {
              this.nopwd=false
              
            }
          break;
        case this.validateEmail(email)  :
          this.noform=false
          this.noemail=false
          break; 
      }
  
    }
  
    isLoggedIn(): boolean {
      const hasAccessToken = localStorage.getItem('accessToken') !== null;
      
      timer(1000);
      if (hasAccessToken) {
        return true;
      } else {     
        return false;
      }
    }
   
    
}

my html component content :

<app-header style="background: linear-gradient(to left ,#032961,#4588ee);"></app-header>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link href="/assets/css/styles.css" rel="stylesheet">
  <link href="/assets/bootstrap/bootstrap.css" rel="stylesheet">
 
  
</head>
<body class="form-v9" style="background: linear-gradient(to left ,#032961,#4588ee); ">
    <div class="page-content">
        <div class="form-v9-content" >
            <form [formGroup]="form" (ngSubmit)="onSubmit()" class="form-detail" action="#" method="post">
                <h2>Login Form</h2>
                <div class="form-row-total">
                        
                        <div *ngIf="login" class="alert alert-success" role="alert">
                            Login avec succés
                        </div>
                    <div class="form-row">
                        <input type="text" name="email" id="email" class="input-text" placeholder="Your Email" required pattern="[^@]+@[^@]+.[a-zA-Z]{2,6}">
                    </div>
                    <div *ngIf="errorMessage" class="alert alert-danger" role="alert">
                        {{ errorMessage }}
                      </div>
                          <div *ngIf="noemail " class="alert alert-danger" role="alert">
                              Enter an email
                          </div> 
                          <div *ngIf="noform" class="alert alert-danger" role="alert">
                              Invalid email form
                          </div>
                </div>
                <div class="form-row-total">
                    <div class="form-row">
                        <input type="password" name="password" id="password" class="input-text" placeholder="Your Password" required>
                    </div>
                    
                    <div *ngIf="errorMessage" class="alert alert-danger" role="alert" >
                        {{ errorMessage }}
                      </div>
                    <div *ngIf="nopwd" class="alert alert-danger" role="alert"  style="margin-top: 90px;">
                        Enter a password                    </div>
                    
                </div>
                <div class="form-row-last">
                    <input type="submit" name="register" class="register" value="Log in" >
                </div>
            </form>
        </div>
    </div>
</body>

whenever i press on login button ( either the fields are empty or not ) , the shown messages are "Enter a password " & "Enter an email " ( which means that the variables 'nopwd' and 'noemail' have always true as value ) , where is exactly the problem ? and what should i change ?


Solution

  • Seems like you forgot to add formControlName in your inputs.

    <input type="text" formControlName="email" name="email" id="email" class="input-text" placeholder="Your Email" required pattern="[^@]+@[^@]+.[a-zA-Z]{2,6}">
    
    <input type="password" formControlName="password" name="password" id="password" class="input-text" placeholder="Your Password" required>
    

    I tried to improve your code.

    component.ts

    import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';
    import { Router, RouterOutlet } from '@angular/router';
    import { AuthService } from '../../auth.service';
    import { Location } from '@angular/common';
    import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
    import { CustomValidators } from './custom-validators';
    import { catchError, of, take, tap } from 'rxjs';
    import { HttpErrorResponse } from '@angular/common/http';
    
    @Component({
      selector: 'app-login',
      standalone: true,
      templateUrl: './login.component.html',
      styleUrl: './login.component.css',
      imports: [RouterOutlet, ReactiveFormsModule],
      changeDetection: ChangeDetectionStrategy.OnPush,
    })
    export class AppComponent {
      private readonly _router = inject(Router);
      private readonly _location = inject(Location);
      private readonly _authService = inject(TestAuthService);
    
      authError = signal<boolean>(false);
      isLoginInProgress = signal<boolean>(false);
    
      form = new FormGroup({
        email: new FormControl<string>('', { nonNullable: true, validators: [Validators.required, CustomValidators.email] }),
        password: new FormControl<string>('', { nonNullable: true, validators: [Validators.required] }),
      });
    
      login = false; // it's always false O_o
    
      constructor() {
        const accessToken = localStorage.getItem('accessToken');
        if (accessToken) this._location.back();
      }
    
      onSubmit(): void {
        this.isLoginInProgress.set(true);
        this._authService
          .login(this.form.controls.email.value.trim(), this.form.controls.password.value.trim())
          .pipe(
            catchError((error: HttpErrorResponse) => {
              this.handleAuthError(error);
              return of(error);
            }),
            tap(response => this._handleLogin(response)),
        finalize(() => this.isLoginInProgress.set(false))
          )
          .subscribe();
      }
    
      private _handleLogin(response: any): void {
        if (!response?.user) return;
    
        const accessToken = response.user.accessToken;
        const user_uid = response.user.uid;
        localStorage.setItem('accessToken', accessToken);
        localStorage.setItem('user_uid', user_uid);
        this._router.navigateByUrl('/');
        window.location.reload();
      }
    
      handleAuthError(err: HttpErrorResponse): void {
        if (!err.error.code) return;
    
        this.authError.set(true);
        this.form.valueChanges
          .pipe(
            take(1),
            tap(() => this.authError.set(false))
          )
          .subscribe();
      }
    
      isLoggedIn(): boolean {
        return localStorage.getItem('accessToken') !== null
      }
    }
    

    component.html

    <form [formGroup]="form" (ngSubmit)="onSubmit()" class="form-detail">
      <h2>Login Form</h2>
      <div class="form-row-total">
    
        @if(login) {
          <div class="alert alert-success" role="alert">
            Login avec succés
          </div>
        }
    
        <div class="form-row">
          <input type="text" formControlName="email" name="email" id="email" class="input-text" placeholder="Your Email" required pattern="[^@]+@[^@]+.[a-zA-Z]{2,6}">
        </div>
        @if (authError()) {
          <div class="alert alert-danger" role="alert">
            Invalid password or email
          </div>
        }
        @if (form.controls.email.errors?.required) {
          <div class="alert alert-danger" role="alert">
            Enter an email
          </div>
        }
        @if (form.controls.email.errors?.email) {
          <div class="alert alert-danger" role="alert">
            Invalid email form
          </div>
        }
      </div>
    
      <div class="form-row-total">
        <div class="form-row">
          <input type="password" formControlName="password" name="password" id="password" class="input-text" placeholder="Your Password" required>
        </div>
    
        @if (authError()) {
          <div class="alert alert-danger" role="alert" >
            Invalid password or email
          </div>
        }
    
        @if (form.controls.password.errors?.required) {
          <div class="alert alert-danger" role="alert"  style="margin-top: 90px;">
            Enter a password
          </div>
        }
    
      </div>
      <div class="form-row-last">
        <input type="submit" name="register" class="register" value="Log in" [disabled]="!form.valid" >
      </div>
    </form>
    

    custom-validators.ts

    import { AbstractControl, ValidationErrors } from '@angular/forms';
    
    export class CustomValidators {
      static email(control: AbstractControl<string>): ValidationErrors | null {
        const emailRegex = new RegExp(/^\S+@\S+\.\S+$/);
    
        if (!control.value) return null;
        return emailRegex.test(control.value) ? null : { email: true };
      }
    }