0
votes

Thanks in advance for any help. I have spent a couple of weeks scouring the web for some insight. I have been developing code for over 50 years but I am a fairly new JavaScript, HTML, knockout. From what I see, this will be great if I can figure out how to make it work. The example given below is only one of the many things I have tried. Please advise.

I have defined two variables as observables, one computed observable, and one observableArray in my view model. Within the document.ready function, I make an Ajax call which returns a json in object notation. ( I checked it in the debugger). When my HTML page displays the observables and computed observables show up properly. The observable array generates an error (see below) and then displays data obtained from only the first row returned from Ajax. (two were returned).

How do I adjust my code so that all the rows in the Ajax data are shown in the displayed HTML?

Here is the error message that I get:

Uncaught ReferenceError: Unable to process binding "foreach: function (){return cartItems }" Message: Unable to process binding "text: function (){return itemSubTotal() }" Message: itemSubTotal is not defined (19:41:39:172 | error, javascript)

Here is my global data for the view model: var cartDB = ""; var totalPrice = "100"; var cartItems = new Array;

Here is the view model:

  var ViewModel =function (){
        // direct items ==
            this.cartDB = ko.observable(cartDB);
        // array itesm
          //  this.cartItems = ko.observableArray(cartItems);
            this.cartItems = ko.mapping.fromJS(cartItems);
            //for (var n = 1;n++;n<cartItems.length){ this.cartItems.push(cartItem[n]);}
        // computed items
            this.totalPriceSv = ko.computed(function(){
                return "Total Price*=" + centsToDollars(totalPrice);// todo fix
                } ,this);//end totalSvPrice

    };// end ViewModel      

The data is obtained from the following routine which calls on Ajax.This routine is called once from within document.ready and obtains the expected data on the success callback.

function databaseCart(commandInput, cartDBInput, cartPidInput,logPhpInput) {
var postData = new Array();
postData[0] = commandInput;
postData[1] = cartDBInput;
postData[2] = cartPidInput;
postData[3] = logPhpInput; //debug log on php side
data = null; //for  return values
$.ajax({
    type: "GET",
    url: 'ww_CartProcess.php', //the script to call to get data
    data: {data: postData}, 
    dataType: 'json',
    success: function(data) {
         cartItems = data;
         debug = 0;
        },
    complete: function(data) {
         ko.applyBindings(new ViewModel);
         return TRUE;
        },
    error: function(x, e) {//this is the error function for ajax
        var xErr = x;
        var eErr = e;
        ajaxErrorProcessing(xErr, eErr, "addToCart", postData);
    }
});
}// end databasecart  

Here is the HTML 5 snippet.

<div>
<h1 id="cartTitle">Cart Number: <span data-bind="text: cartDB"> </h1>

   <div class ="boxCartItem" data-bind="foreach:cartItems" >

<div class ="boxItemTitle">
    <h2 data-bind="text: title()"></h2>

</div><!--boxItemTitle-->

  <div class ="cartItemBottom"></div>   
  </div ><!--class ="boxCartItem"-->
1
itemSubTotal is not in the model that was returned by the AJAX call. You're also not turning the returned model into a viewmodel with observable properties. If you just leave it as a plain JavaScript object, you need need to remove the ()s in your bindings. - Anthony Chu
I suggest that in the ajax call you examine the incoming data with console.log(data) to see if itemSubTotal is really missing or misspelled. Also the ViewModel should be instantiated as new ViewModel(), i.e. with the parenthesis, as far as I know. - Tommi Gustafsson
Thanks for the help. I did not realize that the lack of a computed function for itemSubTotal was hanging the whole thing up. I temporarily removed the line and the titles to all the items came up. - Ann Maybury

1 Answers

0
votes

My thanks to the commenters. I still do not know how to add an element to all item rows in an observable array, but this problem was caused by not having the item listed defined. Clue> When multiple errors are presented it is sometimes ( and maybe always) good to work from the bottom up.

