Handlebars.js: Guiador não funciona em tabelas

Criado em 15 ago. 2013  ·  37Comentários  ·  Fonte: handlebars-lang/handlebars.js

http://jsfiddle.net/cwYhN/3/

Observe que o mesmo guiador #each funciona fora das mesas. Meu jsfiddle inclui duas saídas com bordas que demonstram isso.

Comentários muito úteis

Sei que esse problema é bastante antigo, mas me deparei com isso recentemente porque o editor de modelos de e-mail do Sendgrid não segue essas práticas recomendadas. Se alguém mais descobrir esse problema do Google por esse motivo, uma solução alternativa é colocar o código do guiador em um comentário HTML.

<table >
  <tbody>
    <!-- {{#each items}} -->
    <tr>
      <td>{{this.key}}</td>
      <td>{{this.value}}</td>
    </tr>
    <!-- {{/each}} -->
  </tbody>
</table>

que produz a seguinte saída

<table>
  <tbody>
    <!--  -->
    <tr>
      <td>my key</td>
      <td>my value</td>
    </tr>
    <!--  -->
    <!--  -->
    <tr>
      <td>my key 2</td>
      <td>my value 2</td>
    </tr>
    <!--  -->
  </tbody>
<table>

(OBSERVAÇÃO: não verifiquei isso diretamente com o Handlebars, apenas no editor de modelos do Sendgrid)

Todos 37 comentários

Pelo que vale a pena, se as tags {{each}} são colocadas fora da tabela, as outras tags funcionam. É claro que isso tem o efeito indesejável se duplicar a tabela repetidamente, mas talvez ajude a diminuir o problema:

http://jsfiddle.net/cwYhN/6/

Parece que pode ser um problema com jQuery ou outra coisa ... quando você faz console.log(frag); você vê que o auxiliar {{#each}} é empurrado para fora da mesa antes mesmo de tentar compilá-lo com o guidão ...

Eu atualizei o jsfiddle para colocar o modelo dentro de uma tag <script type="text/x-handlebars-template"></script> e parece estar funcionando bem ...

http://jsfiddle.net/doowb/6GdPy/1/

Sim, acabei de descobrir que:
http://jsfiddle.net/cwYhN/10/

Pelo que vale a pena, acho que é o navegador jogando fora o que considera um html inválido, em vez de uma falha do jquery.

Sim, eu não tinha certeza se seria uma coisa do jQuery ou a função nativa do navegador que o jQuery chama. De qualquer forma, ele não gosta do {{ }} entre tbody e tr .

Seria bom se o guidão fosse construído de alguma forma para operar dentro dessa restrição. Por exemplo, ser capaz de colocar "each" dentro de uma tag, tendo o entendimento implícito de que ele itera sobre o conteúdo da tag. Posso imaginar que se pareça com:

<table>
  <tbody handlebars="{{each}}">
    ... these get iterated ...
  </tbody>
</table>

Permitir algo como isso evitaria que o navegador retirasse as instruções importantes de cada e poderia pegar carona na tag de fechamento a que pertence (/ tbody)

Como vocês já mencionaram, o analisador HTML é confundido pela marcação do guiador e surge com isso como a estrutura DOM que você tenta converter em um modelo de guiador:

            {{#each activity}}

            {{/each}}
        <table style="border:1px solid #ccc;">
        <thead>
            <tr><th>Month</th>
            <th>Imps</th>
            <th>Clicks</th>
            <th>Spend</th>
        </tr></thead>
        <tbody><tr>
                <th>{{month}}</th>
                <td>{{impressions}}</td><td>{{clicks}}</td><td>{{spend}}</td>
            </tr></tbody>
    </table>

Deve usar algo como o comportamento do script acima, strings de javascript ou pré-compilação para contornar isso.

Fechando isso, pois esse problema é mais um detalhe de implementação do navegador do que um bug no próprio guidão.

Perdi meio dia antes de descobrir que {{#each}} não funciona em tabelas. Seria muito útil se isso tivesse sido simplesmente declarado na documentação.

Cada um funciona perfeitamente bem em tabelas, se carregado corretamente. Como você está carregando seus modelos?

Esse bug desperdiçou duas horas da minha vida e agora são 22h30 de sábado, estou trabalhando no meu escritório apenas para resolver esse bug até que encontrei este problema e [Documento oficial do bloco]
(http://handlebarsjs.com/builtin_helpers.html) não diz nada sobre isso.

Caso não tenha ficado claro, isso não é culpa do guidão, mas sua por não saber como o HTML funciona: https://html.spec.whatwg.org/multipage/syntax.html#an -introduction-to-error -tratando-e-casos-estranhos-no-analisador

Então, você assume que todos que tentam usar o Handlebarsjs devem ter um bom entendimento de como o analisador HTML funciona? E se não, então é _a culpa do usuário_, não é culpa da clareza da documentação? Essa suposição não faz sentido. Outro mecanismo de template pesado e complexo, Angularjs, usa sintaxe compatível com Html como sua sintaxe de template, por exemplo, se eu precisar de uma tabela de loop, posso usar

<tr ng-repeat="dto in tableData">

E o Angularjs mantém o status interno do loop usando comentários Html:

<!-- ngRepeat: column in row -->
<tr ng-repeat="dto in tableData">

Angualrjs tenta respeitar e seguir a sintaxe do Html tanto quanto possível e evitar a suposição com sucesso. Mas a sintaxe do template de Handlebarsjs não o faz, então ela expõe o problema do analisador Html aos usuários.
Se o seu desenvolvedor não puder resolver o problema do seu lado e você tiver o _ dever_ de dizer aos seus usuários para estarem cientes do problema, se você realmente se preocupa com o seu projeto e com os usuários de todo o mundo.
De qualquer forma, vou abrir um exemplar de documento porque _ creio que não sou o primeiro que me deparou com esse problema de dor de cabeça e não serei o último. _

O Angular é executado no DOM, portanto, é compatível com o DOM. O guiador funciona apenas com strings e não tem o conceito de DOM.

@profullstack : Como @stevenvachon disse, o Handlebars não funciona com HTML, mas apenas com texto. Mas isso pode não ser óbvio nos documentos, já que todos os exemplos são HTML. Use-o pessoalmente também para gerar markdown ...

Se você pudesse me dizer que tipo de texto você precisaria nos documentos, eu ficaria feliz em adicioná-lo. No entanto, as instruções gerais de uso (incluindo a parte com a <script> -tag já estão lá na página principal de http://handlebarsjs.com/. É por isso que não tenho certeza de qual é a sua necessidade aqui.

@profullstack Eu entendo que você está frustrado por ter "perdido tempo", mas na minha opinião, você entendeu tudo ao contrário.

Nenhum projeto de código aberto ou contribuidor tem qualquer obrigação para com você. Ferramentas como guidão são criadas e mantidas gratuitamente e quase sem agradecimento, para tentar tornar a vida de outros desenvolvedores mais fácil. Se você não pudesse usar nenhum projeto de código aberto, quanto tempo seu trabalho demoraria?

Posso dizer, em primeira mão, que vir e escrever comentários com um tom como este terá o efeito oposto ao desejado . Simples cenoura vs bastão, se você quer que alguém faça algo por você, peça gentilmente ou, melhor ainda, crie um PR e faça você mesmo.

@ErisDS Obrigado por seu conselho. Talvez meu primeiro comentário tenha sido muito forte, mas concordo totalmente com sua opinião sobre:

to try to making other developers lives easier

E por que larguei o Angularjs para usar o Handlebarsjs? _Porque acredito que Handlebarsjs vai tornar minha vida mais fácil do que Angularjs._
Portanto, apenas adicione algumas palavras de aviso na documentação para ajudar seus milhares de usuários de código aberto a evitar o problema em potencial contra a sua vontade de "tornar a vida de outros desenvolvedores mais fácil"? Eu acho que não.
Para:

No open source project nor contributor has any duty to you.

Sim, é verdade. Você pode iniciar um projeto de código aberto e, em seguida, abandoná-lo, está totalmente OK. Mas quando seu projeto cresce, você gasta mais tempo e dedicação a ele, está amando mais seu projeto e também deseja compartilhá-lo com o mundo. Neste momento, você começará a _procurar os seus usuários_ e a _cuidar da sua documentação_. Handlebarsjs está neste estágio, este não é um projeto pequeno, é um projeto popular e usado por programadores em todo o mundo, até mesmo na Coréia do Sul, na China e assim por diante.
Pelo que eu sei, a maioria dos programadores de código aberto no Github tem orgulho de seu projeto e de seu arquivo README.md, e deseja que mais e mais pessoas usem suas ferramentas e códigos.
Então se:

  • Você não quer se preocupar com seus usuários de código aberto
  • Eu sou o último que vai encontrar esse problema
    Você pode ignorar totalmente minha análise técnica no primeiro comentário e a discussão gentil com o usuário neste comentário.
    Além disso, o projeto de código aberto não é algo como _caridade_ que você dá ao mundo, é a _ ponte de comunicação_ entre você e outros programadores.

@nknapp Obrigado pela sua resposta.
Talvez meu primeiro comentário seja muito forte e peço desculpas por isso e às pessoas que leram meu comentário.
À primeira vista, o Handlebars funciona simplesmente como _uma ferramenta de substituição de texto_ e é realmente fácil de entender. Então, quando escrevo algo assim:

{{#each myListData}}
                        <tr>{{name}}</tr>
{{/each}}

Se for apenas uma substituição, eu esperaria algo assim:

<tr>nameA</tr>
<tr>nameB</tr>

Mas quando se deparou com o HTML, ele se comportou de forma diferente, e é por causa da natureza do analisador HTML, como @stevenvachon gentilmente observou.
Portanto, acho que apenas uma frase será suficiente abaixo da seção "O auxiliar de cada bloco":

WARNING: please use script block when you try to use #each block inside table, due to the know issue of [How HTML parse works(thanks for <strong i="18">@stevenvachon</strong>'s reference](https://html.spec.whatwg.org/multipage/syntax.html#an-introduction-to-error-handling-and-strange-cases-in-the-parser)

Eu realmente aprecio se você compartilhar sua opinião. Obrigado.

A questão é que isso não tem nada a ver com o #each -helper. Você simplesmente nunca deve escrever um modelo diretamente em HTML. Uma declaração como essa deveria estar na página principal, mas a pergunta é: Você a teria lido lá?

Talvez pudéssemos um aviso como o seu abaixo do exemplo na página de destino ...

Apenas outra nota:

Eu não usaria o método de blocos de script na produção. Em vez disso, usaria o Webpack ou outra ferramenta para pré-compilar os modelos.

@nknapp Sim, acho que sua opinião está certa: nunca devemos escrever um modelo diretamente em HTML. Então eu acho que na página de destino, a primeira seção "Primeiros passos" deve usar o script como exemplo e no bloco cinza abaixo, podemos mudar

You **can** deliver a template to the browser by including it in a <script> tag.

para

You **should always** deliver a template to the browser by including it in a <script> tag.

Acho que sua sugestão:

**never** write a template directly into HTML

está totalmente certo, e deve ser colocado na landing page para que todos possam acompanhar e pode evitar muitos problemas. Acho que é uma boa ideia, você acha?

Essa explicação não funciona, porém, porque eles podem compreendê-la como:

<script type="text/x-handlebars">
  {{#each list as |item|}}
    <td>{{item}}</td>
  {{/each}}
</script>

@stevenvachon Sim, apenas colocar templates dentro do script não é suficiente em seu exemplo, talvez precisemos adicionar mais notas sobre a maneira correta de usar um template, gostaríamos de ouvir suas sugestões sobre isso.

Possivelmente:

Para a maioria dos aplicativos de produção, você não desejará usar os modelos de analisador e string. Verifique a pré-compilação.

@stevenvachon Obrigado por seus comentários e acho que será melhor se colocarmos o link do analisador de HTML junto com seus comentários:

Para a maioria dos aplicativos de produção, você não desejará usar os modelos de analisador e string. Verifique a pré-compilação. Existem alguns problemas conhecidos se você usar um modelo diretamente em HTML, por exemplo, o #each block helper não funcionará dentro de tabelas devido ao funcionamento do analisador HTML.

Provavelmente deve ser dividido em

  1. Diretamente abaixo do exemplo de tag <script> -tag

É importante que você coloque o modelo dentro de uma <script> -tag. Não coloque-o no HTML diretamente ou o analisador de HTML pode modificá-lo (por exemplo, se ele contiver uma tabela )

  1. Altere o marcador sobre pré-compilação para.

Observe que essa abordagem não é recomendada para aplicativos de produção. Também é possível pré-compilar seus modelos. [...]

Na verdade, eu pessoalmente não usaria mais o Handlebars no navegador: Existem muitos outros frameworks por aí (não apenas Angular e React, mas também Vue e Ractive). Esse vídeo é bem legal e mostra o problema ...

Eu uso o Handlebars no servidor e como gerador de página estática, mas para a renderização do navegador, acho que existem maneiras melhores.

@nknapp Comecei a escrever handlebars-html-parser para usá-lo ao trazê-lo para o navegador por meio de VDOMs, mas encontrei resistência .

@nknapp Obrigado pela sua resposta. Seus comentários incluem:

  1. A importância de colocar o modelo dentro de um

@profullstack Eu não sou um mantenedor deste projeto.

Eu fiz as mudanças.

@nknapp Obrigado, acredito que muitas pessoas se beneficiarão com suas mudanças.

Sei que esse problema é bastante antigo, mas me deparei com isso recentemente porque o editor de modelos de e-mail do Sendgrid não segue essas práticas recomendadas. Se alguém mais descobrir esse problema do Google por esse motivo, uma solução alternativa é colocar o código do guiador em um comentário HTML.

<table >
  <tbody>
    <!-- {{#each items}} -->
    <tr>
      <td>{{this.key}}</td>
      <td>{{this.value}}</td>
    </tr>
    <!-- {{/each}} -->
  </tbody>
</table>

que produz a seguinte saída

<table>
  <tbody>
    <!--  -->
    <tr>
      <td>my key</td>
      <td>my value</td>
    </tr>
    <!--  -->
    <!--  -->
    <tr>
      <td>my key 2</td>
      <td>my value 2</td>
    </tr>
    <!--  -->
  </tbody>
<table>

(OBSERVAÇÃO: não verifiquei isso diretamente com o Handlebars, apenas no editor de modelos do Sendgrid)

Obrigado por essa dica @gurpreetatwal . Você me poupou horas de depuração esta noite com aquele boato para SendGrid!

@gurpreetatwal mas por quê?

@Lazarencjusz, por que motivo a correção funciona ou por que o editor de modelo de e-mail do SendGrid não funciona corretamente?

Oi! Quando você usa elementos div em vez de uma tabela, funcionará.
Além disso, reescreva todos os elementos da tabela em div.

A solução de @gurpreetatwal funciona para mim no modelo Mailchimp / Mandrills para guidão. Obrigado por me poupar uma tonelada de problemas!

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

nknapp picture nknapp  ·  3Comentários

DylanPiercey picture DylanPiercey  ·  7Comentários

sontek picture sontek  ·  3Comentários

mattkime picture mattkime  ·  4Comentários

morgondag picture morgondag  ·  5Comentários