Knockout.js 排序后KnockoutJS UI未使用丰富的可观察数组更新
当我添加新教师时,它会对教师和包含的助手进行排序,但UI不会刷新。查看textarea控件,该控件显示添加新教师后,教师可观察数组会对其中的asstcol进行排序,但UI不会刷新。我尝试在self.teachers()可观察数组和包含的asstCols()上添加valueHasMutated(),但没有成功。我不知道我所做的是否过于复杂,但更大的应用程序也能够添加新的列/助手,并且需要能够在添加时按字母顺序对它们进行排序。因此,我故意以错误的顺序添加了助手列,以演示UI列刷新的问题。有趣的是,当您将Doug添加为教师时,它确实会将他添加到教师可观察数组的顶部,UI将他置于顶部,因此这是可行的,但是列需要注意。如果单击Doug第二列中的复选框,可以看到它正确地更新了百分比,但没有更新原始教师的百分比,因为UI不同步 视图: 两个问题:Knockout.js 排序后KnockoutJS UI未使用丰富的可观察数组更新,knockout.js,Knockout.js,当我添加新教师时,它会对教师和包含的助手进行排序,但UI不会刷新。查看textarea控件,该控件显示添加新教师后,教师可观察数组会对其中的asstcol进行排序,但UI不会刷新。我尝试在self.teachers()可观察数组和包含的asstCols()上添加valueHasMutated(),但没有成功。我不知道我所做的是否过于复杂,但更大的应用程序也能够添加新的列/助手,并且需要能够在添加时按字母顺序对它们进行排序。因此,我故意以错误的顺序添加了助手列,以演示UI列刷新的问题。有趣的是,当
:在执行排序之前读取可观察对象teacher.asstCols()
- 您的数据不匹配。您在
属性值上输入了一个错误id
var initialAssistants = [ new Assistant(20, "Bobby"), new Assistant(21, "Susie") ]; new Teacher(1, "Jeff", [ new AsstCol(20, "Susie", true, 50), new AsstCol(21, "Bobby", true, 33) ])
看起来你提供的小提琴不能正常工作。下拉列表中没有教师,Bobby也没有复选标记。我看到
可用的教师
,UI似乎正在正确更新。我认为在FF、IE和Chrome(最新版本)中,所有教师对给定助手的%更新都没有问题。您是否在旧版/特定浏览器上看到同步问题?啊,我现在看到了。我有一个Chrome插件阻止了一些脚本。明白了。。。为了便于查看,我只将相关数据放在另一个文件中。我在过去的jQuery sortable中也遇到过类似的问题。我在很久以前就发现了可观察的问题,但它仍然不太正确。我花了几分钟才注意到id
不匹配。你的评论和我的回答几乎同时发布。但是,由于您强制刷新,值发生了变化。从assitCols
中删除()
,您可以删除强制更新。太棒了!为了确认,将teacher.asstCols().sort(函数(a,b){更改为teacher.asstCols.sort(函数(a,b){是排序的问题。我没有意识到teacher.asstCols()第二,在InitialAssistants中,我为Bobby使用的ID为20,但在InitialTeachers中,我使用的ID为21。再次感谢!根据Origineil的答案更新了JSFIDLE at。
// 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");
};
};
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(20, "Bobby"),
new Assistant(21, "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;
}
var initialAssistants = [
new Assistant(20, "Bobby"),
new Assistant(21, "Susie")
];
new Teacher(1, "Jeff", [
new AsstCol(20, "Susie", true, 50),
new AsstCol(21, "Bobby", true, 33)
])