Handlebars.js: Puis-je utiliser plusieurs assistants dans une seule balise ?

Créé le 7 sept. 2012  ·  17Commentaires  ·  Source: handlebars-lang/handlebars.js

comme {{ helper1 helper2 text }} , vous savez parfois qu'un seul assistant ne suffit pas pour faire le travail.

Commentaire le plus utile

cela semble avoir un support natif en utilisant quelque chose comme:

{{ helper1 (helper2 text) }}

Tous les 17 commentaires

Je pense qu'il faudrait un moyen d'imbriquer des expressions, comme ceci : {{headerText {{getTitle "my_page"}}}} .

Ce n'est pas actuellement pris en charge et je n'ai pas l'intention de le soutenir.

Cependant, vous pouvez théoriquement créer un assistant qui consomme et enchaîne intentionnellement d'autres assistants :

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

Si quelqu'un est intéressé, j'ai créé une telle aide :

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;
});

Fonctionne comme ceci :

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

@Znarkus qui introduit une dépendance à jQuery

@jrajan J'ai seulement utilisé jQuery.each , n'hésitez pas à le réécrire selon vos préférences.

Si quelqu'un est intéressé par une version agnostique 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();
});

Un problème avec les deux implémentations mérite d'être noté : si l'un des arguments est destiné à être des valeurs à transmettre à un assistant, mais s'avère également être (coercible à) des chaînes qui correspondent au nom d'un assistant existant, il y aura des résultats inattendus.

Voici deux implémentations. Ils vous permettent tous les deux d'envoyer plusieurs arguments à chaque assistant, contrairement aux exemples précédents.
Ils sont également écrits en coffee-script et dépendent du trait de soulignement ou du lodash.

Le premier vous permet de faire quelque chose comme ceci :
{{{chain 'join-strings' 'link-twitter-handles' '@' twitterUsername}}}
Mais quelque chose comme ça produirait des résultats inattendus :
{{{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

Ce deuxième exemple a un séparateur qui permet à chain séparer les helpers des arguments.
L'assistant supposera que chaque argument avant le séparateur est un assistant et que tous les autres doivent être transmis en tant qu'arguments aux assistants.

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

Étant donné ce modèle :
{{{chain 'join-strings' 'link-twitter-handles' '@' 'join-strings' twitterUsername}}}
et cet objet :
{twitterUsername: 'abc'}
Nous pourrions nous attendre à un modèle compilé comme celui-ci :
<a href="https://twitter.com/join-stringsabc">@join-stringsabc</a>

J'ai pris l' implémentation de ai transformée en une version pour les assistants de bloc. J'exige également que les noms des assistants soient préfixés par '!!' pour éviter le problème des arguments correspondant aux noms des assistants.

/**
 * 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;
});

cela semble avoir un support natif en utilisant quelque chose comme:

{{ helper1 (helper2 text) }}

Dans certains cas, vous pouvez faire fonctionner vos assistants comme :

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

@Znarkus En utilisant votre méthode, lorsque je transmets deux assistants qui ont des chaînes sûres, j'ai appliqué mes pauses de code. La première fois que je transmets des données, elles entrent sous forme de chaîne, mais le deuxième filtre la valeur transmise semble être un objet ? Dans mon débogueur, cela s'affiche sous la forme "un saut de ligne, puis une chaîne : "ma valeur" ; Je ne sais pas ce que SafeString fait à la valeur, mais le traverser deux fois ne semble pas bien fonctionner.

    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
    });

+1 Approche @amwmedia - {{pluralize (titleize (humanize schema.name))}}

+1 qui ressemble à une belle syntaxe propre.

+1 @amwmedia Fonctionne parfaitement merci

L' approche @amwmedia fonctionne comme un charme, mais sans Handlebars.SafeString() comme @cssagogo mentionné ci-dessus.

Alors tu peux faire qch. Comme:

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

Merci

J'ai moi-même rencontré ce problème. Je sais que je suis vraiment en retard, mais j'ai une solution qui a fonctionné pour moi. Veuillez m'excuser si cela a déjà été mentionné (je n'ai pas pris le temps de vérifier). Ce n'est pas la solution la plus cool et ce n'est techniquement pas une réponse directe à votre question mais c'est une solution au problème (exécuter plusieurs fonctions sur une valeur).

Je conserve toutes mes fonctions d'assistance dans un fichier séparé. Parce qu'ils sont tous au même endroit, je peux transmettre la valeur à un assistant, puis appeler les autres fonctions que j'ai dans le fichier de ma fonction d'assistance. Alors:

{{ function1 value }}

fichier d'aide

function2 (value) {
   // code
}

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

Bien sûr, c'est un moyen simple de pouvoir utiliser autant de fonctions que vous le souhaitez. Vous pouvez même désigner une fonction de base qui agit comme votre « chaîneur ».

{{ chainer value }}

fichier d'aide

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;
}

Je ne l'ai pas fait moi-même mais je ne vois pas pourquoi cela ne fonctionnerait pas.

Remarque Vous n'avez qu'à enregistrer les fonctions que vous souhaitez utiliser dans votre html en tant qu'assistants de guidon. Personnellement, j'ai tous les miens enregistrés parce que je les utilise indépendamment les uns des autres, mais vous n'êtes pas obligé de le faire si vous ne prévoyez pas avoir besoin de l'utiliser directement.

Un retour à la programmation procédurale :)

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

DylanPiercey picture DylanPiercey  ·  7Commentaires

amirzandi picture amirzandi  ·  7Commentaires

fcpauldiaz picture fcpauldiaz  ·  4Commentaires

rhariraman picture rhariraman  ·  5Commentaires

ShintaroOkuda picture ShintaroOkuda  ·  7Commentaires