循环遍历具有可观察属性的 Knockout 可观察对象数组

Posted

技术标签:

【中文标题】循环遍历具有可观察属性的 Knockout 可观察对象数组【英文标题】:Loop through Knockout observable array of objects with observable properties 【发布时间】:2019-06-02 15:39:22 【问题描述】:

在我的应用程序中,我需要。这样我就可以将每个对象发布回服务器。

我可以访问我的模型,但我无法访问我想将其发回服务器的子元素。

我的客户代码是

self.postAllReqs = function(self) 
    self.error(''); // Clear error message
    var model = ko.toJSON(self.Reqs); // convert to json
    for (var item in model) 

        ajaxHelper(reqsUri, 'POST', item).fail(function (jqXHR, textStatus, errorThrown) 
            self.error(errorThrown);
    )
       

请问如何访问子元素?

我的视图模型的提取

function ReqsTest(rt) 
rt = rt || ;
var self = this;
self.id = ko.observable(rt.ID || 0);
self.requisition = ko.observable(rt.Requisition || "");
self.reqnStatus = ko.observable(rt.ReqnStatus || "");
self.dateReqnRaised = ko.observable(rt.DateReqnRaised|| null);
self.reqnValue = ko.observable(rt.ReqnValue || null);
self.approvedValue = ko.observable(rt.ApprovedValue || null);
self.originator = ko.observable(rt.Originator || "");
self.origName = ko.observable(rt.OrigName || "");
self.origEmail = ko.observable(rt.OrigEmail || "");
self.line = ko.observable(rt.Line || 0.00);
self.indx = ko.observable(rt.INDX || 0);
self.dateReqnRaisedL = ko.observable(rt.DateReqnRaisedL || null);
self.reqStatus = ko.observable(rt.ReqStatus || "");
//self.reqBackground = ko.observable(rt.ReqBackground || "");


//Computed observables
self.reqBackground = ko.computed(function () 
    // get variable 
    var status = self.reqStatus();
    if (status == "A")  return "card-heading bg-success text-white"; 
    else if (status == "D")  return "card heading bg-secondary"; 
    else if (status == "R")  return "card heading bg-warning"; 
    else if (status == "E")  return "card heading bg-danger"; 
    else 
        return "card-heading bg-primary text-white";
    
)
self.reqStatusLabel = ko.computed(function () 
    // get variable 
    var status = self.reqStatus();
    if (status == "A")  return "Approved"; 
    else if (status == "D")  return "Declined - put on hold"; 
    else if (status == "R")  return "Routing On"; 
    else if (status == "E")  return "Erase On Syspro"; 
    else 
        return "Awaiting Approval";
    
)

self.approvalBtn = ko.computed(function () 
    // get variable 
    var status = self.reqStatus();
    if (status == "A")  return "css: button btn-secondary "; 
    else 
        return "btn btn-success ";
    
)

self.approvalBtnLbl = ko.computed(function () 
    // get variable 
    var status = self.reqStatus();
    if (status == "W")  return "Approve"; 
    else 
        return "UnApprove";
    
)



self.declineBtnLbl = ko.computed(function () 
    // get variable 
    var status = self.reqStatus();
    if (status == "D")  return "UnDecline"; 
    else 
        return "Decline";
    
)

self.deleteBtnLbl = ko.computed(function () 
    // get variable 
    var status = self.reqStatus();
    if (status == "E")  return "Restore"; 
    else 
        return "Erase";
    
)

// Functions
//show details alert
$(".btn").on("click", function () 
    $(".alert").removeClass("in").show();
    $(".alert").delay(200).addClass("in").fadeOut(2000);
);

function ReqsViewModel ()
    var self = this;
    self.Reqs = ko.observableArray([]);
    self.error = ko.observable();

    var reqsUri = '/api/ReqsTests/';

function ajaxHelper(uri, method, data) 
    self.error(''); // Clear error message
    return $.ajax(
        type: method,
        url: uri,
        dataType: 'json',
        contentType: 'application/json',
        data: data ? JSON.stringify(data) : null
    ).fail(function (jqXHR, textStatus, errorThrown) 
        self.error(errorThrown);
    );


function getAllReqs() 
    ajaxHelper(reqsUri, 'GET').done(function (data) 
        // Build the ReqsTest objects
        var reqs = ko.utils.arrayMap(data, function (rt) 
            return new ReqsTest(rt);
        );
        self.Reqs(reqs);
    );


【问题讨论】:

【参考方案1】:

从我所提供的代码可以看出,没有任何东西调用 getAllReqs 作为 ReqsViewModel 的私有函数。

我不太清楚您的问题是什么,因此我使用您的示例代码创建了一个快速演示,以展示您如何与数组中的项目进行交互。

