0

我很确定我在上下文方面遗漏了一些东西,但我就是不知道是什么。

我有以下视图模型:

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>

JSFiddle

一旦超时执行,我希望在视图中显示 firstName,但是,我收到以下错误:

 firstName is not defined;

如果我从 viewModel 中的 personB 开始,它可以工作。如果我将 if 语句移到 with 语句之上,它就可以工作。

在这种情况下我做错了什么?

更新了 JSFiddle

4

1 回答 1

3

我不认为你做错了什么。问题是在更新与“with”的绑定之前,正在应用与 root.isEmployee 的“if”绑定。因此代码正在查看对 isEmployee 的更新,然后从那里重新评估视图,但当前上下文仍然是老人(因为该订阅尚未触发)。

这可以通过http://jsfiddle.net/drdamour/X6pC9/2/中的自定义绑定来证明, 请注意更新接收 2 个事件,一次使用旧值导致 isEmployee 更新,第二次使用更新后的新值。第二次更新来自被触发的“with”绑定订阅。'with' 绑定的订阅发生在 applyBindings 调用期间,这发生在您的模型进行订阅之后。

您可以使用 $data.PropertyName 技巧来处理未定义的不引起问题的问题。阿拉: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>

解决这个问题的正确方法是拥有一个计算 isEmployee 的 PersonVM,这样你就不会绑定到根。见: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);

计算优先于订阅方法,因为它为您处理订阅链并将您从必须管理的所有内容中抽象出来。

于 2013-01-22T05:16:09.563 回答