通过映射插件重新映射对象后,属性的可观察订阅者停止工作

Observable subscriber of properties stop working after remapping object by mapping plugin

ViewModel 从 JSON 初始化并映射到 $(document).ready(..)

$(document).ready(function ()
{
    viewmodel = new Order();
    var data = { json data };
    ko.mapping.fromJSON(data, {}, viewmodel);
    ko.applyBindings(viewmodel);
});

class Order
{
    ID: KnockoutObservable<number>;
    InvoiceAddress: KnockoutObservable<Address>;
    constructor()
    {
        this.ID = ko.observable(0);
        this.InvoiceAddress= ko.observable(new Address());
        this.InvoideAddress.subscribe(function(newvalue) { console.log(newvalue)}, this);
    }
}

属性 InvoiceAddress另一种Address可以是null 当用户创建或删除 InvoiceAddress 时,将发送 $ajax 请求并返回新的 JSON 对象,其中包含整个 viewmodel 的更新数据。 收到的数据映射到同一视图模型实例

ko.mapping.fromJSON(data, {}, viewmodel);

如果 InvoiceAddress 的状态从 null 更改为现有对象,则 InvoiceAddress 的绑定将停止工作。

<input data-bind="value: InvoiceAddress().StreetName">

问题:在 "re-mapping" 之后是否可以继续绑定?

更新:"Stops working" -> "InvoiceAddress" 变量中属性的订阅者在 "InvoiceAddress" 变为 null 并重新映射回普通对象后未触发

不要这样做。

<input data-bind="value: InvoiceAddress().StreetName">

这样做:

<div data-bind="with: InvoiceAddress">
    <input data-bind="value: StreetName">
</div>

比较:

ko.applyBindings({
    InvoiceAddress: ko.observable({StreetName: "Invoice Street"}),
    ShippingAddress: ko.observable(null),
    addShipping: function () { this.ShippingAddress({StreetName: "Shipping Street"}); },
    removeShipping: function () { this.ShippingAddress(null); }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<b>Invoice Address</b>
<div data-bind="with: InvoiceAddress">
    <input data-bind="value: StreetName">
</div>

<b>Shipping Address</b>
<div data-bind="ifnot: ShippingAddress">-</div>
<div data-bind="with: ShippingAddress">
    <input data-bind="value: StreetName">
</div>

<button data-bind="click: addShipping">Add Shipping</button>
<button data-bind="click: removeShipping">Remove Shipping</button>

使用 with 还可以更轻松地将整个事物变成模板或组件。

我接受了@Tomalak 的回答,因为他的回答让我朝着正确的方向去理解 Knockout 的 Observables 是如何工作的(文档还不够 :))
但是想post一个解决问题的方法

具体问题是在 属性 被 knockout.mapping 插件从 null 映射到新对象

后订阅者停止触发
var orderData = {"ID":2,"InvoiceAddress":null}
ko.mapping.FromJS(orderData, {}, viewmodel);
//underlying object of observable this.InvoiceAddress is null
// then user added new address
var newAddressData = {"ID":3, "StreetName":"Third"} //returned by ajax request
ko.mapping.FromJS(newAddressData, {}, this.InvoiceAddress);

在那之后 this.InvoiceAddress 内的属性订阅者停止触发。

问题是因为映射插件每次都创建了 属性 类型的新实例,而没有使用初始化订阅者的类型的构造函数。

解决方案:在映射之前创建基础类型的实例

var newAddressData = {"ID":3, "StreetName":"Third"}
var tempAddress: Address = new Address();
ko.mapping.FromJS(newAddressData; {}, tempAddress);
this.InvoiceAddress(tempAddress);