Handlebars.js: ¿Puedo utilizar varios ayudantes en una sola etiqueta?

Creado en 7 sept. 2012  ·  17Comentarios  ·  Fuente: handlebars-lang/handlebars.js

como {{ helper1 helper2 text }} , sabes que a veces solo un ayudante no es suficiente para hacer el trabajo.

Comentario más útil

esto parece tener soporte nativo usando algo como:

{{ helper1 (helper2 text) }}

Todos 17 comentarios

Creo que debería haber una forma de anidar expresiones, como esta: {{headerText {{getTitle "my_page"}}}} .

Eso no es compatible actualmente y no tengo planes de hacerlo.

Sin embargo, teóricamente podrías crear un ayudante que consuma y encadene intencionalmente a otros ayudantes:

{{chain "helper1" "helper2" text}}

Si alguien está interesado, he creado un ayudante de este tipo:

Handlebars.registerHelper('chain', function () {
    var helpers = [], value;
    $.each(arguments, function (i, arg) {
        if (Handlebars.helpers[arg]) {
            helpers.push(Handlebars.helpers[arg]);
        } else {
            value = arg;
            $.each(helpers, function (j, helper) {
                value = helper(value, arguments[i + 1]);
            });
            return false;
        }
    });
    return value;
});

Funciona así:

{{chain "taxAdd" "formatPrice" this.product.price}}

@Znarkus que introduce una dependencia a jQuery

@jrajan Solo usé jQuery.each , siéntete libre de reescribirlo con tus preferencias.

Si alguien está interesado en una versión independiente de jQuery:

Handlebars.registerHelper('chain', function() {
  var helpers = [];
  var args = Array.prototype.slice.call(arguments);
  var argsLength = args.length;
  var index;
  var arg;

  for (index = 0, arg = args[index];
       index < argsLength;
       arg = args[++index]) {
    if (Handlebars.helpers[arg]) {
      helpers.push(Handlebars.helpers[arg]);
    } else {
      args = args.slice(index);
      break;
    }
  }

  while (helpers.length) {
    args = [helpers.pop().apply(Handlebars.helpers, args)];
  }

  return args.shift();
});

Vale la pena señalar un problema con ambas implementaciones: si alguno de los argumentos está destinado a ser valores para pasar a un ayudante, pero también resultan ser (coercibles a) cadenas que coinciden con el nombre de un ayudante existente, habrá resultados inesperados.

Aquí hay dos implementaciones. Ambos le permiten tener varios argumentos enviados a cada ayudante, a diferencia de los ejemplos anteriores.
También están escritas en escritura de café y dependen de guiones bajos o lodash.

El primero te permite hacer algo como esto:
{{{chain 'join-strings' 'link-twitter-handles' '@' twitterUsername}}}
Pero algo como esto produciría resultados inesperados:
{{{chain 'join-strings' 'link-twitter-handles' '@' 'join-strings' twitterUsername}}}

Handlebars.registerHelper 'chain', ->
    # Get rid of the options hash
    args = Array.prototype.slice.call arguments, 0, -1
    helpers = []
    argsForHelpers = null
    value = undefined

    _.each args, (arg, i) ->
        if Handlebars.helpers[arg]
            helpers.push Handlebars.helpers[arg]
        else if not value # Only call the helpers once
            value = arg
            unless argsForHelpers
                argsForHelpers = args[i+1..-1]
                argsForHelpers.unshift value
            _.each helpers, (helper) ->
                argsForHelpers[0] = value
                value = helper.apply null, argsForHelpers

    value

Este segundo ejemplo tiene un separador que permite a chain dividir los ayudantes de los argumentos.
El ayudante asumirá que cada argumento antes del separador es un ayudante y todos los demás deben pasarse como argumentos a los ayudantes.

Handlebars.registerHelper 'chain', ->
    # Get rid of the options hash
    args = Array.prototype.slice.call arguments, 0, -1
    helpers = []

    for arg,i in args
        if arg is '--'
            argsForHelpers = args.slice i + 1
            value = argsForHelpers[0]
            break
        else
            helpers.push Handlebars.helpers[arg]

    _.each helpers, (helper) ->
        argsForHelpers[0] = value
        value = helper.apply null, argsForHelpers

    value

Dada esta plantilla:
{{{chain 'join-strings' 'link-twitter-handles' '@' 'join-strings' twitterUsername}}}
y este objeto:
{twitterUsername: 'abc'}
Podríamos esperar una plantilla compilada como esta:
<a href="https://twitter.com/join-stringsabc">@join-stringsabc</a>

Tomé la implementación de

