当更新ObservableArray时UI不会更新

问题描述:

当用户从UI(html表tblAllCert)中的列表中点击一行时,我有一个点击事件触发来填充另一个应该填充第二个html表的可观察数组(tblCertDetails )。我的点击事件触发,我可以看到数据回来,我可以看到可观察数组中的数据,但我的视图不更新。当更新ObservableArray时UI不会更新

下面是该序列中的代码 -

1. user clicks on row from html table tblAllCert, which fires selectThing method. 
2. In viewmodel code, selectThing passes the row data from the row selected to the GetCertificateDetails(row) method. 
3. GetCertificateDetails(row) method calls getCertDetails(CertificateDetails, source) function on my data service (the data service gets data from a web api). getCertDetails(CertificateDetails, source) function returns an observable array. 
4. once the data is returned to selectThing, CertificateDetails observable array is populated. It does get data to this point. 

步骤5应该被更新UI(具体tblCertDetails HTML表)的概述,但是UI没有更新。

这里是我的视图 -

        <table id="tblAllCert" border="0" class="table table-hover" width="100%"> 
            <tbody data-bind="foreach: allCertificates"> 
             <tr id="AllCertRow" style="cursor: pointer" data-bind="click: $parent.selectThing, css: { highlight: $parent.isSelected() == $data.lwCertID }"> 
              <td> 
               <ul style="width: 100%"> 

                <b><span data-bind=" text: clientName"></span>&nbsp;(<span data-bind=" text: clientNumber"></span>)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span data-bind=" text: borrowBaseCount"></span>&nbsp;Loan(s)&nbsp;</b> 
                <br /> 
                Collateral Analyst:&nbsp;<span data-bind=" text: userName"></span> 
                <br /> 
                Certificate:&nbsp;<span data-bind="text: lwCertID"></span>&nbsp;&nbsp;Request&nbsp;Date:&nbsp;<span data-bind=" text: moment(requestDate).format('DD/MMM/YYYY')"></span> 
              </td> 
             </tr> 
            </tbody> 
           </table> 


           <table id="tblCertDetails" border="0" class="table table-hover" width="100%"> 
           <tbody data-bind="foreach: CertificateDetails"> 
            <tr id="Tr1" style="cursor: pointer"> 
             <td> 
              <ul style="width: 100%"> 
               <b>Loan:&nbsp;<span data-bind=" text: loanNum"></span> 
             </td> 
            </tr> 
           </tbody> 

          </table> 

我viewmodel-

define(['services/logger', 'durandal/system', 'durandal/plugins/router', 'services/CertificateDataService'], 
function (logger, system, router, CertificateDataService) { 
    var allCertificates = ko.observableArray([]); 
    var myCertificates = ko.observableArray([]); 
    var isSelected = ko.observable(); 
    var serverSelectedOptionID = ko.observable(); 

    var CertificateDetails = ko.observableArray([]); 

    var serverOptions = [ 
    { id: 1, name: 'Certificate', OptionText: 'lwCertID' }, 
    { id: 2, name: 'Client Name', OptionText: 'clientName' }, 
    { id: 3, name: 'Client Number', OptionText: 'clientNumber' }, 
    { id: 4, name: 'Request Date', OptionText: 'requestDate' }, 
    { id: 5, name: 'Collateral Analyst', OptionText: 'userName' } 
    ]; 

    var activate = function() { 
     // go get local data, if we have it 
     return SelectAllCerts(), SelectMyCerts(); 
    }; 


    var vm = { 
     activate: activate, 
     allCertificates: allCertificates, 
     myCertificates: myCertificates, 
     CertificateDetails: CertificateDetails, 
     title: 'Certificate Approvals', 
     SelectMyCerts: SelectMyCerts, 
     SelectAllCerts: SelectAllCerts, 
     theOptionId: ko.observable(1), 
     serverOptions: serverOptions, 
     serverSelectedOptionID: serverSelectedOptionID, 
     SortUpDownAllCerts: SortUpDownAllCerts, 
     isSelected: isSelected, 
     selectThing: function (row, event) { 
      CertificateDetails = GetCertificateDetails(row); 
      isSelected(row.lwCertID); 
     } 

    }; 



    serverSelectedOptionID.subscribe(function() { 
     var sortCriteriaID = serverSelectedOptionID(); 
     allCertificates.sort(function (a, b) { 
      var fieldname = serverOptions[sortCriteriaID - 1].OptionText; 

      if (a[fieldname] == b[fieldname]) { 
       return a[fieldname] > b[fieldname] ? 1 : a[fieldname] < b[fieldname] ? -1 : 0; 
      } 

      return a[fieldname] > b[fieldname] ? 1 : -1; 

     }); 

    }); 

    return vm; 



    function GetCertificateDetails(row) { 
     var source = { 
      'lwCertID': row.lwCertID, 
      'certType': row.certType, 
     } 
     return CertificateDataService.getCertDetails(CertificateDetails, source); 
    } 

    function SortUpDownAllCerts() { 
     allCertificates.sort(); 
    } 


    function SelectAllCerts() { 
     return CertificateDataService.getallCertificates(allCertificates); 
    } 

    function SelectMyCerts() { 
     return CertificateDataService.getMyCertificates(myCertificates); 
    } 

}); 

和卫浴套间摘录的,为什么UI没有更新我的数据服务 -

 var getCertDetails = function (certificateDetailsObservable, source) { 
     var dataObservableArray = ko.observableArray([]); 
     $.ajax({ 
      type: "POST", 
      dataType: "json", 
      url: "/api/caapproval/CertDtlsByID/", 
      data: source, 
      async: false, 
      success: function (dataIn) { 

       ko.mapping.fromJSON(dataIn, {}, dataObservableArray); 

      }, 
      error: function (error) { 
       jsonValue = jQuery.parseJSON(error.responseText); 
       //jError('An error has occurred while saving the new part source: ' + jsonValue, { TimeShown: 3000 }); 
      } 

     }); 
     return dataObservableArray; 
    } 

想法?

当你使用Knockout数组时,你应该改变数组的内容而不是对数组本身的引用。在selectThing,当你设置

CertificateDetails = GetCertificateDetails(row); 

observableArray一个已经分配给CertificateDetails是不是KO绑定到表中的同一observableArray

尽管您非常接近解决方案。在AJAX成功回调中,您可以直接将参数映射到参数certificateDetailsObservable中,而不是创建新的dataObservableArray并映射到该参数中。 ko.mapping.fromJSON应该替换表格绑定数组的内容(您也可以在selectThing中删除该作业)。

+0

谢谢ejegg。这工作! – Chris