How do I prevent jQuery Template from digging too deeply on a string array in a recursively “reflection” template?

六月ゝ 毕业季﹏ 提交于 2019-12-13 04:03:17

问题


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>

回答1:


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


来源:https://stackoverflow.com/questions/7436189/how-do-i-prevent-jquery-template-from-digging-too-deeply-on-a-string-array-in-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!