Mustache.js: Accediendo al alcance principal

Creado en 11 dic. 2014  ·  18Comentarios  ·  Fuente: janl/mustache.js

Accediendo al alcance principal

Considerando :

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

Y la siguiente plantilla:

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

Tal como está, a veces tiene que acceder a la propiedad principal (en un modelo de nodo anidado, por ejemplo).
Se puede implementar fácilmente como usar "../" para obtener el alcance principal

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 lograr eso:

  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

Comentario más útil

Correcto. Me olvidé por completo del manillar.

Permite perder usuarios a los manillares.
Esa es una decisión de diseño aceptable.

Todos 18 comentarios

Esto no está en las especificaciones de mustache , ¿verdad? ¿No hay solución para esto? Me sorprende que nadie se haya topado con esta limitación antes.

Estoy de acuerdo en que a menudo es necesario acceder a cosas en el ámbito principal. Mi enfoque pragmático siempre ha sido evitar nombres de propiedad ambiguos. Eso me ha funcionado durante mucho tiempo, aunque a menudo da como resultado objetos extraños.

Por otro lado, hablando de experiencia con manillares; Tener esta habilidad podría tentar a las personas a crear una resolución de alcance parental enredada loca: {{../../../id}} es mucho más difícil de comprender que {{movieId}} .

Es cierto que el uso de "../" podría resultar en ilegibilidad. Pero de otra manera, el uso de caml para resolver el padre no se puede lograr, ya que puede tener caml en el alcance local. Además, creo que definir una palabra clave para acceder a los padres no respetaría la filosofía de Moustache.

Hablando francamente, no podría llegar a una idea mejor y más simple que usar la representación del directorio.

Sí, evitar nombres de propiedad ambiguos también conduce a plantillas más legibles / detalladas. Pero entiendo por qué a algunas personas les gustaría esta función.

¿Qué hay de escribir un paquete separado que modifique el funcionamiento interno de mustache.js para agregar la función deseada? Algo así como un complemento.

Para ser honesto, realmente no veo que esto suceda a menos que sea a través de un complemento o un pragma. Y una API de complemento no parece ser la prioridad en este momento.

He estado pensando un poco más en esto ...

Creo que la filosofía de Moustache no es pasar datos _ como están_ al renderizador, sino "prepararlos" en una vista de antemano. Entonces tendrías una propiedad parentId en tus nodos.

También es más fácil leer y mantener plantillas que tienen variables más detalladas:

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

Antes vs Después

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

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

(siento haberte llamado @bobthecow , pero siempre agradezco tu sabiduría de bigote: sonríe :)

