How can I prevent jQuery Template from digging too deep in an array of strings in a recursive reflection pattern?

full jsFiddle example

From what I learned in my last question about $.tmpl , passing an array of strings to a pattern containing {{each}} will cause the pattern to move over each line in the array like an array of characters, because tmpl implicitly tmpl through arrays . Unfortunately, this means that if I am already in the given template and I recursively call this template again in an array of strings (sub-objects work fine), I skip the recursion level and try to create a pattern for each row in the array instead of the pattern of the array itself.

If I recursively template an object using {{each}} (basically reflection), how do I save this implicit array loop?

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> 
0
source share
1 answer

In case @ mblase75 is right (read: this is impossible) and no one else comes up with anything else, here is the workaround I came up with.

JsFiddle example

Since tmpl previously jumps level to level into arrays, I just came up with a system of templates that bounce from each other as the array appears. One template only processes array elements, allowing nested objects / arrays nested in it (it seems). Duplication is a little rough, but it seems to do the job even for 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")); 
0
source

All Articles