3
votes

I have a function that makes an ajax call to get the initial data and saves it to a viewmodel. Then, I'm passing the returned viewmodel (stringifying the data) into another function that makes another ajax call and so on. Each function is bound to the onclick button event. I was only able to pass the initial view model to the other functions when I placed it in the document.ready. the data I'm getting from each function is 100% correct. However, whenever I bind the viewmodel, it overrides the previous binding and the values don't hold. Below is the code:

JavaScript

<

script type="text/javascript" language='javascript'>
        var MyProject = {};
        var viewModel;
        MyProject.viewModel = "";
        var invoiceModel;
        $(document).ready(function InitializeInvoice() {
                    $.ajax({
                        type: "Post",
                        url: "Default.aspx/InitializeModel",
                        data: {},
                        contentType: "application/json; charset=utf-8",
                        dataType: "json",
                        async: false,
                        success: initializesinvoice
                    });
                function initializesinvoice(msg) {
                    var defaultdata = msg.d.Data;
                    invoiceModel = defaultdata;
                    MyProject.viewModel = ko.mapping.fromJS(invoiceModel);
                    ko.applyBindings(MyProject.viewModel)
                };
            })
            function GetVendorInvoiceDefaults() {
                MyProject.viewModel = JSON.stringify(invoiceModel);
                var data = '{invoice:' + MyProject.viewModel + '}';
                $.ajax({
                    type: "Post",
                    url: "Default.aspx/GetVendorInvoiceDefaults",
                    data: data,
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    async: false,
                    success: GetVendorInvoiceDefaultsSuccess
                });
            }
            function GetVendorInvoiceDefaultsSuccess(msg) {
                var defaultdata = msg.d.Data;
                invoiceModel = defaultdata;
                MyProject.viewModel = ko.mapping.fromJS(invoiceModel);
                ko.applyBindings(MyProject.viewModel)
            };

             function GetVendorCode() {
                var vendormodel = JSON.stringify(invoiceModel);
                var data = '{invoice:' + vendormodel + '}';
                $.ajax({
                    type: "Post",
                    url: "Default.aspx/GetVendorCode",
                    data: '{invoice:' + vendormodel + '}',
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    async: false,
                    success: GetVendorCodeSucess
                });
            }

            function GetVendorCodeSucess(msg) {
                var defaultdata = msg.d.Data;
                MyProject.viewModel = ko.mapping.fromJS(defaultdata);
                ko.applyBindings(MyProject.viewModel)
            };
#HTML#
    <p> Invoice Description <asp:TextBox ID="txtdesc" runat="server" data-bind="value:InvoiceDescription"> </asp:TextBox></p>    
    <p> Distribution Code <asp:TextBox ID="txtdistcode" runat="server" data-bind="value:DistributionCode"></asp:TextBox></p>
    <p> Vendor Code <asp:TextBox ID="txtvendor" runat="server" data-bind="value:VendorCode" ></asp:TextBox></p>
    <p> <button onclick="InitializeInvoice()">InitializeInvoice</button></p>
    <p><button id="btndefaults" onclick="GetVendorInvoiceDefaults()">GetVendorInvoiceDefaults</button></p>
    <p><button id="btnvendor" onclick="GetVendorCode()">GetVendorCode</button><p>
</pre>

#ASPX file#
    namespace WebApplication9
    {

    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            

        }

        protected override void OnLoad(EventArgs e)
        {
            if (IsPostBack)
            {
            
                clientSideIsPostBack.Value = "Y";
            }
            
            else
                    clientSideIsPostBack.Value = "N";

                base.OnLoad(e);
        }
    
        [WebMethod]
        public static JsonResult  InitializeModel()
        {

            var Invoice = new Invoice() { InvoiceNumber = "1235", InvoiceDescription = "Hello World", DistributionCode = "" };
            JsonResult r = new JsonResult();
            r.Data = Invoice;
            return r;    //serializer.Deserialize(Invoice, typeof(Invoice)) as JsonResult;
        }

        [WebMethod]
        public static JsonResult GetVendorInvoiceDefaults(Invoice invoice)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            invoice.DistributionCode = "HELLO WORLD";
            JsonResult r = new JsonResult();
            r.Data = invoice;
            return r;
            //return new JsonResult() { Data = invoice };
        }

        [WebMethod]
        public static JsonResult GetVendorCode(Invoice invoice)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            invoice.VendorCode = "AHM";
            JsonResult r = new JsonResult();
            r.Data = invoice;
            return r;
        }

    }


    public class Invoice
    {
        private string distributionCode;
        private string vendorcode;

        public string InvoiceNumber { get; set; }
        public string InvoiceDescription { get; set; }
        public string DistributionCode 
        {
            get
            {
                return distributionCode ?? string.Empty;
            }
            set
            {
                distributionCode = value;
            }
        }
        public string VendorCode 
        {
            get
            {
                return vendorcode ?? string.Empty;
            
            }
            set 
            {
                vendorcode = value;
            
            }
        }
        
    }
    }
1

1 Answers

3
votes

So, you should never make this call in more than one place, or more than once (per div) ko.applyBindings(MyProject.viewModel).

Once bindings for a viewmodel have been applied, they are applied. YOU NEVER REPEAT THIS STEP! This is very important. When the values in MyProject.viewModel are updated, the bindings update the HTML automatically. That's the whole point. When you call applyBindings more than once, you are going to create all kinds of unexpected behavior.

Setup your viewModel, applyBindings once, then make all the other code update the viewmodel properly. I recommend doing this in the document.ready handler before doing anything else, like wiring up ajaxy stuff.

Second, when using the KO Mapping plugin, per the documentation, you update the entire viewmodel like this: ko.mapping.fromJS(data, viewModel); Calling MyProject.viewModel = ko.mapping.fromJS(invoiceModel); every time will overwrite your viewmodel.

This is another key aspect of Knockout. Because observables are functions, you update them by passing the new value as a parameter, not by overwriting them like normal variables.

Right:

viewModel.observable(newValue)

Wrong:

viewModel.observable = newvalue