在我的Knockout.js模板中,如果我可以访问视图模型上对象的属性会很方便:
<span data-bind="text: account.shortName"></span>
这不起作用。该元素为空白。但是,我可以这样做:
<div data-bind="with: account">
<span data-bind="text: shortName"></span>
</div>
这有什么办法吗?我必须在任何地方使用with
,以及过多的元素吗?
答案 0 :(得分:3)
如果account
是可观察的,那么你真的应该像使用它一样使用with
绑定,或者使用计算的observable来访问该属性。当然,它有点冗长,但必须这样做。
使用像someObservable().someProperty
这样的表达式只会导致头痛和混乱,应该避免。例如,如果您确实使用了这个并且someProperty
恰好是可观察的,那么当someObservable
发生变化时,您可能会注意到某些事情是不正确的。绑定将不更新为使用新值的someProperty
,我希望您能看到原因。
您可以通过创建一个函数来更安全地创建计算的observable。
ko.observable.fn.property = function (name) {
return ko.computed({
read: function () {
var parentValue = this();
if (parentValue)
return ko.utils.unwrapObservable(parentValue[name]);
},
write: function (value) {
var parentValue = this(), property;
if (parentValue) {
property = parentValue[name];
if (ko.isWriteableObservable(property))
property(value);
}
},
owner: this
});
};
然后你可以在你的绑定中使用它:
<span data-bind="text: account.property('shortName')"></span>
答案 1 :(得分:2)
杰夫的答案很好,但您也可以通过将绑定更改为:
来实现text: account() && account().shortName
我发现这与杰夫在他的回答中提到的相反,即使shortName
是可观察的,因为绑定是implemented inside of a computed observable,这也有效。换句话说,text
绑定的值实现为一种匿名计算。
这是一个片段,显示它有效,从没有值的account
observable开始,然后随着时间的推移更新。
var vm = {
account: ko.observable()
};
$(function() {
ko.applyBindings(vm);
// After a second, set account
setTimeout(function() {
var account = {
shortName: ko.observable('Initial account')
};
vm.account(account);
var newAccount = {
shortName: ko.observable('New account')
}
// After another second, change account
setTimeout(function() {
vm.account(newAccount);
// After another second, change shortName within the new account
setTimeout(function() {
newAccount.shortName('New shortName value in the new account');
}, 1000);
}, 1000);
}, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<body>
<h1>Account Binding Test</h1>
<span data-bind="text: account() && account().shortName"></span>
</body>