Knockout.js KnockoutJS添加动态列
尝试在运行时添加多行教师和多列助手,到目前为止,我的核心设计基于Ryan Neimeyer的示例代码,我已经将其改编为JSFIDLE-。我最近的更新尝试是通过创建一个新的助手实例来添加列,但所有复选框都绑定到同一个元素,因此每次我选中一个复选框时,都会在列中选中所有复选框。下面是我尝试添加助手的新尝试:Knockout.js KnockoutJS添加动态列,knockout.js,Knockout.js,尝试在运行时添加多行教师和多列助手,到目前为止,我的核心设计基于Ryan Neimeyer的示例代码,我已经将其改编为JSFIDLE-。我最近的更新尝试是通过创建一个新的助手实例来添加列,但所有复选框都绑定到同一个元素,因此每次我选中一个复选框时,都会在列中选中所有复选框。下面是我尝试添加助手的新尝试: // new way - reuses same instance of Assistant for all rows addAsst: function() { this.asstCo
// new way - reuses same instance of Assistant for all rows
addAsst: function() {
this.asstColumns.push(new Assistant(this.selectedAsst(), $('#assistants option:selected').text(), false, "0%", this.newFTE(), this.newType()));
this.removeAsst(this.selectedAsst()); // remove the assistant from dropdown
this.selectedAsst("0"); // reset the dropdown to "Select One..."
}
显然,我需要能够在每个教师行中添加一个新的/独特的助手实例,但我认为这破坏了我的设计。如果有帮助的话,我不会有超过7个助手,而且总是至少有一个。我在想另一个策略可能是构建7个助手列,甚至可能使那些没有添加助手的列不可见,但我也在努力更新现有的可观察数组。这是我尝试添加助手的老方法,我只是从助手下拉列表中添加了文本,该文本与更新版本中的new Assistant()实例没有链接。但是,两者都不能像它们应该的那样工作,因为它们需要绑定到一个当用户单击它们时更新的可观察对象
// old way - creates new asst, but doesn't use it and doesn't bind anything
addAsst: function() {
var asst = new Assistant(this.selectedAsst(), $('#assistants option:selected').text(), this.newFTE(), this.newType());
this.columns.push({property: $('#assistants option:selected').text(),
display: $('#assistants option:selected').text(), readonly: false });
this.removeAsst(this.selectedAsst()); // remove the assistant from dropdown
this.selectedAsst("0"); // reset the dropdown to "Select One..."
}
蒂娅,史蒂夫
<comedian>
我想帮忙。你能把你的需求分解成小块,然后把它们加起来吗?更新问题,询问如何添加助手。
</comedian>
<table>
<tr style="color:white; background-color:grey">
<td></td>
<!-- ko foreach: columns -->
<td colspan="2" data-bind="text: $data"></td>
<!-- /ko -->
</tr>
<tbody data-bind="foreach: teachers">
<tr>
<td data-bind="text: name"></td>
<!-- ko foreach: asstCols -->
<td class="cellLeft"><input data-bind="checked: isChecked, click: $root.updatePercentage" type="checkbox" /></td>
<td class="cellRight" data-bind="text: accounting.toFixed(percentage(), 0) + '%'"></td>
<!-- /ko -->
</tr>
</tbody>
</table>
<br />
<table class="reset">
<tr>
<td>Teacher:</td>
<td style="padding-left:5px;">
<select data-bind="
options: availableTeachers,
optionsText: 'name',
value: selectedTeacher">
</select>
</td>
<td style="padding-left:5px;"><button data-bind="click: addTeacher">Add Teacher</button></td>
<td style="padding-left:5px;"><button data-bind="click: addAsst">Add Assistant</button></td>
</tr>
</table>
<ul data-bind="foreach: teachers">
<li>
<span data-bind="text: name"></span>
<ul data-bind="foreach: asstCols">
<li>
<span data-bind="text: asstName"></span> : <span data-bind="text: percentage"></span>
</li>
</ul>
</li>
</ul>
<!-- <textarea style="width:620px; height:300px;" data-bind="text: ko.toJSON($data)"></textarea> -->
// methods
var Teacher = function (id, name, asstCols) {
this.id = id;
this.name = name;
this.asstCols = ko.observableArray(asstCols).extend({ rateLimit: 0 }); // trigger just one re-evaluation of computed observable
};
var AsstCol = function (id, asstName, isChecked, percentage) {
this.id = id;
this.asstName = ko.observable(asstName);
this.isChecked = ko.observable(isChecked);
this.percentage = ko.observable(percentage);
};
var Assistant = function (id, name) {
this.id = id;
this.name = name;
};
var viewModel = function (teachers, assistants, columnList) {
var self = this;
self.teachers = ko.observableArray(teachers).extend({ rateLimit: 0 });
self.columns = ko.observableArray();
// set initial columns
for (var index in columnList) {
self.columns.push(columnList[index].asstName());
};
self.assistants = ko.observableArray(assistants).extend({ rateLimit: 0 });
self.selectedTeacher = ko.observable("0");
self.availableTeachers = ko.observableArray([
new Teacher(5, "Doug", [{}]),
new Teacher(6, "Kevin", [{}])
]);
// methods
// passes current item as the first parameter
self.updatePercentage = function (asstCol) {
var totalChecked = 0, percentage = 0;
ko.utils.arrayForEach(self.teachers(), function (teacher) {
for (var i = 0; i < self.columns().length; i++) {
if (teacher.asstCols()[i].id == asstCol.id) {
if (teacher.asstCols()[i].isChecked()) {
totalChecked++;
break;
}
}
}
});
percentage = 100 / totalChecked;
ko.utils.arrayForEach(self.teachers(), function (teacher) {
for (var i = 0; i < self.columns().length; i++) {
if (teacher.asstCols()[i].id == asstCol.id) {
if (teacher.asstCols()[i].isChecked())
teacher.asstCols()[i].percentage(percentage);
else
teacher.asstCols()[i].percentage(0);
}
}
});
return true; // return default browser behavior to allow check/uncheck
};
// operations
self.addTeacher = function () {
self.teachers.push(new Teacher(ko.unwrap(self.selectedTeacher().id), ko.unwrap(self.selectedTeacher().name), undefined));
// add each of the asst columns
ko.utils.arrayForEach(self.assistants(), function (assistant) {
self.teachers()[self.teachers().length - 1].asstCols.push(new AsstCol(assistant.id, assistant.name, false, 0));
});
self.teachers.sort(function(a, b) {
return a.name.toLowerCase() == b.name.toLowerCase() ? 0 : (a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1);
});
self.columns.sort();
ko.utils.arrayForEach(self.teachers(), function (teacher) {
teacher.asstCols.sort(function(a, b) {
return a.asstName().toLowerCase() == b.asstName().toLowerCase() ? 0 :
(a.asstName().toLowerCase() < b.asstName().toLowerCase() ? -1 : 1);
});
});
// remove teacher from dropdown and reset the selection
self.availableTeachers.remove(function (item) { return item.id == ko.unwrap(self.selectedTeacher().id); });
self.selectedTeacher("0");
};
self.addAsst = function () {
self.assistants.push(new Assistant(22, "Abby"));
self.assistants.sort(function(a, b) {
return a.name.toLowerCase() == b.name.toLowerCase() ? 0 : (a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1);
});
ko.utils.arrayForEach(self.teachers(), function (teacher) {
teacher.asstCols.push(new AsstCol(22, "Abby", false, 0));
});
self.columns.push("Abby");
};
};
var initialTeachers = [
new Teacher(1, "Jeff", [
new AsstCol(20, "Susie", true, 50),
new AsstCol(21, "Bobby", true, 33)
]),
new Teacher(2, "Joe", [
new AsstCol(20, "Susie", false, 0),
new AsstCol(21, "Bobby", true, 33)
]),
new Teacher(3, "Josie", [
new AsstCol(20, "Susie", true, 50),
new AsstCol(21, "Bobby", true, 33)
])
];
var initialAssistants = [
new Assistant(21, "Bobby"),
new Assistant(20, "Susie")
];
var vm = new viewModel(initialTeachers, initialAssistants, initialTeachers[0].asstCols());
ko.applyBindings(vm);
table {
border-spacing: 0px;
border-collapse: collapse;
}
td, th {
border: solid 1px black;
padding: 2px;
}
.reset td, th {
border: 0;
padding: 0;
}
.cellLeft {
border: 0;
border-left:solid 1px black;
border-bottom:solid 1px black;
padding:1px 1px 1px 4px;
}
.cellRight {
border: 0;
border-right:solid 1px black;
border-bottom:solid 1px black;
padding:1px; padding:1px 4px 1px 1px;
}