我很确定我在上下文中遗漏了一些东西,但我无法弄清楚是什么。
我有以下ViewModel:
var ViewModel = function(){
var self = this;
self.person = ko.observable();
self.isPerson = ko.observable();
self.person.subscribe(function(value){
self.isPerson('firstName' in value);
});
};
var vm = new ViewModel();
var personA = { };
var personB = { firstName: ko.observable("hello") };
vm.person(personA);
ko.applyBindings(vm);
setTimeout(function(){ vm.person(personB); }, 1000);
以及以下视图:
<span data-bind="with: person">
<!-- ko if: $root.isPerson -->
<span data-bind="text: firstName"></span>
<!-- /ko -->
</span>
一旦超时执行,我希望firstName在视图中显示,但是,我收到以下错误:
firstName is not defined;
如果我从viewModel中的personB开始,它就可以了。如果我将if语句移到with语句之上,它就可以工作。
在这种情况下,我做错了什么?
更新了JSFiddle
答案 0 :(得分:3)
我不认为你做错了什么。问题是在更新绑定到“with”之前,正在应用“if”绑定到root.isEmployee。所以代码看到对isEmployee的更新,然后从那里重新评估视图,但当前上下文仍然是老人(因为该订阅尚未触发)。
通过http://jsfiddle.net/drdamour/X6pC9/2/中的自定义绑定证明,更新接收到2个事件,一次使用旧值导致isEmployee更新,第二次使用更新后的新值。第二次更新来自触发的“with”绑定订阅。订阅“with”绑定发生在applyBindings调用期间,该调用发生在您的模型订阅之后。
你可以使用$ data.PropertyName技巧来处理undefined不会导致问题。阿拉:http://jsfiddle.net/drdamour/X6pC9/1/
<span data-bind="with: person">
<span data-bind="text: firstName"></span>
<!-- ko if: $root.isEmployee -->
<span data-bind="text: $data.employeeId"></span>
<span data-bind="text: $data.employer"></span>
<!-- /ko -->
</span>
解决此问题的正确方法是让PersonVM计算出isEmployee,这样就不会绑定到root。见:http://jsfiddle.net/drdamour/eVXTF/1/
<span data-bind="with: person">
<span data-bind="text: firstName"></span>
<!-- ko if: isEmployee -->
<span data-bind="text: $data.employeeId"></span>
<span data-bind="text: $data.employer"></span>
<!-- /ko -->
</span>
和
var ViewModel = function(){
var self = this;
self.person = ko.observable();
};
var PersonVM = function()
{
var self = this;
this.firstName = ko.observable();
this.employeeId = ko.observable();
this.employer = ko.observable();
self.isEmployee = ko.computed(function(){return self.employer() != null});
}
var vm = new ViewModel();
var customer = new PersonVM();
customer.firstName("John");
var employee = new PersonVM();
employee.firstName("Bill");
employee.employeeId(123);
employee.employer("ACME");
vm.person(customer);
ko.applyBindings(vm);
setTimeout(function(){ vm.person(employee); }, 3000);
计算优先于订阅方法,因为它为您处理订阅链,并抽象您远离必须管理所有这些。