1

我有这个大豆模板

{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>

最好的方法是什么?

4

1 回答 1

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>

这是因为,在内部,在决定它是否应该返回包装器(一般情况)或唯一的孩子(如果呈现的 HTML 仅代表一个节点)之前,safeHtmlToNode放置safeHtml在一个临时的。再次简化,代码为:divdivsafeHtmlToNode

  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其保留在较大的模板中。

于 2017-02-11T18:29:33.457 回答