Below is my Component :
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { HttpService } from './http.service';
import { ProjectidService } from './projectid.service';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
 projectDetailForm: FormGroup;
  public submitted = false;
  constructor(private fb: FormBuilder, private projectidvalidator: ProjectidService) { }
  ngOnInit() {
    this.projectDetailForm = this.fb.group({
      projectid: ['', [Validators.required], [this.projectidvalidator.validate.bind(this.projectidvalidator)]],
      projectname: ['name', Validators.required]
    })
  }
  get f() { return this.projectDetailForm.controls; }
  get validprojectid() { return this.projectDetailForm.get('projectid'); }
  onSubmit(form: FormGroup) {
    this.submitted = true;
    // stop here if form is invalid
    if (this.projectDetailForm.invalid) {
      return;
    }
    console.log('Valid?', this.projectDetailForm.valid); // true or false
    console.log('ID', this.projectDetailForm.value.projectid);
    console.log('Name', this.projectDetailForm.value.projectname);
  }
}
My Service :
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { delay, tap, debounceTime } from 'rxjs/operators';
@Injectable()
export class HttpService {
  constructor() { }
  checkProjectID(id): Observable<any> {
     // Here I will have valid HTTP service call to check the data
     return of(true)
  }
}
My Async validator :
import { HttpService } from './http.service';
import { Injectable } from '@angular/core';
import { AsyncValidator, AbstractControl, ValidationErrors } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { map, catchError, debounceTime, switchMap } from 'rxjs/operators';
@Injectable()
export class ProjectidService {
  constructor(private _httpService:HttpService) { }
    validate(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
        console.log(control.value);
        return control.valueChanges.pipe(
            debounceTime(500),
            switchMap(_ => this._httpService.checkProjectID(control.value).pipe(
                map(isTaken => {
                    console.log(isTaken);
                    if (isTaken) {
                        return { noproject: true }
                    } else {
                        return null
                    }
                })
            )),
            catchError(() => null)
        );
    }
}
and template :
<form [formGroup]="projectDetailForm" name="projectdetails" (ngSubmit)="onSubmit(projectDetailForm)">
    <div class="form-group">
        <label for="id">Project ID</label>
        <input type="text" class="form-control" id="id" [ngClass]="{ 'is-invalid': f.projectid.invalid && (f.projectid.dirty || f.projectid.touched) }" placeholder="Project ID" name="projectid" formControlName='projectid'>
        <button type="button">Validate</button>
        <div *ngIf="f.projectid.invalid && (f.projectid.dirty || f.projectid.touched)" class="invalid-feedback">
            <div *ngIf="f.projectid.errors.required">Project ID is required</div>
            <div *ngIf="f.projectid.errors?.noproject">
                Project id is not valid
            </div>
        </div>
        <div *ngIf="f.projectid.errors?.noproject">
            Project id is not valid
        </div>
        {{f.projectid.errors | json}}
    </div>
    <div class="form-group">
        <label for="name">Project Name</label>
        <input type="text" class="form-control" id="name" placeholder="Project Name" name="projectname" readonly formControlName='projectname'>
    </div>
    <div class="form-group d-flex justify-content-end">
        <div class="">
            <button type="button" class="btn btn-primary">Cancel</button>
            <button type="submit" class="btn btn-primary ml-1">Next</button>
        </div>
    </div>
</form>
Problem is my custom async validation error message is not getting displayed.
Here is stackblitz example
 
     
     
     
    