嵌套视图模型结构导致 ko.computing 错误
Nested view model structure causing error in a ko.computed
我有一个javascript viewModel,它是用一个包含项目列表的"模型"数据集启动的。由于我想从我的页面在项目之间切换,因此我在订阅中收集所有其他数据。"选定项目"定义<select>
中的选定值。我第一次通过启动 selectedProject 到项目数组中的第一个元素来触发订阅。
不知何故,我收到错误消息
TypeError: batch is undefined
return item.parentID === batch.parentID;
^
我不明白为什么。
这是我的代码:
ViewModel = function (model) {
var self = this;
self.selectedProject = ko.observable();
self.selectedText = ko.observable();
self.Textbatches = ko.observableArray();
self.Projects = ko.observableArray(
ko.utils.arrayMap(model, function (item) {
return new Project(item);
}));
self.selectedProject.subscribe(function (project) {
/* ...some code... */
$.getJSON("myService/GetTextbatchesFromDB", "projectID=" + project.projectID,
function (allData) {
var mappedTextbatches = $.map(allData, function (item) {
return new Textbatch(item);
});
self.Textbatches(mappedTextbatches);
self.selectedText(self.Textbatches()[0]);
}
); // End of $.getJSON
/* ...some more code... */
}
self.selectedProject(self.Projects()[0]);
self.parentIDFilteredTextbatches = ko.computed(function () {
var batch = self.selectedText();
return ko.utils.arrayFilter(self.Textbatches(), function (item) {
return item.parentID === batch.parentID; /* ERROR ON THIS LINE */
});
});
}
在 HTML <中>:中>
<script>
// some code getting "model from the db...
var viewModel = new ViewModel(model);
ko.applyBindings(viewModel);
</script>
我发现,如果我在初始化self.selectedText()后将"self.parentIDFilteredTextbatches = ko.computed()"-functon移动到self.selectedProject.subscribe-function中,它将在首次加载页面时工作。
但是,我不喜欢这样的视图模型结构(也许我会习惯它),更糟糕的是,在选择新项目时我遇到了同样的错误(即触发了 selectedProject.subscription)。
您的问题与"mappedTextbatches"变量的范围有关。还可能存在轻微的语法错误。
视图模型的 Textbatches
属性无法访问mappedTextbatches
变量,因为后者的作用域。稍后,当您尝试访问 Textbatches[0]
的 parentID
属性(作为从 selectedText
属性设置的局部变量)时,会出现未定义的错误,因为从未实际设置Textbatches
。
有关进一步的解释和示例,请参阅此jsFiddle:http://jsfiddle.net/0p5fftcc/
/* Demonstrates a similar behavior to
* your current view model.
*/
var currentViewModel = function () {
var self = this;
self.personName = ko.observable('Bob');
self.personAge = ko.observable(10);
self.hasPersonNameChanged = ko.observable(false);
self.personName.subscribe(function (newValue) {
self.hasPersonNameChanged(true);
(function fakeGetJSON() {
/* The local age variable is within the
* function closure, so personAge cannot
* get access to it.
*/
var localAge = 20;
})();
self.personAge(localAge);
});
};
我无法对此进行测试以确保,但我猜如果您将代码更改为以下内容,您应该不会再收到错误。
var mappedTextbatches = $.getJSON("myService/GetTextbatchesFromDB", "projectID=" + project.projectID, function (allData) {
return $.map(allData, function (item) {
return new Textbatch(item);
});
});
编辑以反映帖子中的新代码
在评估之前,继续检查selectedText
是否有值。见下文。
self.parentIDFilteredTextbatches = ko.computed(function () {
if (self.selectedText() !== undefined) {
var batch = self.selectedText();
return ko.utils.arrayFilter(self.Textbatches(), function (item) {
return item.parentID === batch.parentID; /* ERROR ON THIS LINE */
});
}
return;
});
虽然我无法确定如何使用提供的信息,但我将假设self.selectedText
可以在客户端上进行交互。假设这一点,但在不知道更多的情况下,一个不太理想(尽管很快)修复您的问题的方法是在视图模型的顶部将Textbatches
属性声明更改为以下内容。这将减慢对计算函数的通知,该函数保存对Textbatches
和selectedText
的订阅,希望有足够的时间来设置selectedText
。
self.Textbatches = ko.observableArray().extend({ rateLimit: 500 });
这也将规避您以后会遇到的问题,即如果您刚刚实施undefined
检查,则在后续客户端更新中,新Textbatches
和旧selectedText
不匹配。
一个全面的解决方案可能涉及重新设计每个对象所包含的数据结构,但我无法从您的帖子中确切地判断每个属性应该代表什么。
"范围"问题是一个由两部分组成的问题,不是实际问题。
- 原始提供的示例缺少一些用于
$.getJSON
的闭合大括号。 $.map
闭合处的位置看起来像$.getJSON
的位置,并且在视觉上指示实际上不存在的范围界定问题。
问题是selectedText
不依赖于TextBatches
并且手动设置为undefined
,因为订阅尚未(同步性)填充TextBatches
。一旦订阅强制对计算selectedText
进行评估,它仍然具有undefined
,现在TextBatches
具有实际数据,然后导致执行arrayFilter
回调。
此示例中的控制台语句说明了代码中的事件序列。
另一个例子小提琴。
克里斯给出了正确的答案。更具体地说:
$.getJSON("myService/GetTextbatchesFromDB", "projectID=" + project.projectID,
function (allData) {
var mappedTextbatches = $.map(allData, function (item) {
return new Textbatch(item);
});
self.Textbatches(mappedTextbatches);
应该是这个
var mappedTextbatches;
$.getJSON("myService/GetTextbatchesFromDB", "projectID=" + project.projectID,
function (allData) {
mappedTextbatches = $.map(allData, function (item) {
return new Textbatch(item);
});
self.Textbatches(mappedTextbatches);
- jquery数据表的自定义ko绑定
- ko.com在foreach$data变量上添加了write函数
- 如何使双输入可写ko.computed
- 从对象内部调用knockout.js ko.applyBindings()
- 淘汰赛JS;绑定值未更新或 ko.computed() 未更新
- ko observablearray:推送和直接分配之间的区别
- KO 绑定复选框:从代码更改“选中”属性,不更改可观察字段
- 将 d3 演示中的圆圈和文本替换为包含自定义 HTML 和 ko 绑定的 foreignObject
- KNOCKOUT ko.observableArray 不会刷新视图
- 如何迭代ko.OberableArray
- 在ko.applyBindings(..)中执行Knockout js订阅函数(用于可观察对象)
- 防止拖动上的ko点击绑定
- 如何刷新'选项'ko多选组件中的绑定
- knockoutjs undo ko.mapping.fromJS
- KnockoutJS 通过 ko.utils.extend 继承功能
- 调用ko.applyBindings后,向Knockout视图模型添加新属性
- Knockout mapping用于ko.mapping.toJSON()的选项-方法
- 将 a ko.observable 更改为 ko.computed,反之亦然
- KO网格无法保存编辑单元格中的数据-使用Plunker
- 嵌套视图模型结构导致 ko.computing 错误