ya puede subir, por lo que todo lo que hay que hacer para solucionar el problema que se muestra con la primera plantilla es envolver los datos con un objeto temporal {node: ... } , envolver la plantilla con {{#node}}...{{/node}} y luego {{node.id}} parte puede funcionar. no necesita (y no lo hará) mutar los datos existentes de esa manera, y puede agregar ambos "JIT" como to_html() la plantilla ...

se siente como una solución irregular. También funciona solo con el modelo simplista de 2 niveles en el que puede resolver mediante una envoltura de envoltura para la capa exterior. Pero, ¿y si el modelo es más profundo? que se siente haciendo malabares.

A menudo, necesito vincular un modelo que obtengo de las capas de datos inferiores, y mi trabajo es presentarlo, en cualquier forma que lo obtenga de la infra. La propuesta aquí es que tengo que convertir el modelo de forma recursiva hasta un estado presentable, lo que se consideraría aquí redable property names .
Esto no se ajusta convenientemente a la realidad ...
Sí, cierto, empareja la plantilla con el modelo. Pero, ¿puede mostrarme una plantilla que no esté acompañada de reglas de un modelo concreto? Todas las plantillas están hechas, por definición, para representar un modelo definido.
Otra capa mueve la capa de definición un paso hacia atrás y requiere una capa de traducción, lo cual es dedioso y no siempre necesario.

En mi humilde opinión, creo que la herramienta debería dejar la elección al usuario, en lugar de imponer reglas obstinadas

Para los lectores, ejemplo de lo que sugiere @rndme :

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

El uso de la siguiente plantilla no funciona a partir de latest , pero _ debería funcionar_, en mi opinión.

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

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

Sí, cierto, empareja la plantilla con el modelo. Pero, ¿puede mostrarme una plantilla que no esté acompañada de reglas de un modelo concreto? Todas las plantillas están hechas, por definición, para representar un modelo definido.
Otra capa mueve la capa de definición un paso atrás y requiere una capa de traducción, que es tediosa y no siempre necesaria

Afaik, la filosofía de Moustache siempre ha sido que genera una vista que se pasa a la plantilla, no pasa el modelo directamente.

@osher ¿Puede mostrarnos un ejemplo que no pueda resolver fácilmente con el consejo / truco mencionado anteriormente?

Intentaré proporcionar fragmentos más tarde, pero básicamente, con 3 niveles anidados, no funcionará porque no puede ajustar el nivel medio, debe transmutar la fuente a una vista procesada.
Podrá acceder al nivel superior envuelto, pero no tiene una solución para el nivel medio.

Tomemos, por ejemplo, un documento swagger, donde tienes el nivel de raíz, nivel de ruta, nivel de verbo (y hay más, pero detengámonos aquí). Cada nivel puede especificar una directiva personalizada: x-uses , que es una directiva DI para la capa de implementación.

Suponga que desea generar documentos HTML a partir de este documento arrogante.
Necesita una tabla plana que especifique para cada controlador de operación (el nivel de verbo) el DI que acepta y de qué capa lo hereda.
Si bien toda la información es inherente al documento Swagger, ahora tiene un problema.

Próximo.
Intente usar bigote para generar el código que implementa la API descrita en el documento que devuelve respuestas simuladas basadas en la respuesta predeterminada de la operación.
Intente generar doclets que describan lo que el desarrollador implementador que viene a reemplazar la respuesta simulada con lógica real debería esperar en su contexto de DI y sea específico sobre el nivel que obtiene.
Mismo...

No la generación HTML clásica, sí. pero ¿quién dijo que el bigote es solo para HTML? es un motor de plantillas, y la generación de código se implementa comúnmente usando dichos motores de plantilla;)

no pasa el modelo directamente.

que debe ser una elección del usuario, no una limitación / restricción

Les daré un ejemplo más, y trataré de hacerlo sin traicionar la salsa secreta.

Suponga una estructura de datos de árbol que describe los activos que posee un jugador en un juego de estrategia.
El árbol puede tener unos 5 niveles, por ejemplo:
Aliance -> Empire -> City -> Army -> Troops

Cada nivel puede proporcionar bonificación de modificador, por ejemplo, o bonificación de ataque, bonificación de defensa, bonificación de salud, etc.
Los modificadores que abordan las mismas estadísticas se describen con el mismo nombre en todos los niveles (principalmente porque se calculan de forma recursiva).
Debes usar el motor de plantillas para presentar un simulador de batalla que debería ayudar a los jugadores a elegir qué ejército es el ejército ideal para un desafío dado al mostrar las estadísticas de batalla de las tropas en el ejército, que residen en los niveles más bajos, pero acumulan batalla. modificadores que reciben el mismo nombre de atributo en todo el árbol.
Esto es _muy_ simplificado, pero basado en una historia real donde otras herramientas resolvieron el problema con gran facilidad, sin requerir una capa intermedia de traducción.

Agregaré dificultad: a veces, los ejércitos se asignan en un grupo de trabajo a nivel de la Alianza.
Alliance -> Rally -> Troops
La herramienta debe ser lo suficientemente genérica (simple recursiva) y no depender de niveles concretos.

Lo resolví con lo que llamaré bigote parciales, solo que no usé bigote ...

@osher dijo:

que debe ser una elección del usuario, no una limitación / restricción

No hay duda de que el bigote tiene opiniones. Su filosofía de "plantillas sin lógica" impone muchas restricciones a las plantillas, ese hecho a menudo requiere la preparación de datos / modelos antes de entregarlos a la plantilla para su renderizado. Si esto no se adapta a sus necesidades, existen alternativas que pueden ser mejores, como manubrios o incluso lodash.template, solo por nombrar algunas.

Correcto. Me olvidé por completo del manillar.

Permite perder usuarios a los manillares.
Esa es una decisión de diseño aceptable.

Estoy bastante seguro de que @osher estaba siendo sarcástico cuando dijo "Esa es una decisión de diseño aceptable", pero este tema ha sido abandonado desde 2016. ¿Qué está pasando? Parece que esta pregunta se está evitando en este repositorio de JavaScript, así como en el repositorio principal:
https://github.com/mustache/mustache.github.com/issues/103

Por mi parte, creo que poder hacer referencia al alcance principal no tiene lógica y no debería interferir con los ideales del bigote.

Me gusta la idea de poder acceder siempre al alcance raíz con un símbolo, como un "../" inicial:

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

Me gustaría que esto representara "x2x1x2" pero omite el último porque no es así como funciona.
Pensé que recomendaría usar algo como JSONPath: https://goessner.net/articles/JsonPath/index.html#e2 sin embargo, a diferencia de XPath para XML, no recomienda / implementar el operador principal, que es lo que esperaba por.

¿Quizás Moustache podría intentar ser compatible con los manillares y usar la sintaxis ../ para el contexto principal?

AFAIK, el manillar es solo JS, mientras que el bigote usa la misma sintaxis en muchos entornos, PHP por ejemplo. Si desea cambiar la sintaxis de bigote, deberá convencer a todas las demás implementaciones que no sean js para que hagan lo mismo; una orden grande. Además, al modificar el código JS, me resultó problemático subir "un nivel", aunque agregué una forma de volver a la raíz en mi bifurcación , que era bastante simple de implementar ...

¿Algo sobre esto?

También es necesario que exista documentación y recomendaciones de estilo para situaciones en las que la notación de puntos es opcional.

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

Más detalles aquí: https://stackoverflow.com/q/62166467/5637701

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

funston picture funston  ·  7Comentarios

rlightner picture rlightner  ·  7Comentarios

barbalex picture barbalex  ·  5Comentarios

chlab picture chlab  ·  11Comentarios

Immortalin picture Immortalin  ·  12Comentarios