Skip to content
This repository has been archived by the owner on Aug 29, 2023. It is now read-only.

Commit

Permalink
fix(compiler): $onDestroy hook not called
Browse files Browse the repository at this point in the history
Even though the $onInit lifecycle hook is fully supported, the
$onDestroy hook isn't. This is unexpected for developers.

This change introduces a listener for the $destroy event on the linked
scope. See https://docs.angularjs.org/api/ng/type/$rootScope.Scope#event-$destroy

This implementation closely resembles the AngularJS internal
implementation of the lifecycle hook invokation behavior:
https://github.com/angular/angular.js/blob/2b28c540ad7ebf4a9c3a6f108a9cb5b673d3712d/src/ng/compile.js#L3298-L3302

Fixes #11847
  • Loading branch information
oliversalzburg authored and Splaktar committed Apr 30, 2020
1 parent a3c533f commit 8bb1d98
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 1 deletion.
9 changes: 9 additions & 0 deletions src/core/services/compiler/compiler.js
Expand Up @@ -436,6 +436,15 @@ function MdCompilerProvider($compileProvider) {
// Create the specified controller instance.
var ctrl = self._createController(options, injectLocals, locals);

// Registering extra $destroy listeners should be avoided.
// Only register the listener if the controller implements a $onDestroy hook.
if (angular.isFunction(ctrl.$onDestroy)) {
scope.$on('$destroy', function() {
// Call the $onDestroy hook if it's present on the controller.
angular.isFunction(ctrl.$onDestroy) && ctrl.$onDestroy();
});
}

// Unique identifier for AngularJS Route ngView controllers.
element.data('$ngControllerController', ctrl);
element.children().data('$ngControllerController', ctrl);
Expand Down
59 changes: 58 additions & 1 deletion src/core/services/compiler/compiler.spec.js
Expand Up @@ -195,7 +195,7 @@ describe('$mdCompiler service', function() {
}
});
});

function compileAndLink(options) {
var compileData;

Expand Down Expand Up @@ -482,4 +482,61 @@ describe('$mdCompiler service', function() {
});
});

describe('AngularJS 1.6+ lifecycle hooks', function() {
var $mdCompiler, pageScope, $rootScope;

beforeEach(module('material.core'));

beforeEach(inject(function($injector) {
$mdCompiler = $injector.get('$mdCompiler');
$rootScope = $injector.get('$rootScope');
pageScope = $rootScope.$new(false);
}));

it('calls $onInit on initialization', function(done) {
var passed = false;

class TestController {
$onInit() { passed = true; }
}

var compileResult = $mdCompiler.compile({
template: '<span></span>',
controller: TestController,
controllerAs: 'vm',
bindToController: true
});

compileResult.then(function(compileOutput) {
compileOutput.link(pageScope).scope();
expect(passed).toBe(true);
done();
});

$rootScope.$apply();
});

it('calls $onDestroy on destruction', function(done) {
var passed = false;

class TestController {
$onDestroy() { passed = true; }
}

var compileResult = $mdCompiler.compile({
template: '<span></span>',
controller: TestController,
controllerAs: 'vm',
bindToController: true
});

compileResult.then(function(compileOutput) {
compileOutput.link(pageScope).scope().$destroy();
expect(passed).toBe(true);
done();
});

$rootScope.$apply();
});
});
});

0 comments on commit 8bb1d98

Please sign in to comment.