Handlebars.js: Prise en charge des cartes, des ensembles et des itérables personnalisés dans l'assistant "chaque" intégré ?

Créé le 10 janv. 2018  ·  6Commentaires  ·  Source: handlebars-lang/handlebars.js

Lors de l'utilisation de Handlebars dans un environnement ES6, la limitation de l'assistant each intégré de ne prendre en charge que les tableaux et les objets génériques devient gênante. Pour contourner ce problème, j'ai commencé à enregistrer ma propre version de l'assistant each qui prend en charge les tableaux, les cartes, les ensembles, les itérables personnalisés et les objets génériques. Cette aide est ci-dessous.

Existe-t-il un plan ou une volonté d'introduire la prise en charge de ces types de listes dans l'assistant each intégré ? Je demande parce que je comprends que Handlebars vise à éviter les polyfills et j'imagine que la seule façon de faire fonctionner le nouvel assistant sans compromettre la prise en charge du navigateur serait d'activer progressivement la prise en charge des différents types de liste en fonction de la prise en charge native ou pré-polyfille de l'environnement pour Set , Map et Symbol .

Handlebars.registerHelper("each", function (contexts, options) {

    // Throw a runtime exception if options were not supplied.
    if (!options) {
        throw new Handlebars.Exception("Must pass iterator to #each");
    }

    // If the "list of contexts" is a function, execute it to get the actual list of contexts.
    if (typeof contexts === "function") {
        contexts = contexts.call(this);
    }

    // If data was supplied, frame it.
    const data = options.data ? Object.assign({}, options.data, { _parent: options.data }) : undefined;

    // Create the string into which the contexts will be handled and returned.
    let string = "";

    // Create a flag indicating whether or not string building has begun.
    let stringExtensionStarted = false;

    // Create a variable to hold the context to use during the next string extension. This is done to
    // allow iteration through the supplied list of contexts one step out of sync as they are looped
    // through later in this helper, ensuring a predictable sequence of value retrieval, string
    // extension, value retrieval, string extension...
    let nextContext;

    // Create a function responsible for expanding the string.
    const extendString = (final = false) => {

        // If other contexts have been encountered...
        if (nextContext) {

            // Expand the string using the block function.
            string += options.fn(nextContext.value, {
                data: data ? Object.assign(data, {
                    index: nextContext.index,
                    key: nextContext.key,
                    first: !stringExtensionStarted,
                    last: final
                }) : undefined,
                blockParams: [nextContext.key, nextContext.value]
            });

            // Note that string extension has begun.
            stringExtensionStarted = true;

        // If no contexts have been encountered and this is the final extension...
        } else if (final) {

            // Expand the string using the "else" block function.
            string += options.inverse(this);

        }

    };

    // If a list of contexts was supplied...
    if (contexts !== null && typeof contexts !== "undefined") {

        // Start a counter.
        let index = 0;

        // If an array list was supplied...
        if (Array.isArray(contexts)) {

            // For each of the possible indexes in the supplied array...
            for (const len = contexts.length; index < len; index++) {

                // If the index is in the supplied array...
                if (index in contexts) {

                    // Call the string extension function.
                    extendString();

                    // Define the context to use during the next string extension.
                    nextContext = {
                        index: index,
                        key: index,
                        value: contexts[index]
                    };

                }

            }

        // If a map list was supplied...
        } else if (contexts instanceof Map) {

            // For each entry in the supplied map...
            for (const [key, value] of contexts) {

                // Call the string extension function.
                extendString();

                // Define the context to use during the next string extension.
                nextContext = {
                    index: index,
                    key: key,
                    value: value
                };

                // Increment the counter.
                index++;

            }

        // If an iterable list was supplied (including set lists)...
        } else if (typeof contexts[Symbol.iterator] === "function") {

            // Get an iterator from the iterable.
            const iterator = contexts[Symbol.iterator]();

            // Create a variable to hold the iterator's next return.
            let next;

            // Do the following...
            do {

                // Iterate and update the variable.
                next = iterator.next();

                // If there is anything left to iterate...
                if (!next.done) {

                    // Call the string extension function.
                    extendString();

                    // Define the context to use during the next string extension.
                    nextContext = {
                        index: index,
                        key: index,
                        value: next.value
                    };

                    // Increment the counter.
                    index++;

                }

            // ... until there is nothing left to iterate.
            } while (!next.done);

        // If a list other than an array, map, or iterable was supplied...
        } else {

            // For each key in the supplied object...
            for (const key of Object.keys(contexts)) {

                // Call the string extension function.
                extendString();

                // Define the context to use during the next string extension.
                nextContext = {
                    index: index,
                    key: key,
                    value: contexts[key]
                };

                // Increment the counter.
                index++;

            }

        }

    }

    // Call the string extension a final time now that the last supplied context has been encountered.
    extendString(true);

    // Return the fully-extended string.
    return string;

});

Commentaire le plus utile

@karlvr pourriez-vous créer un nouveau problème pour le support Map. Certaines parties de ce problème sont déjà résolues et j'aimerais avoir un bon départ.

Tous les 6 commentaires

Cela devrait être possible maintenant, avec #1557

@nknapp , il semble que l'implémentation dans # 1557 ne supporte pas correctement Map . Il produit actuellement un élément itéré étant le _entry_ dans le Map , qui est un tuple de [key, value] , alors que l'exemple de code ci-dessus fait de l'élément itéré le value et définit @key , ce que je _pense_ est préférable. C'est préférable pour moi !

De plus, il semble que les expressions ne prennent pas actuellement en charge Map , vous ne pouvez donc pas dire {{person.myMap.myMapKey}} . Je me penche plus sur ce problème maintenant.

Avec un ajout dans lookupProperty dans runtime.js nous pouvons rechercher des propriétés dans Map s :

    lookupProperty: function(parent, propertyName) {
      if (parent instanceof Map) {
        return parent.get(propertyName)
      }

Y a-t-il un appétit pour ajouter un support comme celui-ci?

@karlvr Je pense que votre proposition mérite d'être examinée. Mais je voudrais en discuter.

@karlvr pourriez-vous créer un nouveau problème pour le support Map. Certaines parties de ce problème sont déjà résolues et j'aimerais avoir un bon départ.

@nknapp merci beaucoup pour votre réponse rapide ; Je viens de faire un PR avec les changements suggérés. Pourrions-nous discuter là-bas? #1679

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

Questions connexes

NickCis picture NickCis  ·  4Commentaires

rizen picture rizen  ·  6Commentaires

jlubean picture jlubean  ·  8Commentaires

nknapp picture nknapp  ·  3Commentaires

fcpauldiaz picture fcpauldiaz  ·  4Commentaires