var app = ;
function ReqsTest(rt, saveItemFn) 
  rt = rt || ;
  var self = this;
  self.id = ko.observable(rt.ID || 0);
  self.requisition = ko.observable(rt.Requisition || "");
  self.reqnStatus = ko.observable(rt.ReqnStatus || "");
  self.dateReqnRaised = ko.observable(rt.DateReqnRaised || null);
  self.reqnValue = ko.observable(rt.ReqnValue || null);
  self.approvedValue = ko.observable(rt.ApprovedValue || null);
  self.originator = ko.observable(rt.Originator || "");
  self.origName = ko.observable(rt.OrigName || "");
  self.origEmail = ko.observable(rt.OrigEmail || "");
  self.line = ko.observable(rt.Line || 0.00);
  self.indx = ko.observable(rt.INDX || 0);
  self.dateReqnRaisedL = ko.observable(rt.DateReqnRaisedL || null);
  self.reqStatus = ko.observable(rt.ReqStatus || "");
  //self.reqBackground = ko.observable(rt.ReqBackground || "");


  //Computed observables
  self.reqBackground = ko.computed(function() 
    // get variable 
    var status = self.reqStatus();
    if (status == "A") 
      return "card-heading bg-success text-white";
     else if (status == "D") 
      return "card heading bg-secondary";
     else if (status == "R") 
      return "card heading bg-warning";
     else if (status == "E") 
      return "card heading bg-danger";
     else 
      return "card-heading bg-primary text-white";
    
  )
  self.reqStatusLabel = ko.computed(function() 
    // get variable 
    var status = self.reqStatus();
    if (status == "A") 
      return "Approved";
     else if (status == "D") 
      return "Declined - put on hold";
     else if (status == "R") 
      return "Routing On";
     else if (status == "E") 
      return "Erase On Syspro";
     else 
      return "Awaiting Approval";
    
  )

  self.approvalBtn = ko.computed(function() 
    // get variable 
    var status = self.reqStatus();
    if (status == "A") 
      return "css: button btn-secondary ";
     else 
      return "btn btn-success ";
    
  )

  self.approvalBtnLbl = ko.computed(function() 
    // get variable 
    var status = self.reqStatus();
    if (status == "W") 
      return "Approve";
     else 
      return "UnApprove";
    
  )
  self.approve = function() 
    if (self.reqStatus() == 'W') 
      self.reqStatus("A");

     else 
      self.reqStatus("W");
    
    saveItemFn(self);
  


  self.declineBtnLbl = ko.computed(function() 
    // get variable 
    var status = self.reqStatus();
    if (status == "D") 
      return "UnDecline";
     else 
      return "Decline";
    
  )

  self.deleteBtnLbl = ko.computed(function() 
    // get variable 
    var status = self.reqStatus();
    if (status == "E") 
      return "Restore";
     else 
      return "Erase";
    
  )

  // Functions
  //show details alert
  $(".btn").on("click", function() 
    $(".alert").removeClass("in").show();
    $(".alert").delay(200).addClass("in").fadeOut(2000);
  );


function dataService(serviceUrl) 
  var url = serviceUrl;

  function getData() 
    // do ajax call here
    return 
      done: function(fn) 
        return fn(app.externalData);
      
    
	
    function saveItem(item) 
      // add posting to server here.
      alert("Saving item: " + item.id());
    

    return 
      getData: getData,
      saveItem: saveItem,
    ;
  


function ReqsViewModel(dataService) 
  var reqsUri = 'api/ReqsTests/';
  var self = this;
  self.Reqs = ko.observableArray([]);
  self.error = ko.observable();
  self.getAllReqs = getAllReqs;

  function getAllReqs() 
    dataService.getData().done(function(data) 
      // Build the ReqsTest objects
      var reqs = ko.utils.arrayMap(data, function(rt) 
        return new ReqsTest(rt, dataService.saveItem);
      );
      self.Reqs(reqs);
    );

  

app.dataService = dataService;

app.externalData = [
  ID: 1,
  Requisition: "Requisition 1",
  ReqnStatus: "A",
  DateReqnRaised: "2019-01-01T11:00:00+11:00",
  ReqnValue: 200.24,
  ApprovedValue: 200,
  Originator: "Slartibartfast",
  OrigName: "Requisition 1",
  OrigEmail: "test@test.com",
  Line: 1.1,
  INDX: 1,
  DateReqnRaisedL: "2019-01-01T11:00:00+11:00",
  ReqStatus: "A"
, 
  ID: 2,
  Requisition: "Requisition 2",
  ReqnStatus: "W",
  DateReqnRaised: "2019-01-02T11:00:00+11:00",
  ReqnValue: 300.24,
  ApprovedValue: 300,
  Originator: "Slartibartfast",
  OrigName: "Requisition 2",
  OrigEmail: "test@test.com",
  Line: 2.2,
  INDX: 2,
  DateReqnRaisedL: "2019-01-02T11:00:00+11:00",
  ReqStatus: "W"
];

var vm = new ReqsViewModel(app.dataService("/api/reqs/"));
vm.getAllReqs();
ko.applyBindings(vm);
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table class="table">
  <thead>
    <tr>
      <th>ID</th>
      <th>Requistion</th>
      <th>Raised</th>
      <th></th>
    </tr>
  </thead>
  <tbody data-bind="foreach: Reqs">
    <tr>
      <td data-bind="text: id"></td>
      <td data-bind="text: requisition"></td>
      <td data-bind="text: dateReqnRaised"></td>
      <td><button class="btn btn-primary" data-bind="css: approvalBtn, text: approvalBtnLbl, click: approve">Approve</button></td>
    </tr>
  </tbody>
</table>

【讨论】:

以上是关于循环遍历具有可观察属性的 Knockout 可观察对象数组的主要内容,如果未能解决你的问题,请参考以下文章

Knockout.js:当可观察数组中的值发生变化时触发计算的最佳方法是啥

Knockout 订阅可观察的复杂对象的任何变化

如何在 Knockout 中创建计算的可观察数组

Knockout JS - 在没有 ko.mapping 的情况下观察数组的任何属性中的突变

Knockout/Select2:触发 select2 根据可观察的选项更新进行更新

knockout.js 可观察数组表上方的静态行