首页 > 解决方案 > 无法在 JSRender 循环中设置和访问动态变量

问题描述

我有一个循环,我只想在项目名称更改时显示标题。

所以我想设置一个变量 previousProject 并在 IF 语句中进行比较。

我尝试如下,设置它: {{* window.previousProject=:project}} 如下,阅读它: {{* if window.previousProject==:project}}

但我无法让它工作。

更新:

我想要完成的是:

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
...

所以 HEADER 实际上就是 data.project。

第一次,当标题未定义时,我需要打印一个开放的 div + 标题

每次检测到新标题时,我都需要打印一个关闭 div 和一个打开 div + header

最后一次(迭代中的最后一行)我需要打印一个结束 div

标签: variablesjsrender

解决方案


我不确定我是否正确理解了您的预期行为(例如,是您传递给的数据上project的变量,还是在模板外部全局定义的 JavaScript var。但无论如何,您在上面有一些语法错误,包括.data.projectrender(data):project

这是一个您可以尝试的工作示例,它可能会对您有所帮助。

<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>

更新

也就是说,我不确定您是否真的需要使用allowCode(true). 根据您对场景的额外解释,这里有几个替代方案:

如果你有这些数据

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"}
]};

您可以使用在模板渲染期间更改状态的方法,但无需使用allowCode(true). 而是通过~previousProject()get/set 模式传入一个助手:

var _prevProject = ""; //initial state

var html = $("#myTemplate").render(data, {
    prevProject: function(val) {
        if (val===undefined) {
            return _prevProject;
        } else {
            _prevProject=val;
            return "";
        }
    }
});

使用以下模板:

<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>

但实际上您根本不需要动态设置状态,而是可以直接访问数组项进行测试project,如下面的模板所示。(不需要辅助函数):

<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>

如果可能,最好使用 JsRender 标准标签,而不是将 allowCode 设置为 true 并将 javascript 代码插入模板...

添加:

上述解决方案工作正常,但模板不是很容易维护或理解,并且不遵循或揭示输出的自然层次结构。因此,另一种选择是使用过滤器属性: {{for filter=...}},如下所示:

帮手

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

模板:

<script id="myTemplate" type="text/x-jsrender">
{{for projects filter=~header ~projects=projects}}
  <div>
    {{:project}}
    {{for ~projects filter=~items}}
      {{:item}}
    {{/for}}
  </div>
{{/for}}
</script>

推荐阅读