我的问题很可能是简单的 Knockout 问题,但我是一个完全的初学者。我被扔到这页其他人已经处理但从未完成的代码。
当此页面首次加载时,将检索数据并正确加载主网格。当我尝试自动选择结果中的第一条记录以便在网格下方填写详细列表时,问题就出现了。
发生这种情况时,我会收到以下消息。
未捕获的类型错误:无法处理绑定(bind)“text: function (){return selected.RequestLog.Timestamp }”,消息:无法读取未定义的属性“Timestamp”
这是我正在使用的代码片段。返回的数据来自 Entity Framework 。
var siteLogModel = function () {
var self = this;
self.errorList = ko.observableArray([]);
self.selected = ko.observable();
self.updateErrorList = function (page) {
jQuery.ajax({
type: "POST",
url: "/Admin/ErrorPage",
data: { pageNum: page },
success: function (result) {
self.errorList(result);
self.selected(result[0]);
// Since we have success, add the click handler so we can get the details about a row by id.
//addRowHandlers();
},
error: function (result) {
jQuery("#status").text = result;
}
});
};
};
这是在加载数据后尝试发生的实际绑定(bind)。 RequestLog 在绑定(bind)时似乎不存在,即使如果我在上述函数中的 self.selected(result[0]) 行上设置断点,它确实似乎没问题。
我认为这是一个范围问题,但我想不出如何最好地解决它。任何帮助将不胜感激。
<div class="param">
<span>Time</span>
<label data-bind="text: selected.RequestLog.Timestamp"></label>
</div>
更新:这是文档就绪部分。
jQuery(document).ready(function () {
var vm = new siteLogModel();
vm.updateErrorList(0);
ko.applyBindings(vm);
});
最佳答案
在 ko 评估绑定(bind)表达式时,您的 selected
observable 没有 .RequestLog
属性。该错误来自 javascript,而不是 ko(尽管 ko 将异常包装在您看到的错误消息中)。运行时,selected.RequestLog === undefined
为真,你不能在 undefined 上调用任何东西。这就像空引用异常。
如果您在 ajax 调用完成之前调用 applyBindings
是有意义的。
解决这个问题的一种方法是通过计算代替:
<div class="param">
<span>Time</span>
<label data-bind="text: selectedRequestLogTimestamp"></label>
</div>
self.selectedRequestLogTimestamp = ko.computed(function() {
var selected = self.selected();
return selected && selected.RequestLog
? selected.RequestLog.TimeStamp
: 'Still waiting on data...';
});
有了上面的内容,就不会在 undefined variable 上调用任何东西。在 ajax 调用完成之前,您的标签将显示“仍在等待数据”,然后一旦您调用 self.selected(result[0])
,它就会填充时间戳。
另一种解决方法是保持绑定(bind)不变,但给选定的可观察对象一个初始值。您可以保留所有 html 原样,仅此而已:
self.selected = ko.observable({
RequestLog: {
TimeStamp: 'Still waiting on data'
}
});
...你最终会得到相同的结果。
为什么?
任何时候您通过执行诸如 self.prop = ko.observable()
之类的操作来初始化 observable 时,observable 的实际值都是 undefined
。试试看:
self.prop1 = ko.observable();
var prop1Value = self.prop1();
if (typeof prop1Value === 'undefined') alert('It is undefined');
else alert('this alert will not pop up unless you initialize the observable');
总结一下正在发生的事情:
- 您在 View 模型中使用等于 undefined 的值初始化您选择的可观察对象。
- 您针对 View 模型调用 ko.applyBindings。
- ko 解析数据绑定(bind)属性,并尝试绑定(bind)。
- ko 获取
text: selected.RequestLog.Timestamp
绑定(bind)。 - ko 调用 selected(),它返回 undefined。
- ko 尝试调用未定义的 .RequestLog。
- ko 抛出错误,因为 undefined 没有 .RequestLog 属性。
所有这些都发生在您的 ajax 调用返回之前。
回复评论#1
是的,您可以在 ajax 成功事件后调用 applyBindings。然而,这通常不是您应该做的。如果您愿意,这里有一个如何完成的示例:
self.updateErrorList = function (page) {
self.updateErrorPromise = jQuery.ajax({
type: "POST",
url: "/Admin/ErrorPage",
data: { pageNum: page },
success: function (result) {
self.errorList(result);
self.selected(result[0]);
},
error: function (result) {
jQuery("#status").text = result;
}
});
};
jQuery(document).ready(function () {
var vm = new siteLogModel();
vm.updateErrorList(0);
vm.updateErrorPromise.done(function() {
ko.applyBindings(vm);
});
});
另一种方法是继续进行急切绑定(bind)(在 ajax 调用完成之前应用绑定(bind)),但将标记包装在 if 绑定(bind)中,如下所示:
<div class="param" data-bind="if: selected">
<span>Time</span>
<label data-bind="text: selected.RequestLog.Timestamp"></label>
</div>
关于javascript - KnockoutJS 绑定(bind)问题 - 无法读取属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21291251/