This page 提供了几种解决方案。相关部分是这个:
防止空对象
如果你有一个包含对象的 observable,并且你想绑定到该对象的属性,那么你需要小心它是否有可能是 null 或 undefined。你可以这样写你的绑定:
<span data-bind="text: selectedItem() ? selectedItem().name() : 'unknown'"></span>
有很多方法可以处理这个问题。首选方法是简单地使用模板绑定:
var viewModel = {
items: ko.observableArray(),
selectedItem: ko.observable()
};
<ul data-bind="template: { name: 'editorTmpl', data: selectedItem }"></ul>
<script id="editorTmpl" type="text/html">
<li>
<input data-bind="value: name" />
</li>
</script>
使用这个方法,如果selectedItem 为空,那么它就不会渲染任何东西。因此,您不会像在原始绑定中那样看到未知。但是,它确实具有简化绑定的额外好处,因为您现在可以直接指定属性名称,而不是 selectedItem().name。这是最简单的解决方案。
只是为了探索一些选项,这里有一些替代方案:
您可以像我们之前一样使用计算的 observable。
viewModel.selectedItemName = ko.computed(function() {
var selected = this.selected();
return selected ? selected.name() : 'unknown';
}, viewModel);
但是,这又给我们的视图模型增加了一些我们可能不想要的膨胀,我们可能不得不对许多属性重复此操作。
您可以使用自定义绑定,例如:
<div data-bind="safeText: { value: selectedItem, property: 'name', default: 'unknown' }"></div>
ko.bindingHandlers.safeText = {
update: function(element, valueAccessor, allBindingsAccessor) {
var options = ko.utils.unwrapObservable(valueAccessor()),
value = ko.utils.unwrapObservable(options.value),
property = ko.utils.unwrapObservable(options.property),
fallback = ko.utils.unwrapObservable(options.default) || "",
text;
text = value ? (options.property ? value[property] : value) : fallback;
ko.bindingHandlers.text.update(element, function() { return text; });
}
};
这比原版好吗?我会说可能不会。它确实避免了我们绑定中的 JavaScript,但它仍然非常冗长。
另一个选择是创建一个增强的 observable,它提供了一种访问属性的安全方法,同时仍然允许实际值为 null。可能看起来像:
ko.safeObservable = function(initialValue) {
var result = ko.observable(initialValue);
result.safe = ko.dependentObservable(function() {
return result() || {};
});
return result;
};
所以,这只是一个 observable,它还公开了一个名为 safe 的计算 observable,它总是返回一个空对象,但实际的 observable 可以继续存储 null。
现在,您可以像这样绑定到它:
<div data-bind="text: selectedItem.safe().name"></div>
当它为null时你不会看到未知值,但是当selectedItem为null时它至少不会导致错误。
我确实认为在这种情况下首选的选项是使用模板绑定,尤其是当您有许多此类属性要绑定时。