Javascript n级深复选框树行为
我使用knockout实现了一个n级复选框树,其中父级复选框的选择应该选择它的子级(但不是相反),一旦提交了数据,所选元素的ID应该转换为JSON发送到服务器 我不知道如何处理单向复选框关系,也不知道如何以这样的方式过滤我的最终json:Javascript n级深复选框树行为,javascript,knockout.js,Javascript,Knockout.js,我使用knockout实现了一个n级复选框树,其中父级复选框的选择应该选择它的子级(但不是相反),一旦提交了数据,所选元素的ID应该转换为JSON发送到服务器 我不知道如何处理单向复选框关系,也不知道如何以这样的方式过滤我的最终json: 如果选择了一个父对象(这意味着它的所有子对象也被选择),则不在json中发送其子ID 仅选择一个或几个子项时如何不发送父项id 列表项的模型为: marketingListsItem = function (data, parent) { va
marketingListsItem = function (data, parent) {
var self = this;
self.Name = ko.observable(data.Name);
self.Selected = ko.observable(data.Selected);
self.Parent = ko.observable(parent);
self.Children = ko.observableArray([]);
self.Id = ko.observable(data.Id);
self.DateAdded = ko.observable(new Date(data.DateAdded));
self.DateModified = ko.observable(data.DateModified);
if (data.Children) {
ko.utils.arrayForEach(data.Children, function (child) {
self.Children.push(new marketingListsItem(child, this));
}.bind(this));
};
}
以下是“视图模型”部分:
marketingListsViewModel = {
marketingLists: mapping.fromJS([]),
originatorConnectionName: ko.observable(''),
selectedMarketingListIds: ko.observableArray([])
},
init = function (connectionId, connectionName) {
marketingListsViewModel.originatorConnectionName(connectionName);
marketingListsViewModel.getFieldMapping = function () {
require(['mods/fieldmapping'], function (fieldmapping) {
fieldmapping.init(connectionId, connectionName);
});
};
// Here I only managed to filter the parent level selections
marketingListsViewModel.selectedLists = ko.computed(function () {
return ko.utils.arrayFilter(marketingListsViewModel.marketingLists(), function (item) {
return item.Selected() == true;
});
});
marketingListsViewModel.saveMarketingListChanges = function () {
// Which I can filter my JSON to include them but the children are missing
var latestMarketingListChanges = ko.toJSON(marketingListsViewModel.selectedLists, ["Id"]);
console.log(latestMarketingListChanges);
amplify.request("updateExistingMarketingLists", { cid: connectionId, ResponseEntity: { "id": connectionId, "selectedMarketListIds": latestMarketingListChanges } },
function (data) {
console.log(data);
});
}
amplify.request("getExistingMarketingLists", { cid: connectionId }, function (data) {
showMarketingLists();
mapping.fromJS(data.ResponseEntity, dataMappingOptions, marketingListsViewModel.marketingLists);
ko.applyBindings(marketingListsViewModel, $('#marketingLists')[0]);
});
};
最后一个观点是:
<div id="marketingListsContainer">
<ul data-bind="template: {name: 'itemTmpl' , foreach: marketingLists}"></ul>
<script id="itemTmpl" type="text/html">
<li>
<label><input type="checkbox" data-bind="checked: Selected" /><span data-bind='text: Name'></span></label>
<ul data-bind="template: { name: 'itemTmpl', foreach: Children }" class="childList"></ul>
</script>
</div>
<a class="s_button modalClose right" href="#"><span data-bind="click: saveMarketingListChanges">Save and close</span></a><br>
您可以向所选绑定添加订阅事件,并执行类似操作,在检查父项时将所有子项标记为选中
self.Selected.subscribe( function ( newValue ) {
if ( newValue === true ) {
for ( i=0; i<self.Children().length; i++) {
self.Children()[i].Selected(true);
}
}
else {
if ( self.Parent() != null ) {
self.Parent().Selected(false);
}
}
} ) ;
self.Selected.subscribe(函数(newValue)){
如果(newValue==true){
对于(i=0;i感谢您的回答。问题是,现在使用您的解决方案时,如果一个父级已通过服务器的数据进行了检查,则其子级的检查值不会发生变化
我已将以下内容添加到模型中以解决此问题:
self.sync = ko.computed(function () {
return self.Selected.valueHasMutated();
});
对于稍后将找到此帖子并希望了解最终结果的人:
define('mods/marketinglists', ["knockout", "libs/knockout.mapping", "libs/knockout.validation", "datacontext", "mods/campaigner", "text!templates/marketinglists.html", "text!styles/marketinglists.css"],
function (ko, mapping, validation, datacontext, campaigner, html, css) {
'use strict';
var
marketingListsItem = function (data, parent) {
var self = this;
self.Name = ko.observable(data.Name);
self.Selected = ko.observable(data.Selected);
self.Parent = ko.observable(parent);
self.Children = ko.observableArray([]);
self.Id = ko.observable(data.Id);
self.DateAdded = ko.observable(new Date(data.DateAdded));
self.DateModified = ko.observable(data.DateModified);
// If node contains children define each one as a marketingListItem in itself
// and bind it to the the model
if (data.Children) {
ko.utils.arrayForEach(data.Children, function (child) {
self.Children.push(new marketingListsItem(child, this));
}.bind(this));
};
// Watch for value changes in parent and check children
// if the parent was checked
self.Selected.subscribe(function (newValue) {
if (newValue === true) {
for (var i = 0; i < self.Children().length; i++) {
self.Children()[i].Selected(true);
}
}
else {
if (self.Parent() != null) { self.Parent().Selected(false); }
}
});
// Make sure subscribers have been notified when needed
self.sync = ko.computed(function () {
return self.Selected.valueHasMutated();
});
},
dataMappingOptions = {
key: function (data) {
return data.Id;
},
create: function (options) {
return new marketingListsItem(options.data, null);
}
},
showMarketingLists = function () {
campaigner.addStylesToHead(css);
campaigner.addModalWindow(html, {
windowSource: "inline",
width: 700,
height: '340'
});
},
marketingListsViewModel = {},
init = function (connectionId, connectionName) {
// Define marketingLists as an observable array from JS object
marketingListsViewModel.marketingLists = mapping.fromJS([]);
marketingListsViewModel.originatorConnectionName = ko.observable('');
// Set the name for the marketing list
marketingListsViewModel.originatorConnectionName(connectionName);
marketingListsViewModel.getFieldMapping = function () {
require(['mods/fieldmapping'], function (fieldmapping) {
fieldmapping.init(connectionId, connectionName);
});
};
marketingListsViewModel.selectedLists = ko.computed(function () {
var selectedItems = [];
ko.utils.arrayFilter(
marketingListsViewModel.marketingLists(),
function (item) {
// If a parent a selected its being collected
if (item.Selected() == true) selectedItems.push(item);
else {
// If a child is slected it is collected
ko.utils.arrayForEach(item.Children(), function (child) {
if (child.Selected()) selectedItems.push(child);
else {
ko.utils.arrayForEach(child.Children(),
// Finally if children's child is selected its collected
function (childChildren) {
if (childChildren.Selected())
selectedItems.push(childChildren);
});
}
})
}
});
return selectedItems;
});
marketingListsViewModel.saveMarketingListChanges = function () {
// Pick only the selected elements and parse only the Id
var latestMarketingListChanges = ko.toJSON
(marketingListsViewModel.selectedLists,
["Id"]);
console.log(latestMarketingListChanges);
// Send the latest marketing lists changes Ids to the server
amplify.request("updateExistingMarketingLists",
{
cid: connectionId,
ResponseEntity:
{
"id": connectionId,
"selectedMarketListIds": latestMarketingListChanges
}
},
function (data) {
console.log(data);
});
}
amplify.request("getExistingMarketingLists", { cid: connectionId },
function (data) {
showMarketingLists();
mapping.fromJS(
data.ResponseEntity,
dataMappingOptions,
marketingListsViewModel.marketingLists);
ko.applyBindings(marketingListsViewModel, $('#marketingLists')[0]);
});
};
return {
init: init,
marketingListsViewModel: marketingListsViewModel,
html: html,
css: css
}
});
<div id="marketingListsContainer">
<ul data-bind="template: {name: 'itemTmpl' , foreach: marketingLists}"></ul>
<script id="itemTmpl" type="text/html">
<li>
<!-- ko if: $data.Parent -->
(my parent is: <span data-bind="text: $data.Parent().Name"></span>)
<!-- /ko -->
<label><input type="checkbox" data-bind="checked: Selected" /><span data-bind='text: Name'></span></label>
<ul data-bind="template: { name: 'itemTmpl', foreach: Children }" class="childList"></ul>
</script>
</div>
<a class="s_button modalClose right" href="#"><span data-bind="click: saveMarketingListChanges">Save and close</span></a><br>
define('mods/marketinglists',[“knockout”,“libs/knockout.mapping”,“libs/knockout.validation”,“datacontext”,“mods/activater”,“text!templates/marketinglists.html”,“text!style/marketinglists.css”],
功能(ko、映射、验证、datacontext、活动家、html、css){
"严格使用",;
变量
marketingListsItem=功能(数据,父项){
var self=这个;
self.Name=ko.observable(data.Name);
self.Selected=可观察的ko(数据选择);
自我父母=可观察(父母);
自我儿童=ko.observearray([]);
self.Id=ko.observable(data.Id);
self.DateAdded=ko.observable(新日期(data.DateAdded));
self.DateModified=ko.可观察(data.DateModified);
//如果节点包含子节点,则将每个子节点本身定义为marketingListItem
//并将其绑定到模型
if(数据子项){
ko.utils.arrayForEach(data.Children,function(child)){
self.Children.push(new marketingListsItem(child,this));
}.约束(这个);
};
//注意父项中的值更改并检查子项
//如果选中了父项
self.Selected.subscribe(函数(newValue)){
如果(newValue==true){
for(var i=0;i<div id="marketingListsContainer">
<ul data-bind="template: {name: 'itemTmpl' , foreach: marketingLists}"></ul>
<script id="itemTmpl" type="text/html">
<li>
<!-- ko if: $data.Parent -->
(my parent is: <span data-bind="text: $data.Parent().Name"></span>)
<!-- /ko -->
<label><input type="checkbox" data-bind="checked: Selected" /><span data-bind='text: Name'></span></label>
<ul data-bind="template: { name: 'itemTmpl', foreach: Children }" class="childList"></ul>
</script>
</div>
<a class="s_button modalClose right" href="#"><span data-bind="click: saveMarketingListChanges">Save and close</span></a><br>