/**
 * Takes an arbitrary number of arguments, the first of which is the operation type 'AND' or 'OR'.
 * Following that will be a list of block helper names prefixed by '!!'.
 * Calls each block helper with the remaining arguments.
 *
 * <strong i="7">@returns</strong> {string}  returns options.fn(this) or options.inverse(this) depending on result of each helper and operation type
 */
Handlebars.registerHelper('chainBlockHelpers', function() {
    var index, arg, helperResult, pass,
        helpers = [],
        args = Array.prototype.slice.call(arguments),
        argsLength = args.length,
        options = args[argsLength-1],
        operation = args.shift(),
        passVal = options.fn(this),
        failVal = options.inverse(this);

    if (operation !== 'AND' && operation !== 'OR')
        throw new Error ('chainBlockHelpers only supports "AND" or "OR" operations.')

    for (index = 0, arg = args[index]; index < argsLength; arg = args[++index]) {
        if (typeof arg == 'string' && arg.startsWith('!!') && Handlebars.helpers[arg.substr(2)]) {
            helpers.push(Handlebars.helpers[arg.substr(2)]);
        } else {
            args = args.slice(index);
            break;
        }
    }

    if (operation === 'AND') {
        pass = true;
        while (helpers.length) {
            helperResult = helpers.pop().apply(Handlebars.helpers, args);
            if (helperResult == failVal) {
                pass = false;
                break;
            }
        }
    } else {
        pass = false;
        while (helpers.length) {
            helperResult = helpers.pop().apply(Handlebars.helpers, args);
            if (helperResult == passVal) {
                pass = true;
                break;
            }
        }
    }

    return pass ? passVal : failVal;
});

esto parece tener soporte nativo usando algo como:

{{ helper1 (helper2 text) }}

En algunos casos, puede hacer que sus ayudantes funcionen como:

{{#helper1}}{{helper2}}content{{/helper2}}{{/helper1}}

@Znarkus Usando su método, cuando paso dos ayudantes que tienen cadenas seguras aplicadas, mi código se rompe. La primera vez que paso datos, aparece como una cadena, pero el segundo filtro, ¿el valor que se pasa parece ser un objeto? En mi depurador se muestra como 'un salto de línea y luego cadena:' mi valor '; No estoy seguro de qué hace SafeString con el valor, pero pasarlo dos veces no parece funcionar bien.

    Handlebars.registerHelper('shortNumber', function (value) {
        //return new Handlebars.SafeString(iSpot.number.shortNumber(value)); // Breaks
        return iSpot.number.shortNumber(value);  // Works
    });
    Handlebars.registerHelper('asDollars', function (value) {
        //return new Handlebars.SafeString(iSpot.number.asDollars(value)); // Breaks
        return iSpot.number.asDollars(value); // Works
    });

Enfoque de +1 {{pluralize (titleize (humanize schema.name))}}

+1 que parece una sintaxis limpia y agradable.

+1 @amwmedia Funciona perfectamente gracias

El enfoque @amwmedia funciona como un encanto, pero solo sin Handlebars.SafeString() como @cssagogo mencionado anteriormente.

Entonces puedes hacer algo. me gusta:

{{> partial text=(concat value (default extension 'PDF')) }}

Gracias

Yo mismo me encontré con este problema. Sé que llegué tarde en esto, pero tengo una solución que funcionó para mí. Por favor, perdóneme si esto ya se mencionó (no me tomé el tiempo de verificarlo). Esta no es la mejor solución y técnicamente no es una respuesta directa a su pregunta, pero es una solución al problema (ejecutar múltiples funciones en un valor).

Guardo todas mis funciones auxiliares en un archivo separado. Debido a que están todos en el mismo lugar, puedo pasar el valor a un ayudante y luego simplemente llamar a cualquier otra función que tenga en el archivo de mi función auxiliar. Entonces:

{{ function1 value }}

archivo de ayuda

function2 (value) {
   // code
}

function1 (value) {
   // code
   function2(value)
   // code
   return value;
}

Por supuesto, esta es una forma sencilla de poder utilizar tantas funciones como desee. Incluso podría designar una función base que actúe como su "encadenamiento".

{{ chainer value }}

archivo de ayuda

function1 (value) {
   // code
}
function2 (value) {
   // code
}
function3 (value) {
   // code
}
function4 (value) {
   // code
}

function chainer(value) {
   function1(value)
   function2(value)
   function3(value)
   function4(value)
   return value;
}

No lo he hecho yo mismo, pero no veo por qué no funcionaría.

Nota Solo tienes que registrar las funciones que quieras usar en tu html como ayudantes de manubrios. Personalmente, tengo todos los míos registrados porque los uso de forma independiente, pero usted no tiene que hacerlo si no prevé la necesidad de usarlos directamente.

Un retroceso a la programación procedimental :)

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