Knockout.js:如何使用递归模板更新DOM(Knockout.js: How to update the DOM using recursive templates)

编程入门 行业动态 更新时间:2024-10-25 03:30:42
Knockout.js:如何使用递归模板更新DOM(Knockout.js: How to update the DOM using recursive templates)

我的目标是能够使用JSOM数组作为我的数据源并使用Knockout的递归模板功能构建HTML表单。

细节:

我只使用一个嵌套的JavaScript数组。 我的数据结构如下: 表单包含一个项目 项目包含一个字段或一个组。 一个组包含项目 基本上,页面由一个DIV组成,通过模板递归生成其他DIV:一个包含组,另一个包含项目。 在视觉上,您在页面上有两个数据块。 LHS面板显示配置为标题级别1的所有组。

使用递归模板我有一个适度的演示版本正常工作,你可以在这里看到。

我的问题:我想知道如何在单击LHS上的组时在RHS上填充模板。 比如说,如果我点击第1组,我希望看到第1组的所有项目,包括子组的项目(组1.1)。 但是,如果我单击组1.1,我只想查看组1.1的组项。 目前我甚至无法获得子组“组1.1”的项目来显示。 showGroupItems函数不返回true。

我的代码如下:

HTML

<script id="formDef" type="text/html"> <!--<p>FormDef</p>--> <div style="float: left; width: 300px;"> <!--<p>formDef</p>--> <!-- ko template: { name: renderGroup, foreach: formItems } --> <!-- /ko --> </div> <div style="float: left;"> <!-- ko template: { name: 'formElementNodeTemplate', foreach: formItems } --> <!-- /ko --> </div> </script> <script id="formElementNodeTemplate" type="text/html"> <!-- ko if: showGroupItems --> <ul data-bind=""> <li> <span data-bind="text: text"></span> <br /> <!-- ko template: { name: renderTemplate, foreach: formItems } --> <!-- /ko --> </li> </ul> <!-- /ko --> </script> <script id="group" type="text/html"> <!--<p>Group</p>--> <span data-bind="text: text, click: $root.selectSection"></span> <br /> <!-- ko template: { name: renderGroup, foreach: formItems } --> <!-- /ko --> </script> <script id="empty" type="text/html"> </script> <script id="field" type="text/html"> <!--<p>Paragraph</p>--> <ul> <li><span data-bind="text: text"></span></li> </ul> </script> <div data-bind="template: { name: 'formDef', data: $data }"></div>

脚本

