Showing an error message upon submission in Angular 4 according to the server's response

Struggling for hours to display an error message when a form submits and returns an error status code. The solution seems elusive...

In the login form component below, I've indicated where I would like to indicate whether the form is valid or invalid.

import { Component, OnInit, Input, Output, EventEmitter  } from '@angular/core';
import { Router } from '@angular/router';
import { FormBuilder, FormGroup, Validators, NgForm } from "@angular/forms";
import { AuthenticationService } from "../../../services/authentication.service";
import { User } from "../../../domain/user";


@Component({
  selector: 'login-form',
  templateUrl: './login-form.component.html'
})
export class LoginFormComponent implements OnInit {

  loginForm: FormGroup;
  post: any;
  username: string;
  password: string;
  user: User;
  errorMessage: string  = '';


  constructor(private fb: FormBuilder, private router: Router, private authenticationService: AuthenticationService) {
    this.loginForm = fb.group({
      'username': [null, Validators.required],
      'password': [null, Validators.required],
      'login': false
    });
  }


  ngOnInit() {
    this.authenticationService.logout(); // reset login status
  }


  login(values) {
    this.username = values.username;
    this.password = values.password;

    this.authenticationService.login(this.username, this.password)
      .subscribe(result => {
          if (result === true) {
            this.router.navigate(['/']);
            localStorage.setItem('currentUser', JSON.stringify(this.user));
            // here form should be valid
          } else {
            this.errorMessage = 'Username or password is incorrect';
            // here form should be invalid
          }
      });
  }
}

Login Form Html, the second <div> is the error id like shown after the form submits.

<form id="loginForm" [formGroup]="loginForm" (ngSubmit)="login(loginForm.value)" novalidate>
  <div class='form-text error' *ngIf="submitted">
    <div *ngIf="loginForm.invalid" class="help-block error small">Username or password is incorrect.</div>
  </div>
  <div class="form-group">
    <label class="control-label" for="username">Username</label>
    <input type="text" placeholder="Please enter your usename" title="Please enter you username" required value=""
           id="username" class="form-control" name="username" formControlName="username">
    <div class='form-text error' *ngIf="loginForm.controls.username.touched">
      <div *ngIf="loginForm.controls.username.hasError('required')" class="help-block error small">Username is required.</div>
    </div>
    <span *ngIf="loginForm.controls.username.valid || !loginForm.controls.username.touched"  class="help-block small">Your unique username</span>
  </div>
  <div class="form-group">
    <label class="control-label" for="password">Password</label>
    <input type="password" title="Please enter your password" placeholder="******" required value=""
           id="password" class="form-control" name="password" formControlName="password">
    <div class='form-text error' *ngIf="loginForm.controls.password.touched">
      <div *ngIf="loginForm.controls.password.hasError('required')" class="help-block error small">Password is required.</div>
    </div>
    <span *ngIf="loginForm.controls.password.valid || !loginForm.controls.password.touched" class="help-block small">Your strong password</span>
  </div>
  <div>
    <button type="submit" class="btn btn-accent" [disabled]="!loginForm.valid">Login</button>
    <a class="btn btn-default" routerLink="/register">Register</a>
  </div>
</form>

Answer №1

There seems to be an error on the server side, but your form is valid here. Therefore, make sure to set the flag to false in your failure handler.

Component:

Start by creating a variable for it:

export class LoginFormComponent implements OnInit {

  loginForm: FormGroup;
  post: any;
  username: string;
  password: string;
  user: User;
  errorMessage: string = '';
  authenticationFlag: boolean = true;

In your login method:

login(values) {
    this.username = values.username;
    this.password = values.password;

    this.authenticationService.login(this.username, this.password)
      .subscribe(result => {
          if (result === true) {
            this.router.navigate(['/']);
            localStorage.setItem('currentUser', JSON.stringify(this.user));
            // The form should be valid at this point
          } else {
             this.authenticationFlag = false;
          }
      });
  }

HTML Template:

Replace this code:

<div class='form-text error' *ngIf="submitted">
    <div *ngIf="loginForm.invalid" class="help-block error small">Username or password is incorrect.</div>
</div>

With this:

<div *ngIf="!authenticationFlag" class="help-block error small">Username or password is incorrect.</div>

Answer №2

After realizing that I wasn't handling errors properly in my authentication service class, I decided to make some changes. One of the key adjustments was adding a catch block to my login method within the authentication service.

  login(username: string, password: string): Observable<boolean> {
    let user = JSON.stringify({ username: username, password: password });
    let headers = new Headers({ 'Content-Type': 'application/json' });
    let options = new RequestOptions({ headers: headers });

    return this.http.post(this.loginUrl, user, options)
      .map(function(res){
        let data = res.json();
        alert(res.status);

        if (data) {
          this.token = data.token;
          localStorage.setItem('currentUser', JSON.stringify({ username: username, token: this.token }));
          return true; // successful login
        } else {
          return false; // failed login
        }
      })
      .catch((error:any) => Observable.throw(error.json().error || 'Server error'));
  }

In addition, I made changes to the use of the login method in my login form component:

