Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

1.5 Feature: Backport ngOnDestroy (as $onDestroy for example) exactly as ngOnInit ($onInit) #14020

Closed
radek-anuszewski opened this issue Feb 12, 2016 · 5 comments · Fixed by #14302

Comments

@radek-anuszewski
Copy link

In new 1.5.0 release is possible to use $onInit hook which is similar to ngOnInit from Angular 2 lifecycle hooks. It will help with keeping controller's constructors clean, with initialization logic moved to the $onInit method.
I think worth consideration is backport also ngOnDestroy, as $onDestroy for example.

Use Case:

In recent project in my company on of the business rules is to send request to device every second (which we have done with timeouts). We try to stay away as possible from injecting $scope to controllers, but timeouts needs to be cleared when user opens new view or hits back button on mobile device etc... So we solved this with $scope.$on:

$scope.$on('$destroy', function () {
      viewModel.removeIntervals();
});

And it's only one direct usage of $scope at this moment. If we have $onDestroy hook, code would be like:

viewModel.$onDestroy =  function () {
      viewModel.removeIntervals();
});

And we can get rid off $scope injection completely. Also, it let us keep code closer to Angular 2 syntax.

Thank you in advance for looking on this post.

Best regards,
Radek.

@dcherman
Copy link
Contributor

👏 , would love to have something like this.

@shlomiassaf
Copy link

We have a workaround for this, i'll share it.
We use it until it will be supported and it works quite well.

We register our first run block and request the $injector service.
We monkey patch the $injector.instantiate method and inside register the $onDestory event, if needed.

angular.module('app').run(['$injector', function($injector) {
    var $instantiate = $injector.instantiate;
    $injector.instantiate = function (Type, locals, serviceName) {
        var instance = $instantiate.call(this, Type, locals, serviceName);
        if (instance.$onDestroy && typeof instance.$onDestroy === 'function') && locals && locals.$scope) {
            locals.$scope.$on('$destroy', function() {instance.$onDestroy()});
        }
        return instance;
    }
}]);

This is a very simple example of the idea, I converted it real time from TypeScript and removed internal utils so I hope its correct.

Some notes:

Its important to note that it will not work on "child" injectors, i.e injectors created using angular.injector factory, to support it angular.injector should be monkey patched as well, returning a monkey patched version of the injector (using the code above) checking if it was patched, if not returning a patched version...

We never tried using a decorator for this, I'm not sure its even possible to get the $injector service from a decorator, but if its possible it might be better designed (but who cares...)

This is a very simple hack to support this feature until it lands.

bobbijvoet pushed a commit to bobbijvoet/angular.js that referenced this issue Feb 24, 2016
Introduce a destroy hook for directives which follows the ng2 component lifecycle

Closes angular#14020
dcherman added a commit to dcherman/angular.js that referenced this issue Feb 25, 2016
As a complement to the `$onInit` lifecycle hook, the `$onDestroy`
lifecycle hook allows one to wire up cleanup behavior in a controller that
will be invoked for you at the appropriate time.

Fixes angular#14020
bobbijvoet pushed a commit to bobbijvoet/angular.js that referenced this issue Feb 25, 2016
Bind $onDestroy handler to the controller instance

Closes angular#14020
bobbijvoet pushed a commit to bobbijvoet/angular.js that referenced this issue Feb 25, 2016
Call $onDestroy when element is removed, possibility to set $onDestroy method after controller initialization

Closes angular#14020
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 22, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$afterViewInit` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 23, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$afterViewInit` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
Closes angular#14302
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 23, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$afterViewInit` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
Closes angular#14302
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 23, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$afterViewInit` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
Closes angular#14302
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 23, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$postLink` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
Closes angular#14302
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 23, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$postLink` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
Closes angular#14302
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 23, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$postLink` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
Closes angular#14302
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 23, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$postLink` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
Closes angular#14302
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 23, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$postLink` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
Closes angular#14302
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 24, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$postLink` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
Closes angular#14302
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 24, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$postLink` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
Closes angular#14302
petebacondarwin added a commit to petebacondarwin/angular.js that referenced this issue Mar 25, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$postLink` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes angular#14127
Closes angular#14030
Closes angular#14020
Closes angular#13991
Closes angular#14302
petebacondarwin added a commit that referenced this issue Mar 25, 2016
This change adds in the following new lifecycle hooks, which map in some
way to those in Angular 2:

 * `$onChanges(changesObj)` - Called whenever one-way bindings are updated. The `changesObj` is a hash whose keys
   are the names of the bound properties that have changed, and the values are an object of the form
   `{ currentValue: ..., previousValue: ... }`. Use this hook to trigger updates within a component such as
   cloning the bound value to prevent accidental mutation of the outer value.
 * `$onDestroy` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
   external resources, watches and event handlers.
 * `$postLink` - Called after this controller's element and its children been linked. Similar to the post-link
   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
   they are waiting for their template to load asynchronously and their own compilation and linking has been
   suspended until that occurs.

Closes #14127
Closes #14030
Closes #14020
Closes #13991
Closes #14302
@poshest
Copy link
Contributor

poshest commented Nov 9, 2016

Am I correct in saying that the this.$onDestroy only gets "converted" into a scope.$on('$destroy', ... at the time a component is linked? So if, in a component's code you did

$timeout(this.$onDestroy = function ...)

$onDestroy wouldn't actually fire upon component destruction, whereas this

$timeout($scope.$on('$destroy', function ...))

would get mean the $destroy function was called upon component destruction (assuming the destruction happened after the $timeout was processed).

@gkalpak
Copy link
Member

gkalpak commented Nov 9, 2016

@poshest that is correct (assuming you meant $timeout(function() { this.$onDestroy = ... })).
Basically, right after the controller is instantiated and the $onChanges()/$onInit()/$doCheck() hooks are triggered (if present), the controller instance is checked for $onDestroy() and sets up the scope.$on('$destroy', ...) listener if necessary.

@poshest
Copy link
Contributor

poshest commented Nov 10, 2016

Yes, that's what I meant! OK cool. Thanks again @gkalpak :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants