I am trying to create an undo process (reinitialize template) using a deep copy of a data-linked object. This may not be an ideal method, but I cannot use View Models, merge() and unmap() right now.
mainObject
renders templateA (mainObject derived from AJAX request, Type: json)
mainObject = $.extend(true, mainObject, addObject)
; adds additional objects for editing purposes, renders templateB (addObject derived from AJAX request, Type: json)
I have been using the two above templates and objects without issues for quite some time.
Now...
I want to make a deep copy/clone of mainObject
in the case the user cancels editing (two-way data-linked).
When I create mainObjectClone = JSON.parse(JSON.stringify(mainObject))
and re-render using the same template, templateB, I am getting errors related to context ~root
.
It is my understanding that JSON.parse() returns the same type of object as AJAX request, Type: json.
Either the object is not returned or errors like: Uncaught TypeError: Cannot read property '0' of undefined
. +((v=view.ctxPrm("root").myPhotos[j._sq(0)])!=null?v:"")
With debug turned on, all parts of template render fine except where ~root
is used.
The strange thing is, ~root
does not work where I have defined it in the template...but in further testing, if I add ~root
to a 'different' top level object (one that doesn't need context), it works there strangely.
I have tried these and all break on ~root
:
myObjectClone = $.extend(true, {}, mainObject)
mainObject, addObject
to mainObject = $.extend(true, addObject, mainObject)
breaks ~root
access too (first object gets extended).I have tried but failed to reproduce the issue in jsfiddle...although with limited data/template.
Console log shows all objects as correctly formed.
How does ~root
get created/initialized...on some or all objects?
What code conflicts might alter the ~root
context?
Any tips or pointers would be appreciated.
UPDATE
Although I have commented out all helpers, etc, to bare-bones template + data (with debug on)...the ~root issue still remained. This 'finally' led me to believe this had nothing to do with the template or data.
So here is my scenario:
If I change TemplateA render method to render() (instead of link()); and then render TemplateB, ~root context works.
Another scenario: instead of rendering TemplateB with deep copy/clone object (DataA + DataB)...I combined the data on the server and rendered against that. This also produced the ~root context issue.
I then thought maybe there was an issue when link() is called from multiple templates that their objects with same name would conflict. So I isolated one of the common objects, renamed it and rendered a test template with name changes....~root issue remained.
That's all I know for now ;-)
Answering my own question here...
There was no problem with JsViews here...the issue with ~root was of my own creation ;-)
The problem was cause by injecting link() templateB into link() templateA...thus creating a conflict with ~root.
My data sources and templates used to be combined...I split them for testing and wasn't thinking clearly.
Essentially I was doing this:
<script id="templateA" type="text/x-jsrender">
<div id="userView">...</div>
<div id="editView"></div>
</script>
<script id="templateB" type="text/x-jsrender">
...
</script>
$.templates("#templateA").link("#userView", dataA)
onClick openEditView...
$.templates("#templateB").link("#editView", $.extend(true, dataA, dataB))
The fix is pretty easy, something like this:
<script id="templateA" type="text/x-jsrender">
<div id="userView">...</div>
{{if editable}}
{{include tmpl="templateB" /}}
{{/if}}
</script>
<script id="templateB" type="text/x-jsrender">
...
</script>
$.templates("#templateA").link("#userView", dataA)
onClick openEditView...
$.extend(true, dataA, dataB))
This solves the ~root issue and also deep copy object methods now work.