如何使用 soy 模板渲染 tr?

How can I render a tr with soy templates?

我有这个大豆模板

{template .myRowTemplate}
  <tr><td>Hello</td></tr>
{/template}

我想做类似

的事情
var myTable = goog.dom.createElement("table");
goog.dom.appendChild(myTable, goog.soy.renderAsFragment(mytemplates.myRowTemplate));
goog.dom.appendChild(myTable, goog.soy.renderAsFragment(mytemplates.myRowTemplate));

但这会导致

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>

最好的方法是什么?

为什么会失败

对了,renderAsFragment的文档有点乱;上面写着:

Renders a Soy template into a single node or a document fragment. If the rendered HTML string represents a single node, then that node is returned

但是,renderAsFragment 的(简化)实现是:

  var output = template(opt_templateData);
  var html = goog.soy.ensureTemplateOutputHtml_(output);
  goog.soy.assertFirstTagValid_(html); // This is your failure
  var safeHtml = output.toSafeHtml();
  return dom.safeHtmlToNode(safeHtml);

那么为什么闭包作者断言第一个标签不是<tr>

这是因为,在内部,safeHtmlToNodesafeHtml 放置在临时 div 中,然后再决定是否应该 return div 包装器(一般情况) 或独生子(如果呈现的 HTML 仅代表一个节点)。再次简化,safeHtmlToNode的代码为:

  var tempDiv = goog.dom.createElement_(doc, goog.dom.TagName.DIV);
  goog.dom.safe.setInnerHtml(tempDiv, html);
  if (tempDiv.childNodes.length == 1) {
    return tempDiv.removeChild(tempDiv.firstChild);
  } else {
    var fragment = doc.createDocumentFragment();
    while (tempDiv.firstChild) {
      fragment.appendChild(tempDiv.firstChild);
    }
    return fragment;
  }

renderAsElement 也不起作用

我不确定你要的片段是什么,但不幸的是 goog.soy.renderAsElement() 的行为是一样的,因为它也使用临时 div 来呈现 DOM。

renderElement 不能循环

错误消息提示 goog.soy.renderElement,但只有当您的 table 有一行时才有效,因为它会替换内容,并且不会附加子节点。

推荐方法

所以通常,我们在模板中做 for 循环:

  {template .myTable}
    <table>
    {foreach $person in $data.persons}
      <tr><td>Hello {$person.name}</td></tr>
    {/foreach}
    </table>
  {/template}

当然,我们可以将您的简单模板保留一行,call 它来自较大的模板。