Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(uiView): do not leave initial view scope undestroyed (#3164)
Previously the contents of the initial view were linked and left
undestroyed when the view was replaced with a subview. Because the view
was not destroyed, directives like ngInclude assumed it was safe to
compile and link asynchronous content to it. This would cause a ctreq
error if the asynchronous content required another directive from the
DOM. Now the initial view is either not linked at all or its scope is
properly destroyed.

Closes #1896
  • Loading branch information
jpekkala authored and christopherthielen committed Nov 29, 2016
1 parent 9795c8f commit 37d6f9a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 3 deletions.
7 changes: 6 additions & 1 deletion src/ng1/directives/viewDirective.ts
Expand Up @@ -326,10 +326,15 @@ function $ViewDirectiveFill ($compile: ICompileService, $controller: IController
priority: -400,
compile: function (tElement: JQuery) {
let initial = tElement.html();
tElement.empty();

return function (scope: IScope, $element: JQuery) {
let data: UIViewData = $element.data('$uiView');
if (!data) return;
if (!data) {
$element.html(initial);
$compile($element.contents())(scope);
return;
}

let cfg: Ng1ViewConfig = data.$cfg || <any> { viewDecl: {} };
$element.html(cfg.template || initial);
Expand Down
52 changes: 50 additions & 2 deletions test/viewDirectiveSpec.js
Expand Up @@ -88,7 +88,7 @@ describe('uiView', function () {
controller: function() {
this.someProperty = "value"
},
template: "hi",
template: "{{vm.someProperty}}",
controllerAs: "vm"
},
lState = {
Expand Down Expand Up @@ -324,7 +324,7 @@ describe('uiView', function () {
});

it('should instantiate a controller with controllerAs', inject(function($state, $q) {
elem.append($compile('<div><ui-view>{{vm.someProperty}}</ui-view></div>')(scope));
elem.append($compile('<div><ui-view></ui-view></div>')(scope));
$state.transitionTo(kState);
$q.flush();

Expand Down Expand Up @@ -726,6 +726,54 @@ describe("UiView", function() {
}));
});

describe('uiView transclusion', function() {
var scope, $compile, elem;

beforeEach(function() {
app = angular.module('foo', []);

app.directive('scopeObserver', function() {
return {
restrict: 'E',
link: function(scope) {
scope.$emit('directiveCreated');
scope.$on('$destroy', function() {
scope.$emit('directiveDestroyed');
});
}
};
});
});

beforeEach(module('ui.router', 'foo'));

beforeEach(module(function($stateProvider) {
$stateProvider
.state('a', { template: '<ui-view><scope-observer></scope-observer></ui-view>' })
.state('a.b', { template: 'anything' });
}));

beforeEach(inject(function ($rootScope, _$compile_) {
scope = $rootScope.$new();
$compile = _$compile_;
elem = angular.element('<div>');
}));

it('should not link the initial view and leave its scope undestroyed when a subview is activated', inject(function($state, $q) {
var aliveCount = 0;
scope.$on('directiveCreated', function() {
aliveCount++;
});
scope.$on('directiveDestroyed', function() {
aliveCount--;
});
elem.append($compile('<div><ui-view></ui-view></div>')(scope));
$state.transitionTo('a.b');
$q.flush();
expect(aliveCount).toBe(0);
}));
});

describe('uiView controllers or onEnter handlers', function() {
var el, template, scope, document, count;

Expand Down

0 comments on commit 37d6f9a

Please sign in to comment.