如何防止 jQuery 模板在递归“反射”中对字符串数组挖掘得太深?模板?

发布于 2024-12-05 03:06:27 字数 2636 浏览 0 评论 0原文

完整的 jsFiddle 示例

从我在 关于 $ 的最后一个问题。 tmpl,将字符串数组传递到包含 {{each}} 的模板中将导致模板像遍历数组中的每个字符串一样字符数组,因为 tmpl 已经隐式循环遍历数组。不幸的是,这意味着,如果我已经在给定的模板中,并且我在字符串数组上再次递归调用该模板(子对象工作正常),我会跳过递归级别并尝试对数组中的每个字符串进行模板化,而不是数组本身的模板化。

如果我通过 {{each}} (基本上是反射)递归地模板化一个对象,如何防止隐式数组循环发生?

HTML

<div class="results"></div>
<script id="reflectTemplate" type="text/x-jquery-tmpl"> 
    <ul>
        {{each(i, prop) $data}}
        {{if $data.hasOwnProperty(i)}}
        <li>
            ${i}:
            {{if $item.shouldDigDeeper(prop)}}
            {{tmpl(prop, { shouldDigDeeper: $item.shouldDigDeeper, formatDisplay: $item.formatDisplay }) "#reflectTemplate"}}
            {{else}}
            ${$item.formatDisplay(prop)}
            {{/if}}
        </li>
        {{/if}}
        {{/each}}
    </ul>
</script>

JavaScript

var data = {
        test2: "abc",
        test3: [ "abc", "123", "def", "456" ]
    },
    templateFunctions = {
        shouldDigDeeper: function(itemToCheck) {
            return null !== itemToCheck && "object" === typeof(itemToCheck);
        },
        formatDisplay: function(propertyValue) {
            var result = propertyValue;    
            if (null === result) {
                result = "null";
            }
            else if ("string" === typeof (propertyValue)) {
                result = "\"" + result + "\"";
            }
            return result;
        }
    };

$("#reflectTemplate").tmpl(data, templateFunctions).appendTo($(".results"));

实际输出

<ul>
    <li>test2: "abc" </li>
    <li>test3:
        <ul>
            <li>0: "a" </li>
            <li>1: "b" </li>
            <li>2: "c" </li>
        </ul>
        ...
        <ul>
            <li>0: "4" </li>
            <li>1: "5" </li>
            <li>2: "6" </li>
        </ul>
    </li>
</ul>

期望输出

<ul>
    <li>test2: "abc" </li>
    <li>test3:
        <ul>
            <li>0: "abc" </li>
            ...
            <li>1: "456" </li>
        </ul>
    </li>
</ul>

full jsFiddle Example

From what I found out on my last question about $.tmpl, passing an array of strings into a template containing an {{each}} will result in the template going over each string in the array like an array of characters because tmpl implicitly loops over arrays already. Unfortunately, that means, if I am already in a given template and I recursively call that template again on an array of strings (sub-objects work fine), I skip a level of recursion and try to template each string in the array instead of the templating the array itself.

If I am recursively templating an object by {{each}} (reflection, basically), how do I keep that implicit array loop from happening?

HTML

<div class="results"></div>
<script id="reflectTemplate" type="text/x-jquery-tmpl"> 
    <ul>
        {{each(i, prop) $data}}
        {{if $data.hasOwnProperty(i)}}
        <li>
            ${i}:
            {{if $item.shouldDigDeeper(prop)}}
            {{tmpl(prop, { shouldDigDeeper: $item.shouldDigDeeper, formatDisplay: $item.formatDisplay }) "#reflectTemplate"}}
            {{else}}
            ${$item.formatDisplay(prop)}
            {{/if}}
        </li>
        {{/if}}
        {{/each}}
    </ul>
</script>

JavaScript

var data = {
        test2: "abc",
        test3: [ "abc", "123", "def", "456" ]
    },
    templateFunctions = {
        shouldDigDeeper: function(itemToCheck) {
            return null !== itemToCheck && "object" === typeof(itemToCheck);
        },
        formatDisplay: function(propertyValue) {
            var result = propertyValue;    
            if (null === result) {
                result = "null";
            }
            else if ("string" === typeof (propertyValue)) {
                result = "\"" + result + "\"";
            }
            return result;
        }
    };

$("#reflectTemplate").tmpl(data, templateFunctions).appendTo($(".results"));

Actual Output

<ul>
    <li>test2: "abc" </li>
    <li>test3:
        <ul>
            <li>0: "a" </li>
            <li>1: "b" </li>
            <li>2: "c" </li>
        </ul>
        ...
        <ul>
            <li>0: "4" </li>
            <li>1: "5" </li>
            <li>2: "6" </li>
        </ul>
    </li>
</ul>

Desired Output

<ul>
    <li>test2: "abc" </li>
    <li>test3:
        <ul>
            <li>0: "abc" </li>
            ...
            <li>1: "456" </li>
        </ul>
    </li>
