fix(render): don’t store a document fragment as bound element

When a template contains bound text nodes as root nodes,
we used to store the document fragment that we got from
cloning `template.content`. However, this fragment will be
empty as soon as the view gets attached. Now we store
`null` instead of the document fragment in this case.

Also groups the 3 cases in `_createView` so they are easier to
understand.
This commit is contained in:
Tobias Bosch 2015-05-28 15:02:05 -07:00
parent 2351896cc0
commit 24bc4b66d0

View File

@ -209,34 +209,35 @@ export class DomRenderer extends Renderer {
}
_createView(protoView: DomProtoView, inplaceElement): DomView {
var rootElementClone =
isPresent(inplaceElement) ? inplaceElement : DOM.importIntoDoc(protoView.element);
var rootElementClone;
var elementsWithBindingsDynamic;
if (protoView.isTemplateElement) {
elementsWithBindingsDynamic =
DOM.querySelectorAll(DOM.content(rootElementClone), NG_BINDING_CLASS_SELECTOR);
} else {
elementsWithBindingsDynamic = DOM.getElementsByClassName(rootElementClone, NG_BINDING_CLASS);
}
var elementsWithBindings = ListWrapper.createFixedSize(elementsWithBindingsDynamic.length);
for (var binderIdx = 0; binderIdx < elementsWithBindingsDynamic.length; ++binderIdx) {
elementsWithBindings[binderIdx] = elementsWithBindingsDynamic[binderIdx];
}
var viewRootNodes;
if (protoView.isTemplateElement) {
var childNode = DOM.firstChild(DOM.content(rootElementClone));
viewRootNodes =
[]; // TODO(perf): Should be fixed size, since we could pre-compute in in DomProtoView
if (isPresent(inplaceElement)) {
rootElementClone = inplaceElement;
elementsWithBindingsDynamic = [];
viewRootNodes = [inplaceElement];
} else if (protoView.isTemplateElement) {
rootElementClone = DOM.importIntoDoc(DOM.content(protoView.element));
elementsWithBindingsDynamic =
DOM.querySelectorAll(rootElementClone, NG_BINDING_CLASS_SELECTOR);
var childNode = DOM.firstChild(rootElementClone);
// TODO(perf): Should be fixed size, since we could pre-compute in in DomProtoView
viewRootNodes = [];
// Note: An explicit loop is the fastest way to convert a DOM array into a JS array!
while (childNode != null) {
ListWrapper.push(viewRootNodes, childNode);
childNode = DOM.nextSibling(childNode);
}
} else {
rootElementClone = DOM.importIntoDoc(protoView.element);
elementsWithBindingsDynamic = DOM.getElementsByClassName(rootElementClone, NG_BINDING_CLASS);
viewRootNodes = [rootElementClone];
}
var elementsWithBindings = ListWrapper.createFixedSize(elementsWithBindingsDynamic.length);
for (var binderIdx = 0; binderIdx < elementsWithBindingsDynamic.length; ++binderIdx) {
elementsWithBindings[binderIdx] = elementsWithBindingsDynamic[binderIdx];
}
var binders = protoView.elementBinders;
var boundTextNodes = [];
var boundElements = ListWrapper.createFixedSize(binders.length);
@ -245,15 +246,21 @@ export class DomRenderer extends Renderer {
for (var binderIdx = 0; binderIdx < binders.length; binderIdx++) {
var binder = binders[binderIdx];
var element;
var childNodes;
if (binderIdx === 0 && protoView.rootBindingOffset === 1) {
element = rootElementClone;
// Note: if the root element was a template,
// the rootElementClone is a document fragment,
// which will be empty as soon as the view gets appended
// to a parent. So we store null in the boundElements array.
element = protoView.isTemplateElement ? null : rootElementClone;
childNodes = DOM.childNodes(rootElementClone);
} else {
element = elementsWithBindings[binderIdx - protoView.rootBindingOffset];
childNodes = DOM.childNodes(element);
}
boundElements[binderIdx] = element;
// boundTextNodes
var childNodes = DOM.childNodes(DOM.templateAwareRoot(element));
var textNodeIndices = binder.textNodeIndices;
for (var i = 0; i < textNodeIndices.length; i++) {
ListWrapper.push(boundTextNodes, childNodes[textNodeIndices[i]]);