The problem can be better stated as : Given a 2 x 17 array (2 rows and 17 columns of independent vars)create an observableArray that contains 2 rows and 17 plus columns consisting of the 17 independent variables (can only be changed in the database or by limited user input) augmented with a large number of computed functions .
1.0 I created an orderModel which contained the ko.computed(functions() for each dependent variable.

function rowOrder(data) {
    var self = this;
    var model = ko.mapping.fromJS(data, {}, self);
    model.imagePathSv = ko.computed(function() {
        var category = self.category();
        var imageName = self.imageName();
        var sv ="";
        var sv = "products\\" +category+"\\" + imageName;
        return sv;
        });//end  model.imagePathSv
    //original offer
    model.origNumValidate = ko.computed(function() {
        ans = self.origNum();
        if (ans < 0 | ans > 1) {
            alert("\
         Only onw Original can be pruchased");
            ans = 1;
        }
        self.origNum(ans);
        return ans;
        });//originalNumValidate
    model.origNumLabel = ko.computed(function() {
        var sv = "Original..." + centsToDollars(self.origCost());
        return sv;
        });//end  model.origNumLabel
    model.origMattedShow = ko.computed(function() {
        if (self.origMattedCost() > 0) {
            return true;
        }
        else {
            return false;
        }
    });
    model.origMattedLabel = ko.computed(function() {
        var sv = "Matting...." + centsToDollars(self.origMattedCost());
        return sv;
    });
    model.origFramedShow = ko.computed(function() {
        if (self.origFramedCost() > 0) {
            return true;
        }
        else {
            return false;
        }
    });

    model.origFramedLabel = ko.computed(function() {
        var sv = "Framing...." + centsToDollars(self.origFramedCost());
        return sv;
    });
    //reproductons  offer
    model.reproNumValidate = ko.computed(function() {
        ans = self.reproNum();

        self.reproNum(ans);
        return ans;
    });

    model.reproNumLabel = ko.computed(function() {
        var sv = "Reproductions." + centsToDollars(self.reproCost()) + " each";
        return sv;
    });//end  model.reproNumLabel
    model.reproMattedShow = ko.computed(function() {
        if (self.reproMattedCost() > 0) {
            return true;
        }
        else {
            return false;
        }
    });
    model.reproMatted = ko.observable(true);
    model.reproMattedLabel = ko.computed(function() {
        var sv ="Matting...." +centsToDollars(self.reproMattedCost());
        return sv;
        });
     model.reproFramedShow = ko.computed(function(){
          if(self.reproFramedCost()>0){return true;}
          else {return false;}
      });
    model.reproFramed = ko.observable(true);
    model.reproFramedLabel = ko.computed(function() {
        var sv ="Framing...." +centsToDollars(self.reproFramedCost());
        return sv;
        });
    //pricing subTotals
    model.productsSubTotal = ko.computed(function() {
        var ans =self.origNum() * self.origCost() + self.reproNum() * self.reproCost();
        return ans;
        });//end  model.productsSubTotal
    model.productsSubTotalSv = ko.computed(function() {
        return "Products.." +centsToDollars(model.productsSubTotal());
        return ans;
        });//end  model.productsSubTotal
    model.mattingSubTotal = ko.computed(function() {
        return self.origNum() * self.origMattedCost() + self.reproNum() * self.reproMattedCost();
        });//end  model.mattingSubTotal
        model.mattingSubTotalSv = ko.computed(function() {
        return "Matting...." +centsToDollars(model.mattingSubTotal());
        });//end  model.mattingSubTotal
    model.framingSubTotal = ko.computed(function() {
        return self.origNum() * self.origFramedCost() + self.reproNum() * self.reproFramedCost();
        });//end  model.framingSubTotal
    model.framingSubTotalSv = ko.computed(function() {
        return "Framing...." +centsToDollars(model.framingSubTotal());
        });//end  model.productsSubTotal
    model.rowSubTotal = ko.computed(function() {
        return model.productsSubTotal() +model.mattingSubTotal() + model.framingSubTotal();
        });//end  model.rowsSubTotal
    model.rowSubTotalSv = ko.computed(function() {
        return "Item Subtotal.." +centsToDollars(model.rowSubTotal());
        });//end  model.productsSubTotal
};// END rowOrder

2.0 I created a mapping variable as follows:

var mapping = {
                create: function(options) {
                    return new rowOrder(options.data);
                }

            };

3,0 I created a View Model as follows:

function ViewModel() {
    // direct items for whole page
    var self = this;
    this.cartId = ko.observable(cartDB);
    this.cartIdSv =  ko.computed(function() {
        var sv = "Cart Number: "+ self.cartId();
        return sv;
    },this);//
    this.totalPrice = ko.computed(function() {//to DO COMPUTE
        var int = 10000;
        return int;
    },this);
    this.totalPriceSv = ko.computed(function(){
        return "Total Price*: " + centsToDollars(this.totalPrice());
    },this);
// by row items
    this.cartItems = ko.mapping.fromJS(cartItems, mapping);
}// end ViewModel

4.0 In the success call back from ajax :

success: function(data) {
cartItems = data;
ViewModel();

5.0 I put the ko.apply.bindings(new ViewModel) in the ajax complete callback.

The result was that my rather involved page came up as expected with the computed values initially set.

I am still working on how to update this page. I have not been able to get my code to recompute the computed variables when the user clicks or unclicks a checkbox.

I could not have done this without suggestions from the stackOverflow group. Thanks to you all for the posts that I found all over the google.