あなたが何か間違ったことをしているとは思いません。問題は、「with」へのバインディングが更新される前に、root.isEmployee への「if」バインディングが適用されることです。そのため、コードは isEmployee への更新を確認し、そこからビューを再評価していますが、現在のコンテキストはまだ古い人です (そのサブスクリプションが起動されていないため)。
これは、 http://jsfiddle.net/drdamour/X6pC9/2/のカスタム バインディングによって証明されています 。更新が 2 つのイベントを受け取ることに注意してください。この 2 番目の更新は、トリガーされた "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>
これを解決する正しい方法は、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);
計算されたメソッドは、サブスクライブ チェーンを処理し、そのすべてを管理する必要がなくなるため、サブスクライブ メソッドよりも優先されます。