function SortByOrdinal(a, b) { return ((a.ordinal < b.ordinal) ? -1 : ((a.ordinal > b.ordinal) ? 1 : 0)); } var FormGroup = function (formItem) { var self = this; self.def = formItem; self.isGroup = true; self.text = formItem.text; // title self.ordinal = formItem.ordinal; self.showGroupItems = ko.observable(false); var formItems = []; $(formItem.group.formItems).each(function (indx, fi) { if (fi.group != null) formItems[formItems.length] = new FormGroup(fi); else formItems[formItems.length] = new FormField(fi); }); formItems.sort(SortByOrdinal); self.formItems = ko.observableArray(formItems); self.renderTemplate = function (item) { if (item.isGroup) return 'formElementNodeTemplate'; else return 'field'; }; self.renderGroup = function (item) { if (item.isGroup && item.def.group.headingLevel == 1) return "group"; else return "empty"; }; return self; } var FormField = function (formItem) { var self = this; self.def = formItem; self.isGroup = formItem.group != null; self.text = formItem.text; self.ordinal = formItem.ordinal; return self; } var FormDef = function (formDef) { var self = this; self.text = formDef.text; self.formDef = formDef; self.showGroupItems = true; var formItems = []; $(formDef.formItems).each(function (indx, di) { if (di.group != null) formItems[formItems.length] = new FormGroup(di); else formItems[formItems.length] = new FormField(di); }); self.formItems = ko.observableArray(formItems); self.renderTemplate = function () { return 'formElementNodeTemplate' }; self.renderGroup = function (item) { if (item.isGroup && item.def.group.headingLevel == 1) return "group"; else return "empty"; }; self.selectedSection = ko.observable(); self.selectSection = function (item) { if (self.selectedSection()) self.selectedSection().showGroupItems(false); item.showGroupItems(true); self.selectedSection(item); }; return self; } var def = { "formItems": [ { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'1'}" }, "group": null, "text": "This is field 1.1", "ordinal": 1 }, { "field": { "paraId": "{value:'2'}" }, "group": null, "text": "This is field 1.2", "ordinal": 2 }, { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'3'}" }, "group": null, "text": "This is field 1.1.1", "ordinal": 1 } ], "headingLevel": 1 }, "text": "Group 1.1", "ordinal": 3 } ], "headingLevel": 1 }, "text": "Group 1", "ordinal": 2 } ], "id": 2, "text": "Project 1" }; var viewModel = new FormDef(def); ko.applyBindings(viewModel);

My goal is to be able to build a HTML form using a JSOM array as my data source and using Knockout's recursive template feature.

Details:

I'm working with only one nested JavaScript array. My data structure is the following: A form contains one item An item contains contains a field or a group. A group contains items Basically the page consists of one DIV which through template recursion generates other DIVs: one contains the groups and the other contains the items. Visually you have two blocks of data on the page. The LHS panel displays all the groups configured as heading level 1.

Using recursive template I've got a modest demo version working as you can see here.

My issue: I would like to know how to populate the template on RHS as you click a group on the LHS. Say for example, if I click on Group 1 I expect to see all items for Group 1 including the items for sub-groups (Group 1.1). However, if I click group 1.1 I only want to see the group items for group 1.1. At the moment I cannot even get the items form sub-group 'Group 1.1' to display. The showGroupItems function doesn't return true.

My code is as follows:

HTML

<script id="formDef" type="text/html"> <!--<p>FormDef</p>--> <div style="float: left; width: 300px;"> <!--<p>formDef</p>--> <!-- ko template: { name: renderGroup, foreach: formItems } --> <!-- /ko --> </div> <div style="float: left;"> <!-- ko template: { name: 'formElementNodeTemplate', foreach: formItems } --> <!-- /ko --> </div> </script> <script id="formElementNodeTemplate" type="text/html"> <!-- ko if: showGroupItems --> <ul data-bind=""> <li> <span data-bind="text: text"></span> <br /> <!-- ko template: { name: renderTemplate, foreach: formItems } --> <!-- /ko --> </li> </ul> <!-- /ko --> </script> <script id="group" type="text/html"> <!--<p>Group</p>--> <span data-bind="text: text, click: $root.selectSection"></span> <br /> <!-- ko template: { name: renderGroup, foreach: formItems } --> <!-- /ko --> </script> <script id="empty" type="text/html"> </script> <script id="field" type="text/html"> <!--<p>Paragraph</p>--> <ul> <li><span data-bind="text: text"></span></li> </ul> </script> <div data-bind="template: { name: 'formDef', data: $data }"></div>

Script

function SortByOrdinal(a, b) { return ((a.ordinal < b.ordinal) ? -1 : ((a.ordinal > b.ordinal) ? 1 : 0)); } var FormGroup = function (formItem) { var self = this; self.def = formItem; self.isGroup = true; self.text = formItem.text; // title self.ordinal = formItem.ordinal; self.showGroupItems = ko.observable(false); var formItems = []; $(formItem.group.formItems).each(function (indx, fi) { if (fi.group != null) formItems[formItems.length] = new FormGroup(fi); else formItems[formItems.length] = new FormField(fi); }); formItems.sort(SortByOrdinal); self.formItems = ko.observableArray(formItems); self.renderTemplate = function (item) { if (item.isGroup) return 'formElementNodeTemplate'; else return 'field'; }; self.renderGroup = function (item) { if (item.isGroup && item.def.group.headingLevel == 1) return "group"; else return "empty"; }; return self; } var FormField = function (formItem) { var self = this; self.def = formItem; self.isGroup = formItem.group != null; self.text = formItem.text; self.ordinal = formItem.ordinal; return self; } var FormDef = function (formDef) { var self = this; self.text = formDef.text; self.formDef = formDef; self.showGroupItems = true; var formItems = []; $(formDef.formItems).each(function (indx, di) { if (di.group != null) formItems[formItems.length] = new FormGroup(di); else formItems[formItems.length] = new FormField(di); }); self.formItems = ko.observableArray(formItems); self.renderTemplate = function () { return 'formElementNodeTemplate' }; self.renderGroup = function (item) { if (item.isGroup && item.def.group.headingLevel == 1) return "group"; else return "empty"; }; self.selectedSection = ko.observable(); self.selectSection = function (item) { if (self.selectedSection()) self.selectedSection().showGroupItems(false); item.showGroupItems(true); self.selectedSection(item); }; return self; } var def = { "formItems": [ { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'1'}" }, "group": null, "text": "This is field 1.1", "ordinal": 1 }, { "field": { "paraId": "{value:'2'}" }, "group": null, "text": "This is field 1.2", "ordinal": 2 }, { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'3'}" }, "group": null, "text": "This is field 1.1.1", "ordinal": 1 } ], "headingLevel": 1 }, "text": "Group 1.1", "ordinal": 3 } ], "headingLevel": 1 }, "text": "Group 1", "ordinal": 2 } ], "id": 2, "text": "Project 1" }; var viewModel = new FormDef(def); ko.applyBindings(viewModel);

最满意答案

我能够通过创建其他模板来解决问题。

这是代码:

HTML

<script id="formDef" type="text/html"> <!--<p>FormDef</p>--> <div style="float: left; width: 300px;"> <!--<p>formDef</p>--> <!-- ko template: { name: renderGroup, foreach: formItems } --> <!-- /ko --> </div> <div style="float: left;"> <!-- ko template: { name: 'formElementNodeTemplate', foreach: formItems } --> <!-- /ko --> </div> </script> <script id="formElementNodeTemplate" type="text/html"> <!-- ko if: showGroupItems --> <ul id="expList"> <li> <span data-bind="text: text"></span> <span data-bind="text: showGroupItems"></span> <br /> <ul> <!-- ko template: { name: renderTemplate, foreach: formItems } --> <!-- /ko --> </ul> </li> </ul> <!-- /ko --> <!-- ko ifnot: showGroupItems --> <!-- ko template: { name: 'drillDownToSelectedGroup', foreach: formItems } --> <!-- /ko --> <!-- /ko --> </script> <script id="drillDownToSelectedGroup" type="text/html"> <!-- ko if: isGroup --> <!-- ko if: def.group.headingLevel == 1 --> <!-- ko template: { name: renderTemplate } --> <!-- /ko --> <!-- /ko --> <!-- /ko --> </script> <script id="group" type="text/html"> <!--<p>Group</p>--> <span data-bind="text: text, click: $root.selectSection"></span> <br /> <!-- ko template: { name: renderGroup, foreach: formItems } --> <!-- /ko --> </script> <script id="empty" type="text/html"> </script> <script id="field" type="text/html"> <!--<p>Paragraph</p>--> <ul> <li><span data-bind="text: text"></span></li> </ul> </script> <div data-bind="template: { name: 'formDef', data: $data }"></div>

脚本

function SortByOrdinal(a, b) { return ((a.ordinal < b.ordinal) ? -1 : ((a.ordinal > b.ordinal) ? 1 : 0)); } var FormGroup = function (formItem) { var self = this; self.def = formItem; self.isGroup = true; self.text = formItem.text; // title self.ordinal = formItem.ordinal; self.showGroupItems = ko.observable(false); var formItems = []; $(formItem.group.formItems).each(function (indx, fi) { if (fi.group != null) formItems[formItems.length] = new FormGroup(fi); else formItems[formItems.length] = new FormField(fi); }); formItems.sort(SortByOrdinal); self.formItems = ko.observableArray(formItems); self.renderTemplate = function (item) { if (item.isGroup) return 'formElementNodeTemplate'; else return 'field'; }; self.renderGroup = function (item) { if (item) { if (item.isGroup && item.def.group.headingLevel == 1) return "group"; else return "empty"; } }; // Cascade down changes self.showGroupItems.subscribe(function (newValue) { $(self.formItems()).each(function (indx, fi) { if (fi.isGroup) fi.showGroupItems(newValue); }) }); return self; } var FormField = function (formItem) { var self = this; self.def = formItem; self.isGroup = formItem.group != null; self.text = formItem.text; self.ordinal = formItem.ordinal; return self; } var FormDef = function (formDef) { var self = this; self.text = formDef.text; self.formDef = formDef; self.showGroupItems = true; var formItems = []; $(formDef.formItems).each(function (indx, di) { if (di.group != null) formItems[formItems.length] = new FormGroup(di); else formItems[formItems.length] = new FormField(di); }); self.formItems = ko.observableArray(formItems); self.renderTemplate = function () { return 'formElementNodeTemplate' }; self.renderGroup = function (item) { if (item.isGroup && item.def.group.headingLevel == 1) return "group"; else return "empty"; }; self.selectedSection = ko.observable(); self.selectSection = function (item) { if (self.selectedSection()) self.selectedSection().showGroupItems(false); item.showGroupItems(true); self.selectedSection(item); }; return self; } var def = { "formItems": [ { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'1'}" }, "group": null, "text": "This is field 1.1", "ordinal": 1 }, { "field": { "paraId": "{value:'2'}" }, "group": null, "text": "This is field 1.2", "ordinal": 2 }, { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'3'}" }, "group": null, "text": "This is field 1.1.1", "ordinal": 1 } ], "headingLevel": 1 }, "text": "Group 1.1", "ordinal": 3 } ], "headingLevel": 1 }, "text": "Group 1", "ordinal": 2 }, { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'2'}" }, "group": null, "text": "This is field 2.1", "ordinal": 1 }, { "field": { "paraId": "{value:'3'}" }, "group": null, "text": "This is field 2.2", "ordinal": 2 }, { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'4'}" }, "group": null, "text": "This is field 2.2.1", "ordinal": 1 } ], "headingLevel": 1 }, "text": "Group 2.1", "ordinal": 3 } ], "headingLevel": 1 }, "text": "Group 2", "ordinal": 3 } ], "id": 2, "text": "Project 1" }; var viewModel = new FormDef(def); ko.applyBindings(viewModel);

看看这个小提琴的最后作品。

如果您觉得这很有帮助,请不要忘记向上投票。

I was able to solve the problem by creating other templates.

Here's the code:

HTML

<script id="formDef" type="text/html"> <!--<p>FormDef</p>--> <div style="float: left; width: 300px;"> <!--<p>formDef</p>--> <!-- ko template: { name: renderGroup, foreach: formItems } --> <!-- /ko --> </div> <div style="float: left;"> <!-- ko template: { name: 'formElementNodeTemplate', foreach: formItems } --> <!-- /ko --> </div> </script> <script id="formElementNodeTemplate" type="text/html"> <!-- ko if: showGroupItems --> <ul id="expList"> <li> <span data-bind="text: text"></span> <span data-bind="text: showGroupItems"></span> <br /> <ul> <!-- ko template: { name: renderTemplate, foreach: formItems } --> <!-- /ko --> </ul> </li> </ul> <!-- /ko --> <!-- ko ifnot: showGroupItems --> <!-- ko template: { name: 'drillDownToSelectedGroup', foreach: formItems } --> <!-- /ko --> <!-- /ko --> </script> <script id="drillDownToSelectedGroup" type="text/html"> <!-- ko if: isGroup --> <!-- ko if: def.group.headingLevel == 1 --> <!-- ko template: { name: renderTemplate } --> <!-- /ko --> <!-- /ko --> <!-- /ko --> </script> <script id="group" type="text/html"> <!--<p>Group</p>--> <span data-bind="text: text, click: $root.selectSection"></span> <br /> <!-- ko template: { name: renderGroup, foreach: formItems } --> <!-- /ko --> </script> <script id="empty" type="text/html"> </script> <script id="field" type="text/html"> <!--<p>Paragraph</p>--> <ul> <li><span data-bind="text: text"></span></li> </ul> </script> <div data-bind="template: { name: 'formDef', data: $data }"></div>

Script

function SortByOrdinal(a, b) { return ((a.ordinal < b.ordinal) ? -1 : ((a.ordinal > b.ordinal) ? 1 : 0)); } var FormGroup = function (formItem) { var self = this; self.def = formItem; self.isGroup = true; self.text = formItem.text; // title self.ordinal = formItem.ordinal; self.showGroupItems = ko.observable(false); var formItems = []; $(formItem.group.formItems).each(function (indx, fi) { if (fi.group != null) formItems[formItems.length] = new FormGroup(fi); else formItems[formItems.length] = new FormField(fi); }); formItems.sort(SortByOrdinal); self.formItems = ko.observableArray(formItems); self.renderTemplate = function (item) { if (item.isGroup) return 'formElementNodeTemplate'; else return 'field'; }; self.renderGroup = function (item) { if (item) { if (item.isGroup && item.def.group.headingLevel == 1) return "group"; else return "empty"; } }; // Cascade down changes self.showGroupItems.subscribe(function (newValue) { $(self.formItems()).each(function (indx, fi) { if (fi.isGroup) fi.showGroupItems(newValue); }) }); return self; } var FormField = function (formItem) { var self = this; self.def = formItem; self.isGroup = formItem.group != null; self.text = formItem.text; self.ordinal = formItem.ordinal; return self; } var FormDef = function (formDef) { var self = this; self.text = formDef.text; self.formDef = formDef; self.showGroupItems = true; var formItems = []; $(formDef.formItems).each(function (indx, di) { if (di.group != null) formItems[formItems.length] = new FormGroup(di); else formItems[formItems.length] = new FormField(di); }); self.formItems = ko.observableArray(formItems); self.renderTemplate = function () { return 'formElementNodeTemplate' }; self.renderGroup = function (item) { if (item.isGroup && item.def.group.headingLevel == 1) return "group"; else return "empty"; }; self.selectedSection = ko.observable(); self.selectSection = function (item) { if (self.selectedSection()) self.selectedSection().showGroupItems(false); item.showGroupItems(true); self.selectedSection(item); }; return self; } var def = { "formItems": [ { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'1'}" }, "group": null, "text": "This is field 1.1", "ordinal": 1 }, { "field": { "paraId": "{value:'2'}" }, "group": null, "text": "This is field 1.2", "ordinal": 2 }, { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'3'}" }, "group": null, "text": "This is field 1.1.1", "ordinal": 1 } ], "headingLevel": 1 }, "text": "Group 1.1", "ordinal": 3 } ], "headingLevel": 1 }, "text": "Group 1", "ordinal": 2 }, { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'2'}" }, "group": null, "text": "This is field 2.1", "ordinal": 1 }, { "field": { "paraId": "{value:'3'}" }, "group": null, "text": "This is field 2.2", "ordinal": 2 }, { "field": null, "group": { "formItems": [ { "field": { "paraId": "{value:'4'}" }, "group": null, "text": "This is field 2.2.1", "ordinal": 1 } ], "headingLevel": 1 }, "text": "Group 2.1", "ordinal": 3 } ], "headingLevel": 1 }, "text": "Group 2", "ordinal": 3 } ], "id": 2, "text": "Project 1" }; var viewModel = new FormDef(def); ko.applyBindings(viewModel);

See final work in this fiddle.

If you find this helpful please don't forget to up-vote.

更多推荐

本文发布于:2023-07-04 11:09:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1023609.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:递归   如何使用   模板   js   Knockout

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!