Instructor: In this example here, we have defined a login service, which is quite simple. It has a log method, which gets a message as a string, and then it logs into the console. We registered this service here in the app module in the provider section.
We have basically that person component, which gets an instance here via the dependency injection mechanism. Whenever you press that button, it uses that login service to log to the console. If you dig here, you can see the message is being printed out here in our devtools console.
Imagine we define a new login service. We have quite a large application, let's call this newLoggerService.ts. We can simply, for now, copy that over. We call that newLoggerService, and here, we say new logger, and print out the message. The API stays exactly the same.
We might change some implementation internally, and we will like then to refactor our application to use that new login service. First of all, we obviously need to register that in that provider section here. We have to wire in here that newLoggerService. That needs to get imported here for us.
We would like that our entire application now uses that newLoggerService wherever we have that loggerService defined. Our person component should now pick up the newLoggerService, without us having to change the entire application.
There's a mechanism called aliasing. What we can do here is to write this in its full form. We can say here provide a logger service, but use an existing, which would be our newLoggerService.
Obviously, the API here of that newLoggerService and that loggerService have to be the same. For that reason, it's also probably convenient in a real application to use an interface, which then, at compile time, would alert you in terms of compilation errors.
We can click that log to console button, and you can see now that the new logger is being picked up instead of that old logger. We actually didn't have to change any kind of implementation, but we did wire it up with this useExisting.
At this point, you might ask yourself, "Why not use the useClass basically, and override, basically, that logger service with the new logger service?" That would work perfectly, but there's one key difference here.
When using useClass, we will get two different kind of instances for those components or services which use that loggerService as an import and those that use newLoggerService as in import. Instead, if we use useExisting, we will use the exact same instance and have just a single one for the entire application.