我是Knockout的新手,我无法理解如何编辑"使用Knockout映射插件时的视图模型。希望有人可以帮助我。我有一个列表清单。下面是一个类似的例子。基本上是多个组有多个文件。
[
{
"group": "Alice",
"files": [
{"filename": "red.mp3", "length": 5},
{"filename": "blue.mp3","length": 6},
{"filename": "yellow.mp3","length": 5}
]
},
{
"group": "Bob",
"files": [
{"filename": "green.mp3","length": 2},
{"filename": "purple.mp3","length": 10}
]
}
]
我可以从中获得基本模型:
$.getJSON('api/get-list', function(data)
{
view = ko.mapping.fromJS(data);
ko.applyBindings(view);
});
它有效,而且我设法将其绑定在HTML中,因此它可见并且在该区域一切都很好。但是,我需要添加一些东西,而且我不确定如何做到这一点。更重要的是,如何干净利落地完成它。
我输出带有复选框的文件,我想要一个'选择'属于它的财产。我已经能够通过在后端添加字段来实现这一目标,但并不想要它,因为它真的不应该存在。还需要显示当前选择的数量,每组数量和总数。
所以,基本上我想要这样的东西:
{
"formSubmit": ?,
"totalNumberOfFiles": ?,
"totalNumberOfSelectedFiles": ?,
"groups":
[
{
"group": "Alice",
"numberOfFiles": ?,
"selectedFiles": ?,
"files": [
{
"filename": "red.mp3",
"length": 5,
"selected": boolean
},
...
]
},
...
]
}
numberOfFiles
?可以从files.length
或其他东西获得吗?selectedFiles
应该是一个函数/可观察函数来计算所选文件的数量(看起来如何?)或者它应该是一个以某种方式添加/删除的列表(以及如何做吗?)基本上,我知道(可以弄清楚)当模型正在运行时如何进行绑定,但是在使用映射插件时并不理解如何以良好的方式构建它(并且我真的不想手动完成。)
希望有人可以帮助我,因为我无法解决这个问题
答案 0 :(得分:3)
使用ko.mapping.fromJS时,每个属性都转换为一个observable,每个数组都转换为observableArray。
主视图模型 MyViewModel 具有一个FileGroups列表,该列表使用自定义映射对象的映射进行初始化。该对象有一个'create'回调(如http://knockoutjs.com/documentation/plugins-mapping.html中所述),用于实例化一个新的FileGroup。
在 FileGroup 构造函数中,在创建新的子视图模型之前,添加了一个属性“selected”,其中 false 是其默认值。
此外,主视图模型有两个计算的可观察量:
在提交方法中,有一个简单的提醒,用于演示如何访问所选文件的数组。
// data obtained from the server
var data = [
{
"group": "Alice",
"files": [
{ "filename": "red.mp3", "length": 5 },
{ "filename": "blue.mp3", "length": 6 },
{ "filename": "yellow.mp3", "length": 5 }
]
},
{
"group": "Bob",
"files": [
{ "filename": "green.mp3", "length": 2 },
{ "filename": "purple.mp3", "length": 10 }
]
}
];
// sub view model representing a single file grouping
var FileGroup = function (data) {
data.files.map(f => f.selected = false);
ko.mapping.fromJS(data, {}, this);
}
// main view model
var MyViewModel = function (data) {
this.fileGroups = ko.mapping.fromJS(data, { create: options => new FileGroup(options.data) });
this.numberOfFiles = ko.computed(() => {
return this.fileGroups().reduce((total, fg) => {
total += fg.files().length;
return total;
}, 0);
}, this);
this.selectedFiles = ko.computed(function() {
return this.fileGroups().reduce((selectedFiles, fg) => {
selectedFiles.push.apply(selectedFiles, fg.files().filter(f => f.selected()));
return selectedFiles;
}, [])
}, this);
this.submit = function() {
alert("FILES POSTED TO SERVER: " + this.selectedFiles().length);
}
}
var viewModel = new MyViewModel(data);
ko.applyBindings(viewModel);
.fileGroup {
border: 1px solid lightgray;
margin-bottom: 15px;
padding: 10px;
}
.selected {
border: 1px solid lightgreen;
margin-bottom: 15px;
padding: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js" type="text/javascript"></script>
<div data-bind="foreach: fileGroups">
<h3 data-bind="text: group"></h3>
<div data-bind="foreach: files" class="fileGroup">
<input type="checkbox" data-bind="checked: selected">
<span data-bind="text: filename" />
</div>
</div>
<h4>Number of Files: <span data-bind="text: numberOfFiles"></span></h4>
<div data-bind="foreach: selectedFiles, visible: selectedFiles().length > 0" class=selected>
<span data-bind="text: filename" />
</div>
<button data-bind="click: submit">Submit</button>