2

I'm fairly new to Angular 2+, so please bear with me if I'm way off. My goal is to have a shared notification service to be used throughout the application. For the most part, I got it working fine. It is a lazy module structure, so in order to not have issues with multiple instances (took me a while to figure this one out) I had to add a forRoot() method to my SharedModule class as such:

export class SharedModule {
 static forRoot(): ModuleWithProviders {
  return {
    ngModule: SharedModule,
    providers: [
      NotificationService,
      {
        provide: ErrorHandler,
        useClass: ErrorHandlerService
      }]
  };
}

}

Then, the SharedModule is added to the AppModule calling forRoot():

@NgModule({
 declarations: [...],
 imports: [
  ...
  SharedModule.forRoot()
  ...
 ],
 providers: [...],
 bootstrap: [...]
})
export class AppModule { }

I was happy to see that the notification service worked fine from my lazy modules by simply adding SharedModule to the lazy loaded module and then making notificationService calls from the components.

The problem is with the global error handler (provided in the forRoot() in SharedModule, see above), it looks like it might be creating a second instance of notification service and it doesn't work properly.

I guess first of all, am I structuring this correctly? If so, what am I doing wrong so that the notification service acts weird?

Here's the code for the error handler service:

     import { ErrorHandler, Injectable, Injector } from '@angular/core';
import { Router } from '@angular/router';
import { HttpErrorResponse } from '@angular/common/http';
import { NotificationService } from './notification.service';

@Injectable()
export class ErrorHandlerService implements ErrorHandler {
  constructor(private injector: Injector) { }

  handleError(error: Error) {
    const notificationService = this.injector.get(NotificationService);
    const router = this.injector.get(Router);
    if (error instanceof HttpErrorResponse) {
      if (!navigator.onLine) {

      } else {
        console.log('Http error!');
        notificationService.error('Error!', error.message);
      }
    } else {

    }
    console.error('It happens: ', error);
  }
}

Again, calling notification service from components works fine, the behavior is completely different when calling from the error handler service. The behavior I get is similar to the one I was getting from components BEFORE adding the forRoot() method to the SharedModule module, thus the theory of multiple instances.

Any help appreciated. Thanks

--- EDIT ---

I've created Stackblitz to show the different behavior when calling notification service from a component vs from the error handler service. The show notification button shows the notification as intended, but when making an error http call, notice that the first time you click, the notification doesn't show, and if keep playing with it, it will sometimes go away all of the sudden, or not go away at all, whereas you cannot make the same happen when using the show notification button.

Click here for Stackblitz

1
  • Do you need a shared module? Seems that this would be easier/simpler if you just built the shared services and injected them where you need them. Commented Aug 1, 2018 at 17:39

2 Answers 2

1

After spending a few hours looking at this ... it appears that when you are throwing the http exception, that the UI is not picking up the changes.

You may have to ask another question of someone more familiar with change detection to determine exactly why ... but here is a work around to fix it.

In the notification component:

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';

  constructor(private notificationService: NotificationService, private cd: ChangeDetectorRef) { }

  ngOnInit() {
    this.notificationService.getNotification().subscribe((notification: Notification) => {
      if (notification) {
        this.show = true;
        this.notification = notification;
        this.cd.detectChanges();        // <- Add this line
        // the rest of your code here
      }
    });
  }

Here is another post for more information and with some links to articles on change detection: How to trigger a change event manually - angular2

If you are just starting out, you could also consider using NgRx which helps you manage your state and notifications.

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

1 Comment

You're the best, that worked, thank you! Also, I've fixed the issue with the subscribe being called multiple times, it was a rookie mistake: accidentally used interval instead of timeout. Btw, I think I might have been to one of your talks at a conference a couple of years ago, AngularJS back then! Anyway, thanks again, this was driving me crazy :)
0

If you build a simple notification service using the providedIn property of the Injectable decorator, you will only get one instance. You don't need to create a sharedModule.

You could then inject the notification service into the ErrorHandler service.

@Injectable({
  providedIn: 'root'
})
export class ErrorHandlerService {
   // ...
   constructor(private notificationService: NotificationService) {}
}

But based on the code you posted, I assume I'm missing some key point as to the purpose of the added complexity of that code?

6 Comments

Thank you Deborah. Here's what I tried, I added the providedIn to the service and removed it completely from the SharedModule, including the NotificationComponent. I added both NotificationService and NotificationComponent directly to the AppModule, but unfortunately I'm still getting the same behavior :(
Can you build a stackblitz that demonstrates the issue so we can better help you?
Oh my, I can try. It's a large project , but yeah, that's a good idea, I'll try to have the basics and see if I can reproduce. If you or anyone else has any other ideas, by all means, please let me know. :)
We definitely don't want the large project ... just the two services (notification and error handling) along with a simple component to see them in action (and hopefully illustrate your issue).
Deborah, thank you again for the help. I've created a stackblitz to show the behavior I'm getting. I've updated the original question to include the link. Notice that clicking show notification one or many times works fine, but when clicking the error http call button, the notification acts strangely
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.