  login(values) {
    this.username = values.username;
    this.password = values.password;

    this.authenticationService.login(this.username, this.password)
      .subscribe(result => {
          if (result === true) {
            this.router.navigate(['/']);
            localStorage.setItem('currentUser', JSON.stringify(this.user));
          }
      },
      err => {
        this.authenticationFlag = false;
      });
  }

It became clear to me, as @Wasif Khan pointed out in his answer, that all I needed was a simple component variable - a concept too complex to be explained in a mere comment.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 5 - Creating a dynamic function that generates a different dynamic function

One of my latest projects involved creating a versatile function that generates switch-case statements dynamically. export function generateReducer(initialState, reducerName: ReducerName, adapter: EntityAdapter<any>): (state, initialState) => ISt ...

Minimum width of Angular Material's mat-menu

I am looking to create a compact Material mat-menu using Angular 15. Below is the code I have: <mat-menu #flagMenu="matMenu"> <button mat-menu-item> <img src="assets/flags/en.png" class="flag"/> ...

Developing a personalized Avada form auto-scrolling algorithm

Our form, created using the Wordpress - Avada theme, needs an autoscroll feature. As users answer questions, the next question appears below, but this is not immediately visible on mobile devices. To address this, we require autoscroll functionality. The ...

Adjust the size of each link in the highchart network diagram

Is it feasible to individually set the length of each link in a network graph using highcharts? I am interested in creating a visualization where each user is displayed at varying distances from the main center user. I have been experimenting with the lin ...

What could be causing the need for RxJs TypeScript files to be requested exclusively when my website is hosted on IIS?

When I develop my site using Visual Studio / IIS Express, everything runs smoothly without any unusual requests or 404 errors. However, once I publish the site to IIS and try to run it, I start receiving multiple requests for typescript files (.ts), prima ...

The Angular Date Pipe is currently unable to display solely the Month and Year; it instead presents the complete date, including day, month,

I'm currently using the Bootstrap input date feature to save a new Date from a dialog box. However, I only want to display the month and year when showing the date. Even though I added a pipe to show just the month and year, it still displays the mont ...

The class 'GeoJSON' is mistakenly extending the base class 'FeatureGroup'

Encountering an error message in one of my projects: test/node_modules/@types/leaflet/index.d.ts(856,11): error TS2415: Class 'GeoJSON' incorrectly extends base class 'FeatureGroup'. Types of property 'setStyle' are incompa ...

Generate an object in Typescript that includes a dynamic property calculated from an input parameter

Is there a way to achieve the following function in TypeScript? function f<T extends 'a' | 'b'>(t : T): {[t]: ...} { return {[t]: ...} } This code is intended to make f('a') have type {'a': ...} and similarl ...

Obtain a hidden item using *ngIf in Angular for testing purposes

Snippet of HTML Code: <div *ngIf="state"> <p>some text<p> <button (click)="increment()" class="myButton">Increment</button> </div> My Component Structure: @Component( ...

Experiencing difficulty accessing the response header in Angular 16 due to CORS restrictions

When attempting to retrieve the response header from my post call, I am encountering difficulties as it appears there are "no headers" or I may be doing something incorrectly. On the backend, I am utilizing ASP.NET Core. Below is a basic outline of my API ...

Form-select failing to transmit data

There seems to be an issue with one specific HTML field not sending data. This is my HTML code: <form id="login_registro_form" role="form" method="post" action="./controllers/register.php"> <div cl ...

Managing sessions in Typescript using express framework

Hey there, I'm just starting to learn about TypeScript and I have a question about how sessions are handled in Typescript. Could someone please explain the process of session initialization, storing user data in sessions, etc.? If you have any tutoria ...

The entry for "./standalone" in the "@firebase/database-compat" package does not have any documented conditions

Upon running npm run build for my sveltekit project, I encountered the following error generated by vite: 7:55:49 PM [vite-plugin-svelte] When trying to import svelte components from a package, an error occurred due to missing `package.json` files. Contact ...

Launching Angular (2.x and above) into various platforms via bootstrapping

According to the Angular documentation, there are various bootstrapping options available for targeting different platforms. Angular offers a variety of ways to bootstrap applications for multiple platforms In their guide, they demonstrate how to boots ...

Angular 6 - accepting an HTTP GET request as the app loads

Upon the initial startup of my Angular application, just before its pages are loaded onto the user's browser, I aim to retrieve certain information from the HTTP request that triggered the app's launch. More precisely, I am looking to obtain the ...

`AngularJS Voice Recognition Solutions`

In my quest to implement voice recognition in an AngularJS application I'm developing for Android and Electron, I've encountered some challenges. While I've already discovered a suitable solution for Android using ng-speech-recognition, fin ...

Is there a simple method to eliminate devDependencies from the ultimate package using esbuild?

My current challenge involves using esbuild to package my lambda functions. However, during the build generation for deployment, I encounter an alert indicating that the package size exceeds the limit, as shown in the image below. File too large In explo ...

Concealing a column within an Angular Material table

I'm currently faced with a challenge involving an Angular Material table containing numerous columns. My goal is to selectively hide certain columns based on specific CSS media queries. This is the code snippet I have experimented with so far: HTML: ...

NEXT JS 13 experiencing an infinite loop when using State, encountering an error with Params, and facing issues with hook definition

Currently, I am in the process of developing a shopping cart using NEXT JS and encountering several issues within my code. To begin with, I have established a route [product]/[productitems] within the apps folder. In the page.tsx file of [productitems], I ...

Guide on setting up redux store from server component using next.js and app router

I'm currently working with Next.js 13, React, and Redux to handle state management. My main objective is to fetch initial data on the server side and present it on the client side. Although I assumed this would be a typical approach with Redux and Ne ...