Skip to content

destructor option for service providers #11228

Closed

Description

@pjordaan
[ ] bug report => search github for a similar issue or PR before submitting
[X ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior
See example below:

@Injectable()
export class GlobalServiceProvidedInBootstrap {
    public subscribe(f: Function);
    public unsubscribe(f: Function);
}
export function callback() {
};

@Injectable()
export class ServiceProvidedInElement {
    constructor(public service: GlobalServiceProvidedInBootstrap) {
        service.subscribe(callback);
    }
}
@Component({
    selector: 'example-tag',
     providers: [ServiceProvidedInElement]
})
export class ExampleTagComponent {
    constructor(private s: ServiceProvidedInElement) {
    }
    public ngOnDestroy() {
        this.s.service.unsubscribe(callback);
    }
}

The problem I'm having in similar code is that the moment this component is destroyed, there is no way for me to unsubscribe ServiceProvidedInElement from GlobalServiceProvidedInBootstrap unless I use ngOnDestroy in the component.

Expected/desired behavior
The expected behavior is that when I declare my providers, I should be able to set a callback to destroy my service provided. So instead of using ngOnDestroy I could do it like this:

export SERVICE_PROVIDED_IN_ELEMENT_PROVIDERS = [
    {
        token: ServiceProvidedInElement,
        useDestructor: function (element: ServiceProvidedInElement) {
              element.service.unsubscribe(callback);
        }
    }
];

Activity

  1. added
    featureLabel used to distinguish feature request from other issues
    on Sep 1, 2016
  2. added
    area: coreIssues related to the framework runtime
    and removed on Sep 7, 2016
  3. DzmitryShylovich commented on Nov 12, 2016

    @DzmitryShylovich
    Contributor

    Services already have ngOnDestroy hook so it can be closed.

  4. zoechi commented on Nov 14, 2016

    @zoechi
    Contributor

    I have never seen it mentioned that ngOnDestroy is supported on services.
    The docs say "when a directives or pipe is destroyed" https://angular.io/docs/ts/latest/api/core/index/OnDestroy-class.html

  5. DzmitryShylovich commented on Nov 14, 2016

    @DzmitryShylovich
    Contributor
  6. zoechi commented on Nov 14, 2016

    @zoechi
    Contributor

    I guess the docs on the interface should be updated then

  7. added 2 commits that reference this issue on Dec 13, 2016
    1d0ed6f
    9e0e6b5
  8. maxkoretskyi commented on Jun 7, 2017

    @maxkoretskyi

    @DzmitryShylovich, there is no longer logging in the console in the plunker you referenced when a component is destroyed. Has anything changed?

  9. willshowell commented on Jun 29, 2017

    @willshowell
    Contributor

    @MaximusK there was a change in 4.0.0-rc.4 that made providers instantiate lazily.

    Updated plunker: http://plnkr.co/edit/FA9bIc3dEiHundiKx95M?p=preview

  10. 10 remaining items

  11. gparlakov commented on Apr 15, 2018

    @gparlakov
    Contributor

    @aks1994 This is my understanding of what happens:

    1. Whenever the lazy module is first loaded the service gets instantiated and placed in the module's injector
    2. Every subsequent request to that module (to its main component) would use that same instance

    Right?
    (I am not aware of a way of instructing angular to kill off any module or its providers.)

    Provided that you already have guards: Maybe inside of a route guard that is executed on the way in you can clean up/initialize the service i.e. every time user wants to go back to this component the service-s state gets zeroed out.
    Alternatively the service could become a provider of a service-s instead of doing the work itself.

  12. aks1994 commented on Apr 15, 2018

    @aks1994
  13. gparlakov commented on Apr 15, 2018

    @gparlakov
    Contributor

    @aks1994

    For the clean up - I would do it just like you said - set everything back to initial value. And do it /initialize it/ every time you want to use it. The risk is that there might be a confusion about whether or not the state was initialized - so I'd do it every time.

    Elaborating on the provider of services: here. Notice the 'the-service.service.ts' and how it is provided in the module and used in hello.component.ts and app.component.ts. It is providing a new instance for every time we call the .provideAService('somestring') method.

  14. aks1994 commented on Apr 16, 2018

    @aks1994

    @gparlakov

    Okay, makes sense. Thanks for the help and sharing the info on provider of services!

  15. jscharett commented on Jul 6, 2018

    @jscharett

    This seems like a bit of a hack, imo. It would be nice to simply specify my provider in the module and allow the module to destroy it when the user exits the module. The current design can be left in place for backwards compatibility, but why not allow me to specify that the provider gets destroyed every time the use exits the module?

  16. mlc-mlapis commented on Jul 6, 2018

    @mlc-mlapis
    Contributor

    @jscharett ... what is the term exit from the module? What it means for you.

  17. jscharett commented on Jul 6, 2018

    @jscharett

    @mlc-mlapis When my route changes to leave a lazy loaded module. I understand that lazy loading only delays the loading of the module and does not "unload" it when navigating away from it. It just seems like there should be a clean way to "reset/destroy" a provider used in a lazy loaded module.

    For example, in my app, we have a lazy loaded module that when the user enters, create a provider for storing various data. The provider is used across multiple components, so its created in the ng module. When the user navigates away from the module back to the home page, I am required to implement a guard so that I can "cleanup" the data stored in the provider. Not a huge issue, but just seems like it would be beneficial if you could specify a provider that could be destroyed upon exiting the module/route.

    It was not intuitive to me that my provider would continue after navigating away from the module.

  18. Sahil624 commented on Feb 22, 2019

    @Sahil624

    Hi !
    I am also facing same issue. My provider stores some user data that is shared among one or more components for a logged in user. When user logs out and login with any other account user data of previous user is shown in every component.
    Any solution or workaround available ?
    Thanks for any help.

  19. shikharseth commented on May 9, 2019

    @shikharseth

    @Sahil624 any solution you found out for your use case?
    It would be great if you can help me in that too

  20. gparlakov commented on May 9, 2019

    @gparlakov
    Contributor

    @Sahil624 @shikharseth One approach would be providing the provider in the component that needs it. Then It will get instantiated and destroyed along with the component. I am assuming this component would get destroyed when user logs out - because app navigates to logout screen for example

  21. shikharseth commented on May 9, 2019

    @shikharseth

    @gparlakov the use case is quite different here. Since, I require service data to be shared across components so I need to mention my providers inside my app.module.ts. Your's approach wont let me do the same.
    Data sharing is working fine as to my need across different module and component.
    But the scenario is when I logout from one user and login with different app.module don't get destroyed(though component do), due to this service data remains intact and I get same data of my last user on sigining with different user.
    I want to destroy data from my services data defined in app.module

  22. gparlakov commented on May 22, 2019

    @gparlakov
    Contributor

    I want to destroy data from my services data defined in app.module

    @shikharseth It appears that you need to use the onDestroy lifecycle hook to clean up your service.
    Or the logout method needs to actually clear the state of that service. Either way I would create a method on that service onLogout and call it.

  23. Sahil624 commented on May 22, 2019

    @Sahil624

    @Sahil624 any solution you found out for your use case?
    It would be great if you can help me in that too

    Hi !
    Sorry didn't knew about your reply earlier.I did this by making an event service. It was basically a subject in service and I subscribed it in my services which I wanted to destroy (More like i wanted to clear data that was cached in that service). In my logout function i emitted a event (subjectName.next()). Whenever is received anything in by event subscription I cleared my data.
    This is more of a hack. But it was working for me. I cannot share my code at this time but i hope I could explain it will. Feel free in any case of doubt.
    Thanks

  24. angular-automatic-lock-bot commented on Sep 15, 2019

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  25. locked and limited conversation to collaborators on Sep 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: coreIssues related to the framework runtimefeatureLabel used to distinguish feature request from other issuesfreq1: low

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions