I have a loop where I only want to display the header when a project name changes.
So I would like to set a variable previousProject and compare it in an IF statement.
I have tried as follows, setting it:
{{* window.previousProject=:project}}
And as follows, reading it:
{{* if window.previousProject==:project}}
But I can't get it to work.
Update:
What I am trying to accomplish is this:
HEADER 1 (This only prints on the first occurrence of HEADER 1)
ITEM 1.1
ITEM 1.2
ITEM 1.3
...
HEADER 2 (This only prints on the first occurrence of HEADER 2)
ITEM 2.1
ITEM 2.2
ITEM 2.3
...
So HEADER is in fact data.project.
The first time, when header is undefined I need to print an opening div + header
Every time a new header is detected I need to print a closing div and an opening div + header
The last time (last row in the iteration) I need to print a closing div
I'm not sure if I understand correctly your intended behavior (for example is project
a variable data.project
on the data you are passing to render(data)
,
or is it a JavaScript var defined globally outside the template. But at any rate you have some syntax errors above, including :project
.
Here is a working example that you can try out, which may help you.
<script id="myTemplate" type="text/x-jsrender">
{{* window.previousProject=data.project;}}
{{* if (window.previousProject==data.project) { }}
A {{*:data.project}} {{:project}}
{{* } else { }}
B {{*:window.previousProject}}
{{* } }}
{{* window.previousProject="Other project"; }}
{{* if (window.previousProject==data.project) { }}
A {{*:data.project}} {{:project}}
{{* } else { }}
B {{*:window.previousProject}}
{{* } }}
</script>
<div id="result"></div>
<script>
var data = {project: "My project"};
$.views.settings.allowCode(true);
var html = $("#myTemplate").render(data);
$("#result").html(html);
</script>
UPDATE
That said, I'm not sure you actually need to use allowCode(true)
. Here are a couple of alternatives, based on your additional explanation of the scenario:
If you have this data
data = {projects: [
{project: "Header1", item: "Item 1.1"},
{project: "Header1", item: "Item 1.2"},
{project: "Header1", item: "Item 1.3"},
{project: "Header2", item: "Item 2.1"},
{project: "Header2", item: "Item 2.2"},
{project: "Header2", item: "Item 2.3"},
{project: "Header3", item: "Item 3.1"},
{project: "Header3", item: "Item 3.2"},
{project: "Header3", item: "Item 3.3"}
]};
you can use your approach of having state which is mutated during template rendering, but without exposing full javascript with allowCode(true)
. Instead pass in a ~previousProject()
helper with a get/set pattern:
var _prevProject = ""; //initial state
var html = $("#myTemplate").render(data, {
prevProject: function(val) {
if (val===undefined) {
return _prevProject;
} else {
_prevProject=val;
return "";
}
}
});
with the following template:
<script id="myTemplate" type="text/x-jsrender">
{{for projects}}
{{if !~prevProject()}}
<div>{{:project}} {{:item}}
{{else ~prevProject()===project}}
{{:item}}
{{else}}
</div><div>{{:project}} {{:item}}
{{/if}}
{{:~prevProject(project)}}
{{/for}}
</div>
</script>
But in fact you don't need to set state dynamically at all, but instead can access the array items directly to test for project
, as in the following template. (No helper function needed for this):
<script id="myTemplate" type="text/x-jsrender">
{{for projects ~projects=projects}}
{{if #getIndex()===0}}
<div>{{:project}} {{:item}}
{{else}}
{{if ~projects[#getIndex()-1].project===project}}
{{:item}}
{{else}}
</div><div>{{:project}} {{:item}}
{{/if}}
{{/if}}
{{/for}}
</div>
</script>
It's better to use the JsRender standard tags, when possible, rather than setting allowCode to true and inserting javascript code into the template...
ADDED:
The above solutions work fine, but the template is not very easy to maintain or understand, and it doesn't follow or reveal the natural hierarchical structure of the output. So yet another alternative is to use the filter property: {{for filter=...}}
, as in the following:
Helpers
var html = $("#myTemplate").render(data, {
header: function(item, index, items) {
if (index===0 || item.project!==items[index-1].project) {
_prevProject=item.project;
return true;
}
},
items: function(item, index, items) {
return item.project===_prevProject;
}
});
Template:
<script id="myTemplate" type="text/x-jsrender">
{{for projects filter=~header ~projects=projects}}
<div>
{{:project}}
{{for ~projects filter=~items}}
{{:item}}
{{/for}}
</div>
{{/for}}
</script>