Skip to content

Commit 878a254

Browse files
authored
fix: re-create template instance after detaching instance's root (#2083)
1 parent 422bc4e commit 878a254

File tree

2 files changed

+55
-10
lines changed

2 files changed

+55
-10
lines changed

packages/vaadin-template-renderer/src/vaadin-template-renderer-templatizer.js

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,28 @@ export class Templatizer extends PolymerElement {
2020
this.__templateInstances = new Set();
2121
}
2222

23+
/**
24+
* If the template instance was created by this templatizer's instance and is still attached to DOM,
25+
* it only re-renders the instance with the new properties.
26+
* Otherwise, it disposes of the old template instance (if it exists),
27+
* creates a new template instance with the given properties and renders the instance's root to the element.
28+
*/
2329
render(element, properties = {}) {
24-
// If the template instance exists and has been instantiated by this templatizer,
25-
// it only re-renders the instance with the new properties.
26-
if (this.__templateInstances.has(element.__templateInstance)) {
27-
this.__updateProperties(element.__templateInstance, properties);
30+
let instance = element.__templateInstance;
31+
32+
if (this.__hasTemplateInstance(instance) && this.__isTemplateInstanceAttachedToDOM(instance)) {
33+
this.__updateProperties(instance, properties);
2834
return;
2935
}
3036

31-
// Otherwise, it instantiates a new template instance
32-
// with the given properties and then renders the result to the element
33-
const templateInstance = this.__createTemplateInstance(properties);
37+
if (this.__hasTemplateInstance(instance)) {
38+
this.__disposeOfTemplateInstance(instance);
39+
}
40+
41+
instance = this.__createTemplateInstance(properties);
42+
element.__templateInstance = instance;
3443
element.innerHTML = '';
35-
element.__templateInstance = templateInstance;
36-
element.appendChild(templateInstance.root);
44+
element.appendChild(instance.root);
3745
}
3846

3947
__updateProperties(instance, properties) {
@@ -56,6 +64,23 @@ export class Templatizer extends PolymerElement {
5664
return instance;
5765
}
5866

67+
__disposeOfTemplateInstance(instance) {
68+
this.__templateInstances.delete(instance);
69+
}
70+
71+
__hasTemplateInstance(instance) {
72+
return this.__templateInstances.has(instance);
73+
}
74+
75+
__isTemplateInstanceAttachedToDOM(instance) {
76+
// A workaround for the edge-case case when the template is empty
77+
if (instance.children.length === 0) {
78+
return false;
79+
}
80+
81+
return !!instance.children[0].parentElement;
82+
}
83+
5984
__createTemplateClass(properties) {
6085
if (this.__TemplateClass) return;
6186

packages/vaadin-template-renderer/test/vaadin-template-renderer.test.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,28 @@ describe('vaadin-template-renderer', () => {
4646
const newTemplateInstance = component.$.content.__templateInstance;
4747

4848
expect(template.__templatizer.__templateInstances).to.have.lengthOf(1);
49-
expect(template.__templatizer.__templateInstances).to.include(newTemplateInstance);
5049
expect(template.__templatizer.__templateInstances).to.include(oldTemplateInstance);
50+
expect(template.__templatizer.__templateInstances).to.include(newTemplateInstance);
51+
});
52+
53+
it('should create a new template instance after clearing the content', () => {
54+
const oldTemplateInstance = component.$.content.__templateInstance;
55+
56+
component.$.content.innerHTML = '';
57+
component.render();
58+
59+
const newTemplateInstance = component.$.content.__templateInstance;
60+
61+
expect(template.__templatizer.__templateInstances).to.have.lengthOf(1);
62+
expect(template.__templatizer.__templateInstances).not.to.include(oldTemplateInstance);
63+
expect(template.__templatizer.__templateInstances).to.include(newTemplateInstance);
64+
});
65+
66+
it('should render the template after clearing the content', () => {
67+
component.$.content.innerHTML = '';
68+
component.render();
69+
70+
expect(component.$.content.textContent).to.equal('foo');
5171
});
5272
});
5373

0 commit comments

Comments
 (0)