0
votes

I have a child observable array on an defined object. When the object from the server is returned and populated into the knockout observable the data fails to display. However the data is in the view model can can be verified with debugging. I have created jsFiddle that illustrates the problem.

http://jsfiddle.net/CraigHead/Y2Fr6/

My view models are defined as such

function PropertyLease(propertyLeaseId, propertyCatalogId, confirmedBldgSF, leaseExpenseStructure, leaseTermRate, propertyType, yearBuilt)
{
    var self = this;
    self.PropertyLeaseId  = ko.observable(propertyLeaseId);
    self.PropertyCatalogId = ko.observable(propertyCatalogId);
    self.ConfirmedBldgSF = ko.observable(confirmedBldgSF);
    self.LeaseExpenseStructure = ko.observable(leaseExpenseStructure);
    self.LeaseTermRate = ko.mapping.fromJS(leaseTermRate);
    self.PropertyType = ko.observable(propertyType);
    self.YearBuilt = ko.observable(yearBuilt);
}

function PropertyLeaseTermRate(propertyLeaseTermId, propertyLeaseId, from, to, annualRatePSF)
{
    var self = this;
    self.PropertyLeaseTermId = ko.observable(propertyLeaseTermId);
    self.PropertyLeaseId = ko.observable(propertyLeaseId);
    self.From = ko.observable(from);
    self.To = ko.observable(to);
    self.AnnualRatePSF = ko.observable(annualRatePSF);
}

and I update them when the data is returned from the server like

viewModel.LeaseSearchResults.removeAll();
var vmLeaseSearchResults = viewModel.LeaseSearchResults();
for(var idx = 0; idx<result.LeaseSearchResults.length; idx++){
    var data = result.LeaseSearchResults[idx];
    vmLeaseSearchResults.push(
        new PropertyLease(
            data.PropertyLeaseId, 
            data.PropertyCatalogId, 
            data.ConfirmedBldgSF, 
            data.LeaseExpenseStructure, 
            data.LeaseTermRate, 
            data.PropertyType, 
            data.YearBuilt
            )
        )
}
viewModel.LeaseSearchResults.valueHasMutated();

I am not sure what I am doing wrong? Arg!

P.S. The second View Model PropertyLeaseTermRate isn't used until the user makes a choice from a data grid. ;-) Sorry for the confusion there.

1

1 Answers

1
votes

You have multiple problems:

  • If you are writing var vmLeaseSearchResults = viewModel.LeaseSearchResults(); because of the () you are referencing the underaying array and not the observable array itself. So when you are calling vmLeaseSearchResults.push Knockout won't be notified so you need the call valueHasMutated.

    But the correct approach is to let Knockout do the change tracking so you should remove the (): so var vmLeaseSearchResults = viewModel.LeaseSearchResults; then you don't need the valueHasMutated call.

  • You have the same problem with the var vmLeaseTermRate = viewModel.SelectedLease().LeaseTermRate();

    However here you have a second problem. When you call viewModel.SelectedLease(value); knockout will start to bind your details list in the <div data-bind="with: SelectedLease">. But your model (value) does not have the LeaseTermRate defined yet, so Knockout will silently fail on the ko foreach: LeaseTermRate.

    To fix it just move the LeaseTermRate declaration before the SelectedLease call:

    var value = ko.mapping.fromJS(item);
    value.LeaseTermRate = ko.observableArray();
    viewModel.SelectedLease(value);
    var vmLeaseTermRate = viewModel.SelectedLease().LeaseTermRate;
    

Demo JSFiddle.