如何使用大豆模板渲染tr?

时间:2017-02-01 23:39:02

标签: html google-closure-templates 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>

最好的方法是什么?

1 个答案:

答案 0 :(得分:4)

为什么失败

是的,renderAsFragment的文档有点令人困惑;它写着:

  

将Soy模板呈现为单个节点或文档片段。如果呈现的HTML字符串表示单个节点,则返回该节点

但是,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中,然后才决定是否应该返回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,但只有在您的表有一行时才会有效,因为它会替换内容,并且不会附加子节点。

推荐方法

通常,我们在模板中执行for循环:

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

当然,我们可以保留一行中的简单模板,并从较大的模板中保留call