Skip to content

Commit

Permalink
Merge pull request #11329 from emberjs/teardown-component
Browse files Browse the repository at this point in the history
Failing test for {{component}} keyword teardown.
  • Loading branch information
rwjblue committed Jun 12, 2015
2 parents e83dbfc + ac846c3 commit eb68b3e
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/ember-htmlbars/lib/keywords/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ export default {
},

render(morph, ...rest) {
if (morph.state.manager) {
morph.state.manager.destroy();
}

// Force the component hook to treat this as a first-time render,
// because normal components (`<foo-bar>`) cannot change at runtime,
// but the `{{component}}` helper can.
Expand Down
5 changes: 5 additions & 0 deletions packages/ember-htmlbars/lib/keywords/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ export default {
options.createOptions._targetObject = node.state.targetObject;
}

if (state.manager) {
state.manager.destroy();
state.manager = null;
}

var nodeManager = ViewNodeManager.create(node, env, hash, options, parentView, null, scope, template);
state.manager = nodeManager;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,15 @@ ComponentNodeManager.prototype.rerender = function(_env, attrs, visitor) {
}, this);
};

ComponentNodeManager.prototype.destroy = function() {
let component = this.component;

// Clear component's render node. Normally this gets cleared
// during view destruction, but in this case we're re-assigning the
// node to a different view and it will get cleaned up automatically.
component._renderNode = null;
component.destroy();
};

export function createComponent(_component, isAngleBracket, _props, renderNode, env, attrs = {}) {
let props = assign({}, _props);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ ViewNodeManager.prototype.rerender = function(env, attrs, visitor) {
}, this);
};

ViewNodeManager.prototype.destroy = function() {
this.component.destroy();
};

function getTemplate(componentOrView) {
return componentOrView.isComponent ? get(componentOrView, '_template') : get(componentOrView, 'template');
}
Expand Down Expand Up @@ -191,6 +195,7 @@ export function createOrUpdateComponent(component, options, createOptions, rende
}

component._renderNode = renderNode;

renderNode.emberView = component;
return component;
}
Expand Down
48 changes: 48 additions & 0 deletions packages/ember-htmlbars/tests/helpers/component_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,54 @@ if (isEnabled('ember-htmlbars-component-helper')) {
equal(view.$().text(), 'yummy Loisaida arepas!', 'component was updated and re-rendered');
});

QUnit.test("component helper destroys underlying component when it is swapped out", function() {
var currentComponent;
var destroyCalls = 0;
registry.register('component:foo-bar', Component.extend({
init() {
this._super(...arguments);
currentComponent = 'foo-bar';
},
willDestroy() {
destroyCalls++;
}
}));
registry.register('component:baz-qux', Component.extend({
init() {
this._super(...arguments);
currentComponent = 'baz-qux';
},
willDestroy() {
destroyCalls++;
}
}));

view = EmberView.create({
container: container,
dynamicComponent: 'foo-bar',
template: compile('{{component view.dynamicComponent}}')
});

runAppend(view);

equal(currentComponent, 'foo-bar', 'precond - instantiates the proper component');
equal(destroyCalls, 0, 'precond - nothing destroyed yet');

Ember.run(function() {
set(view, "dynamicComponent", 'baz-qux');
});

equal(currentComponent, 'baz-qux', 'changing bound value instantiates the proper component');
equal(destroyCalls, 1, 'prior component should be destroyed');

Ember.run(function() {
set(view, "dynamicComponent", 'foo-bar');
});

equal(currentComponent, 'foo-bar', 'changing bound value instantiates the proper component');
equal(destroyCalls, 2, 'prior components destroyed');
});

QUnit.test("component helper with actions", function() {
registry.register('template:components/foo-bar', compile('yippie! {{yield}}'));
registry.register('component:foo-bar', Ember.Component.extend({
Expand Down

0 comments on commit eb68b3e

Please sign in to comment.