Handlebars.js: 組み込みの「各」ヘルパーでのマップ、セット、およびカスタム反復可能オブジェクトのサポート?

作成日 2018年01月10日  ·  6コメント  ·  ソース: handlebars-lang/handlebars.js

ES6環境でハンドルバーを使用する場合、組み込みのeachヘルパーの配列と汎用オブジェクトのみをサポートするという制限は不便になります。 これを回避するために、配列、マップ、セット、カスタム反復可能オブジェクト、およびジェネリックオブジェクトをサポートする独自のバージョンのeachヘルパーの登録を開始しました。 そのヘルパーは以下にあります。

組み込みのeachヘルパーにこれらのタイプのリストのサポートを導入する計画または意欲はありますか? ハンドルバーはポリフィルを回避することを目的としていることを理解しているので、ブラウザのサポートを損なうことなく新しいヘルパーを機能させる唯一の方法は、環境のネイティブサポートまたは事前にポリフィルされたサポートに応じてさまざまなリストタイプのサポートを段階的に有効にすることだと思います。 SetMap 、および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;

});

最も参考になるコメント

@karlvrは、マップサポートの新しい問題を開始できますか。 この問題の一部はすでに解決されており、クリーンなスタートを切りたいと思います。

全てのコメント6件

#1557で今可能になるはずです

@ nknapp #1557の実装はMap適切にサポートしていないようです。 現在、 Mapの_entry_である反復アイテムを生成します。これは[key, value]のタプルですが、上記のサンプルコードは反復アイテムをvalueにし、 @keyを設定します。

また、式は現在Mapをサポートしていないようですので、 {{person.myMap.myMapKey}}とは言えません。 私は今、この問題についてさらに掘り下げています。

runtime.jslookupPropertyに追加すると、 Mapのプロパティを検索できます。

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

このようなサポートを追加したいという欲求はありますか?

@karlvrあなたの提案は検討する価値があると思います。 しかし、私はそれについて議論したいと思います。

@karlvrは、マップサポートの新しい問題を開始できますか。 この問題の一部はすでに解決されており、クリーンなスタートを切りたいと思います。

@nknappは、迅速な対応に感謝します。 提案された変更を加えてPRを行いました。 そこで話し合ってもらえますか? #1679

このページは役に立ちましたか?
0 / 5 - 0 評価