Success/Error Handling

When we perform an HTTP request and get an error, we want to notify the user about the error. There are several methodologies you can use to do that:

Local Component Error

A local component error is when only the current component needs to know about the error, so we can set it once in the component and forget about it.

todos.service.ts
todos.component.ts
class TodosService {
updateTodo() {
return this.http.post().pipe(
tap(() => this.store.updateEntity(...))
)
}
}
@Component({
template: `<div *ngIf="error">{{error}}</div>`
})
class TodosComponent {
updateTodo() {
this.todosService.updateTodo().subscribe({
error(error) {
this.error = error;
}
})
}
}

The benefit is that we don't need to save the error in the store and reset it on destroy.

A different case is when you don't need to show the error in the component because you're using a global alert framework for example. In such case, you can do it directly on the service.

todos.service.ts
import { throwError } from 'rxjs';
ā€‹
class TodosService {
constructor(private toaster: Toaster) {}
updateTodo() {
return this.http.post().pipe(
tap(() => this.store.updateEntity(...)),
catchError((err) => {
this.toaster.error(...);
return throwError(err);
})
)
}
}

Global Error

If you want to communicate the error to other components or services you can save the error in the store.

todos.service.ts
todos.component.ts
class TodosService {
constructor(private toaster: Toaster) {}
updateTodo() {
return this.http.post().pipe(
tap(() => this.store.updateEntity(...)),
catchError((err) => {
this.store.setError(error);
return throwError(err);
})
)
}
}
@Component({
template: `<div *ngIf="error | async">{{error}}</div>`
})
class TodosComponent {
error$ = this.todosQuery.selectError();
updateTodo() {
this.todosService.updateTodo().subscribe();
}
}

If you choose this path, don't forget to reset the error when you need to.

Success Notifications

The same also applies to success notifications. Let's say we need to show our users a success notification after they add a new todo. When we require to show the notification in the component, we'll do the following:

todos.service
todos.component.ts
class TodosService {
addTodo(todo) {
return this.http.post(url, todo).pipe(
tap(() => this.store.add(todo)),
)
}
}
@Component({
template: `<div *ngIf="success">šŸ¦„</div>`
})
class TodosComponent {
addTodo() {
this.todosService.addTodo(this.todoForm.value).subscribe({
next() {
this.success = true;
},
error() { ... }
})
}
}

Otherwise, we can call the notification service in the service:

todos.service
class TodosService {
constructor(private toaster: Toaster) {}
addTodo(todo) {
return this.http.post(url, todo).pipe(
tap(() => {
this.store.add(todo);
this.toaster.success('šŸ¦„');
}),
)
}
}