</ul>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

套路撩心 2024-12-12 03:06:27

如果 @mblase75 是正确的(阅读:这是不可能的)并且没有其他人想出其他任何东西,这是我想出的一种解决方法。

jsFiddle 示例

由于 tmpl 预先跳转到数组的更深层次,我只是提出了一个模板系统,当数组出现时,模板系统会相互反弹。一个模板仅处理数组项,同时允许在其中嵌套对象/数组(看起来)。复制有点粗糙,但它似乎可以完成甚至疯狂的嵌套数组的工作。

HTML

<div class="results"></div>
<script id="arrayDisplayTemplate" type="text/x-jquery-tmpl">
<li>
    {{if null !== $data && "object" === typeof ($data)}}
        {{if $data instanceof Array}}
    [
    <ul>
        {{tmpl($data, { formatDisplay: $item.formatDisplay }) "#arrayItemTemplate"}}
    </ul>
    ]
        {{else}}
    {{tmpl($data, { formatDisplay: $item.formatDisplay }) "#reflectTemplate"}}
        {{/if}}
    {{else}}
    ${$item.formatDisplay($data)}
    {{/if}}
</li>
</script>
<script id="reflectTemplate" type="text/x-jquery-tmpl"> 
<ul>
    {{each(i, prop) $data}}
    {{if $data.hasOwnProperty(i)}}
    <li>
        ${i}:
        {{if null !== prop && "object" === typeof (prop)}}
            {{if prop instanceof Array}}
        [
        <ul>
            {{tmpl(prop, { formatDisplay: $item.formatDisplay }) "#arrayDisplayTemplate"}}
        </ul>
        ]
            {{else}}
        {{tmpl(prop, { formatDisplay: $item.formatDisplay }) "#reflectTemplate"}}
            {{/if}}
        {{else}}
        ${$item.formatDisplay(prop)}
        {{/if}}
    </li>
    {{/if}}
    {{/each}}
</ul>
</script>

JavaScript

var data = {
    test1: 123,
    test2: { w: [ "some", "string", "array" ], x: 1, y: 2, z: "abc" },
    test3: [ "abc", "123", "def", "456" ],
    test4: null
},
    templateFunctions = {
        formatDisplay: function(propertyValue) {
            var propertyType = typeof (propertyValue),
                result = propertyValue;

            if (null === result) {
                result = "null";
            }
            else if ("string" === propertyType) {
                result = "\"" + result + "\"";
            }
            return result;
        }
    };

$("#reflectTemplate").tmpl(data, templateFunctions).appendTo($(".results"));

In case @mblase75 is right (read: it isn't possible) and no one else comes up with anything else, here is a workaround I came up with.

jsFiddle example

Since tmpl pre-jumps a level deeper into arrays, I just came up with a system of templates that bounce off each other as an array comes up. One template handles only array items, while allowing nested objects/arrays within it (it seems). The duplication is a bit rough, but it appears to do the job for even crazy nested arrays.

HTML

<div class="results"></div>
<script id="arrayDisplayTemplate" type="text/x-jquery-tmpl">
<li>
    {{if null !== $data && "object" === typeof ($data)}}
        {{if $data instanceof Array}}
    [
    <ul>
        {{tmpl($data, { formatDisplay: $item.formatDisplay }) "#arrayItemTemplate"}}
    </ul>
    ]
        {{else}}
    {{tmpl($data, { formatDisplay: $item.formatDisplay }) "#reflectTemplate"}}
        {{/if}}
    {{else}}
    ${$item.formatDisplay($data)}
    {{/if}}
</li>
</script>
<script id="reflectTemplate" type="text/x-jquery-tmpl"> 
<ul>
    {{each(i, prop) $data}}
    {{if $data.hasOwnProperty(i)}}
    <li>
        ${i}:
        {{if null !== prop && "object" === typeof (prop)}}
            {{if prop instanceof Array}}
        [
        <ul>
            {{tmpl(prop, { formatDisplay: $item.formatDisplay }) "#arrayDisplayTemplate"}}
        </ul>
        ]
            {{else}}
        {{tmpl(prop, { formatDisplay: $item.formatDisplay }) "#reflectTemplate"}}
            {{/if}}
        {{else}}
        ${$item.formatDisplay(prop)}
        {{/if}}
    </li>
    {{/if}}
    {{/each}}
</ul>
</script>

JavaScript

var data = {
    test1: 123,
    test2: { w: [ "some", "string", "array" ], x: 1, y: 2, z: "abc" },
    test3: [ "abc", "123", "def", "456" ],
    test4: null
},
    templateFunctions = {
        formatDisplay: function(propertyValue) {
            var propertyType = typeof (propertyValue),
                result = propertyValue;

            if (null === result) {
                result = "null";
            }
            else if ("string" === propertyType) {
                result = "\"" + result + "\"";
            }
            return result;
        }
    };

$("#reflectTemplate").tmpl(data, templateFunctions).appendTo($(".results"));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文