Как я могу сделать визуализацию с соевыми шаблонами?

У меня есть этот шаблон сои

{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 ответ

Решение

Почему это не удается

Правильно, документация renderAsFragment немного сбивает с толку; это читает:

Визуализирует шаблон сои в один узел или фрагмент документа. Если представленная 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>?

Это потому, что внутри safeHtmlToNode мест safeHtml во временном div, прежде чем решить, если он должен вернуть div wrappper (общий случай) или единственный дочерний элемент (если отображаемый 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 это из большего шаблона.

Другие вопросы по тегам