4

I am trying to show and hide HTML elements according to the service result. I am using *ngIf="messageService.getData() | async" but it isn't working to show or hide the element. I am using async, otherwise "Failure Message" is shown for a short time and then "Successful Message" is shown.

I have 2 tags like these:

<div *ngIf="messageService.getData() | async">Successful Message</div>
<div *ngIf="!messageService.getData() | async">Failure Message</div>

In the service I have a code like this:

export class MessageService {
  constructor(private http: HttpClient) { }

  public getData() {
    return this.http.get("https://jsonplaceholder.typicode.com/todos/1")
    .pipe(
      map((response) => {
        console.log("success");
      }),
      catchError(this.handleError)
    )
  }

  private handleError(error: Response) {
    console.log("handleError")
    let errMsg: string;
    errMsg = "error"
    return Observable.throw(errMsg);
  }
}

Here is the source code: https://stackblitz.com/edit/angular-iqr6az

3 Answers 3

7

in your service:

public getData() {
    return this.http.get("https://jsonplaceholder.typicode.com/todos/1")
    .pipe(
      map((response) => {
        return response; // return res
      }),
      catchError(this.handleError)
    )
  }

in your component:

export class MessageComponent implements OnInit {
  isServiceAPIWorking: boolean;
  todos;
  loadingError$ = new Subject<boolean>();
  constructor(private messageService: MessageService) { }

  ngOnInit() {
    this.todos = this.messageService.getData().pipe(
      catchError((error) => {
        // it's important that we log an error here.
        // Otherwise you won't see an error in the console.
        console.error('error loading the list of users', error);
        this.loadingError$.next(true);
        return of();
      })
    );
  }
}

in your html:

<div>Show Message:</div>
<div *ngIf="todos | async">Successfull Message</div>
<div *ngIf="loadingError$ | async">Failure Message</div>

DEMO.

Sign up to request clarification or add additional context in comments.

2 Comments

well done @Fateme this is the best answer i see and also i do when i face such a problem.
@FatemeFazli I am trying to see the "Failure Message" but it is giving Observable.throw is not a function error. I changed it to "throwError" but it is still not displaying.
1

Why bother with async pipes when you can just assign the data in your component?

// message.component.ts

class MessageComponent implements OnInit {
  isServiceAPIWorking: boolean;
  data: any;
  constructor(private messageService: MessageService) { }

  ngOnInit() {
    this.messageService.getData()
      .subscribe(response => {
        this.isServiceAPIWorking = true;
        // Assign the data
        this.data = response;
      },
        error => {
          this.isServiceAPIWorking = false;
        })
  }
}
// message.component.html

<div>Show Message:</div>
<div *ngIf="data">Successfull Message</div>
<div *ngIf="!data">Failure Message</div>

And there is a mistake in your service. If you use map without returning anything, you won't get any data in the end. Use tap if you want to do logging:

// message.service.ts

public getData() {
  return this.http.get("https://jsonplaceholder.typicode.com/todos/1")
  .pipe(
    tap((response) => {
      console.log("success");
    }),
    catchError(this.handleError)
  )
}

Updated Stackblitz

2 Comments

If you don't use async, "Failure Message" is shown for a short time and then "Sucess Message" is shown.
Yeah, sure, I just adapted your logic but you can do more clever things to do what you want.
1

This is a wrong usage of async pipe not in syntactical but in semantic way. Every time a change detection triggered, you are making an HTTP request.

Rather than checking with async pipe, you can store two flags (boolean variables) or one boolean variable for HTTP request and one variable for response.

Below example is using two flags.

export class MessageService {

  isLoaded = false;
  hasError  = false;

  constructor(private http: HttpClient) { }

  public getData() {
    this.isLoaded = false;
    this.http.get("https://jsonplaceholder.typicode.com/todos/1")
    .subscribe(
       (response) => {
           this.hasError = false;
           this.isLoaded = true;
       },
       (error) => {  
           this.hasError = true;
           this.isLoaded = true;
       },
    )
  }
}

And in the template:

<ng-container *ngIf="isLoaded">
    <div *ngIf="!hasError">Successfull Message</div>
    <div *ngIf="hasError">Failure Message</div>
</ng-container>

2 Comments

I see your point but if you don't use async, "Failure Message" is shown for a short time on page load.
Hmm.. Swapping the assigning of isLoaded and hasError has any effect? Updated the answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.