Mustache.js: Acessando o escopo pai

Criado em 11 dez. 2014  ·  18Comentários  ·  Fonte: janl/mustache.js

Acessando o escopo pai

Considerando :

node = {
  id: 1,
  children : [
      { id : 2 },
      { id : 3 }
  ]
}

E o seguinte modelo:

{{ id }} {# will output node.id #}
{{#children}}
    {{children.id}}  {# will output node.children[i].id #}
    {{id}}  {# will also output node.children[i].id #}
{{/children}}

Como está, às vezes você precisa acessar a propriedade pai (em um modelo de nó aninhado, por exemplo).
Pode ser facilmente implementado como usar "../" para obter o escopo pai

Ex:

{{ id }} {# will output node.id #}
{{#children}}
    {{children.id}}  {# will output node.children[i].id #}
    {{id}}  {# will also output node.children[i].id #}
    {{ ../id }}  {# will output node.id #}
{{/children}}

Para conseguir isso:

  Context.prototype.lookup = function (name) {
    var cache = this.cache;

    var value;
    if (name in cache) {
      console.log(name + ' found');
      value = cache[name];
    } else {
      var context = this, names, index;

      while (context) {
        if (name.indexOf('.') > 0) {
          value = context.view;
          names = name.split('.');
          index = 0;

          while (value != null && index < names.length)
            value = value[names[index++]];
        } else if(name.match(/^\.\.\//)) {
          name = name.replace(/^\.\.\//, '');
        } else {
          value = context.view[name];
        }

        if (value != null)
          break;

        context = context.parent;
      }

      cache[name] = value;
    }

    if (isFunction(value))
      value = value.call(this.view);

    return value;
  };
Future Plugin

Comentários muito úteis

Direito. Esqueci completamente o guiador.

Permite perder usuários para o guidão.
Essa é uma decisão de design aceitável.

Todos 18 comentários

Isso não está nas especificações de mustache certo? Não há solução alternativa para isso? Estou surpreso que ninguém tenha encontrado essa limitação antes.

Concordo que muitas vezes é necessário acessar coisas no escopo pai. Minha abordagem pragmática sempre foi evitar nomes de propriedade ambíguos. Isso tem funcionado por muito tempo para mim, embora frequentemente resulte em objetos estranhos.

Por outro lado, falando em experiência com guidão; ter essa capacidade pode tentar as pessoas criando uma resolução maluca de escopo pai emaranhada: {{../../../id}} é muito mais difícil de entender do que {{movieId}} .

É verdade que usar "../" pode levar à ilegibilidade. Mas, por outro lado, usar caml para resolver o pai não pode ser alcançado, pois você pode ter caml no escopo local. Além do mais, definir uma palavra-chave para acessar o pai não respeitaria a filosofia do Mustache, eu acho.

falando francamente, eu não poderia ter uma ideia mais simples e melhor do que usar a representação de diretório.

Sim, evitar nomes de propriedade ambíguos também leva a modelos mais legíveis / detalhados. Mas eu entendo porque algumas pessoas gostariam desse recurso.

Que tal escrever um pacote separado que modifique o funcionamento interno de mustache.js para adicionar o recurso desejado? Mais ou menos como um plugin.

Para ser honesto, eu realmente não vejo isso acontecendo, a menos que seja por meio de um plug-in ou um pragma. E uma API de plugin não parece ser a prioridade agora.

Tenho pensado um pouco mais sobre isso ...

Eu acredito que a filosofia do Mustache não é passar os dados _ como estão_ para o renderizador, mas 'prepará-los' em uma visualização de antemão. Você teria então uma propriedade parentId em seus nós.

Também é mais fácil ler e manter modelos com variáveis ​​mais detalhadas:

{{ id }}
{{#children}}
    {{children.id}}
    {{id}}
{{/children}}

Antes vs depois

{{ nodeId }}
{{#children}}
    {{ nodeId }}
    {{ parentId }}
{{/children}}

Relevante: http://stackoverflow.com/questions/4067093/mustache-read-variables-from-parent-section-in-child-section

(desculpe chamá-lo @bobthecow , mas sempre aprecio sua sabedoria de bigode: sorria :)

você já pode subir, então tudo que precisa fazer para corrigir o problema mostrado com o primeiro modelo é envolver os dados com um objeto temporário {node: ... } , embrulhar o modelo com {{#node}}...{{/node}} e então {{node.id}} parte pode funcionar. você não precisa (e não vai) modificar os dados existentes dessa maneira, e você pode adicionar ambos os "JIT" enquanto to_html() o modelo ...

parece uma solução alternativa irregular. Ele também funciona apenas com o modelo simplista de 2 níveis, onde você pode resolver por um envoltório de envelope para a camada externa. Mas e se o modelo for mais profundo? isso parece malabarismo.

Freqüentemente, preciso vincular um modelo que obtenho de camadas de dados inferiores e meu trabalho é apresentá-lo - em qualquer forma que o obtive com o infra. A proposição aqui é que eu tenho que converter o modelo recursivamente profundamente para um estado apresentável - o que seria considerado aqui redable property names .
Isso não atende a realidade convenientemente ...
Sim, é verdade, ele acopla o modelo ao modelo. Mas você pode me mostrar um modelo que não esteja associado a regras de modelo concretas? Todos os modelos são, por definição, feitos para renderizar um modelo definido.
Outra camada move a camada de definição um passo para trás e requer uma camada de tradução - o que é árduo e nem sempre necessário

IMHO, acho que a ferramenta deve deixar a escolha para o usuário, em vez de impor regras opinativas

Para leitores, exemplo do que @rndme está sugerindo:

const Mustache = require('mustache')

var view = {
  node: {
    id: 5,
    children: [ { id: 6 }, { id: 7 } ]
  }
}

const template = `
{{#node}}
  children:
  {{#children}}

    id: {{ id }}
    parentId: {{ node.id }}
  {{/children}}
{{/node}}
`

const output = Mustache.render(template, view)
console.log(output)

  children:

    id: 6
    parentId: 5

    id: 7
    parentId: 5

Usar o modelo a seguir não funciona a partir de latest , mas _deve funcionar_, imo.

const template = `
  children:
  {{#node.children}}

    id: {{ id }}
    parentId: {{ node.id }}
  {{/node.children}}
`

Sim, é verdade, ele acopla o modelo ao modelo. Mas você pode me mostrar um modelo que não esteja associado a regras de modelo concretas? Todos os modelos são, por definição, feitos para renderizar um modelo definido.
Outra camada move a camada de definição um passo para trás e requer uma camada de tradução - o que é tedioso e nem sempre necessário

Afaik, a filosofia do Mustache sempre foi que você gere uma visualização que é passada para o modelo - você não passa o modelo diretamente.

@osher Você pode nos mostrar um exemplo que você não consegue resolver facilmente com a dica / truque mencionado acima?

Tentarei fornecer trechos mais tarde, mas basicamente - com aninhamento de 3 níveis não funcionará porque você não pode encapsular o nível médio - você tem que transmutar a fonte para uma visualização processada.
Você poderá acessar o nível superior empacotado, mas não tem solução para o nível médio.

Tome por exemplo um documento swagger, onde você tem nível de raiz, nível de caminho, nível de verbo (e há mais, mas vamos parar por aqui). Cada nível pode especificar uma diretiva personalizada - x-uses , que é uma diretiva DI para a camada de implementação.

Suponha que você deseja gerar documentos HTML a partir deste documento swagger.
Você precisa de uma tabela plana especificando para cada manipulador de operação (o nível do verbo) o DI que ele aceita e de qual camada ele herda.
Embora todas as informações sejam inerentes ao documento swagger, agora você tem um problema.

Próximo.
Tente usar o bigode para gerar o código que implementa a API descrita no documento que retorna respostas simuladas com base na resposta padrão da operação.
Tente gerar doclets que descrevam o que o desenvolvedor de implementação que vem para substituir a resposta simulada por lógica real deve esperar em seu contexto de DI e ser específico sobre o nível que eles obtêm.
Mesmo...

Geração de HTML não clássica - sim. mas quem disse que bigode é apenas para HTML? é um mecanismo de templates, e a geração de código é comumente implementada usando esses mecanismos de template;)

você não passa o modelo diretamente.

deve ser uma escolha do usuário, não uma limitação / restrição

Vou dar mais um exemplo e tentarei fazê-lo sem trair o molho secreto.

Suponha que uma estrutura de dados em árvore descreva os ativos pertencentes a um jogador em um jogo de estratégia.
A árvore pode ter cerca de 5 níveis, por exemplo:
Aliance -> Empire -> City -> Army -> Troops

Cada nível pode fornecer bônus modificador - por exemplo - ou bônus de ataque, bônus de defesa, bônus de saúde, etc.
Os modificadores que tratam das mesmas estatísticas são descritos pelo mesmo nome em todos os níveis (principalmente porque são calculados recursivamente).
Você precisa usar o mecanismo de modelo para apresentar um simulador de batalha que deve ajudar os jogadores a escolher qual exército é o exército ideal para um determinado desafio, exibindo as estatísticas de batalha das tropas no exército - que residem nos níveis mais baixos, mas coletam a batalha modificadores que são nomeados pelo mesmo nome de atributo na árvore.
Isso é _muito_ simplificado, mas baseado em uma história real onde outras ferramentas resolveram o problema com grande facilidade, sem exigir uma camada intermediária de tradução.

Acrescentarei a dificuldade: às vezes, os exércitos são alocados em uma força-tarefa no nível da Aliança.
Alliance -> Rally -> Troops
A ferramenta deve ser genérica o suficiente (recursiva simples) e não depender de níveis concretos.

Resolvi com o que o bigode vai chamar de parciais, só que não usei bigode ...

@osher disse:

deve ser uma escolha do usuário, não uma limitação / restrição

Não há dúvida de que o bigode tem opiniões. Sua filosofia de "templates menos lógicos" coloca muitas restrições nos templates, fato que muitas vezes requer preparação de dados / modelo antes de entregá-los ao template para renderização. Se isso não atender às suas necessidades, existem alternativas que podem ser melhores, como guidão ou mesmo lodash.

Direito. Esqueci completamente o guiador.

Permite perder usuários para o guidão.
Essa é uma decisão de design aceitável.

Tenho certeza de que @osher estava sendo sarcástico quando disse "Essa é uma decisão de design aceitável.", Mas este tópico foi abandonado desde 2016. O que está acontecendo? Parece que essa pergunta está sendo evitada neste repositório JavaScript, bem como no repositório principal:
https://github.com/mustache/mustache.github.com/issues/103

Eu, pelo menos, acho que ser capaz de fazer referência ao escopo pai não tem lógica e não deve interferir com os ideais do bigode.

Gosto da ideia de sempre poder acessar o escopo da raiz com um símbolo, como um "../" inicial:

Mustache.render('{{a1}}{{#a}}{{b.c}}{{../a1}}{{/a}}',{"a":{"b":{"c":"x1"}},"a1":"x2"})
"x2x1"

Eu gostaria que isso renderizasse "x2x1x2", mas omite o último porque não é assim que funciona.
Achei que recomendaria usar algo como JSONPath: https://goessner.net/articles/JsonPath/index.html#e2, porém, ao contrário do XPath para XML, ele não recomenda / implementa o operador pai, que é o que eu esperava por.

Talvez o Mustache pudesse apenas tentar permanecer compatível com o guidão e usar a sintaxe ../ para o contexto pai?

AFAIK, o guidão é apenas JS, enquanto o bigode usa a mesma sintaxe em muitos ambientes, PHP por exemplo. Se você quiser alterar a sintaxe do bigode, precisará convencer todas as outras implementações não-js a fazer o mesmo; uma ordem de altura. Além disso, ao modificar o código JS, achei problemático subir "um nível", embora tenha adicionado uma maneira de voltar a enraizar em meu fork , que foi muito simples de implementar ...

Alguma coisa sobre isso?

Também deve haver documentação e recomendação de estilo para situações em que a notação de ponto é opcional.

view = { wrap: { txt: "test" } };
{{#wrap}}
  {{wrap.txt}} {{! Should I use this?}}
  {{txt}} {{! Or this?}}
{{/wrap}}

Mais detalhes aqui: https://stackoverflow.com/q/62166467/5637701

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

Questões relacionadas

funston picture funston  ·  7Comentários

ForbesLindesay picture ForbesLindesay  ·  14Comentários

kuldeepdhaka picture kuldeepdhaka  ·  9Comentários

mbrodala picture mbrodala  ·  16Comentários

amper5and picture amper5and  ·  5Comentários