I've got this soy template
{template .myRowTemplate}
<tr><td>Hello</td></tr>
{/template}
and I want to do something like
var myTable = goog.dom.createElement("table");
goog.dom.appendChild(myTable, goog.soy.renderAsFragment(mytemplates.myRowTemplate));
goog.dom.appendChild(myTable, goog.soy.renderAsFragment(mytemplates.myRowTemplate));
But that causes
Uncaught goog.asserts.AssertionError
Assertion failed: This template starts with a <tr>,
which cannot be a child of a <div>, as required by soy internals.
Consider using goog.soy.renderElement instead.
Template output: <tr><td>Hello</td></tr>
What's the best way to do this?
Why it fails
Right, the documentation of
renderAsFragment
is a bit confusing; it reads:However, the (simplified) implementation of
renderAsFragment
is:So why do the closure author assert that the first tag is not
<tr>
?That's because, internally,
safeHtmlToNode
placessafeHtml
in a temporarydiv
, before deciding if it should return thediv
wrappper (general case) or the only child (if the rendered HTML represents only one Node). Once again simplified, the code ofsafeHtmlToNode
is:renderAsElement won't work either
And I'm unsure what you are asking for fragments, but unfortunately
goog.soy.renderAsElement()
will behave the same because it also uses a temporarydiv
to render the DOM.renderElement cannot loop
The error message suggests
goog.soy.renderElement
, but that will only work if your table has one row, since it replaces content, and doesn't append children nodes.Recommended approach
So usually, we do the for loop in the template:
Of course, we can keep the simple template you have for one row and
call
it from the larger template.