ViewModel initialized and mapped from JSON inside $(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);
}
}
Property InvoiceAddress
of another type Address
can be null
When user create or delete InvoiceAddress
, $ajax
request will be send and new JSON object returned which contain updated data of whole viewmodel
.
Received data mapped to the same instance of viewmodel
ko.mapping.fromJSON(data, {}, viewmodel);
If state of InvoiceAddress
was changed from null
to existed object, then binding for InvoiceAddress
stops working.
<input data-bind="value: InvoiceAddress().StreetName">
Question: Is it possible to keep binding working after "re-mapping"?
Update: "Stops working" -> subscribers of properties in the "InvoiceAddress" variable not firing after "InvoiceAddress" become null
and remapped back to normal object
Don't do this.
<input data-bind="value: InvoiceAddress().StreetName">
Do this:
<div data-bind="with: InvoiceAddress">
<input data-bind="value: StreetName">
</div>
Compare:
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>
Using with
also makes it easier to turn the whole thing into a template or a component.