Knockout.js可观察阵列操作

时间:2017-02-27 19:17:24

标签: javascript oop knockout.js

我对knockout.js有些新意见,而且我无法绕过将某些操作放在可观察数组上的地方。这是我的代码:

var Building = function() {
    var self = this;
    self.nLocation = ko.observable();
    self.nBuilding = ko.observable();
    ...
    self.increaseLocNum = function() {
        self.nLocation(self.nLocation + 1);
    };
}
var Quote = function() {
    var self = this;
    var nQuoteID = ko.observable();
    ...
    self.buildings = ko.observableArray([]);
    self.addBuilding = function(){
        ...
        // Build new building with next loc/building number
        buildings.push();
    }
    ...
}
ko.applyBindings(new Quote());

基本上我的报价可以有多个建筑物。每个建筑物都绑定到选项卡控件上的不同选项卡。在这些标签上有一个位置'具有增加/减少位置编号的+/-按钮的字段。

我需要使用'启用'绑定以设置+/-按钮的启用(例如,如果建筑物是最高位置编号的唯一建筑物。以下是一些简单规则的示例:

  • 如果建筑物位于位置1
  • ,则无法减少位置编号
  • 如果建筑物是最高位置的唯一建筑物,则无法增加位置编号
  • 如果只有一个建筑物
  • ,则无法增加位置编号

逻辑非常简单,但我在这个逻辑应遵循最佳淘汰赛的地方迷失了。

1 个答案:

答案 0 :(得分:1)

减少函数很容易,因为个别建筑视图模型不需要知道任何外部因素来做出决定;它可以是基于其位置可观察的直接计算。增加功能比较棘手,因为它取决于集合中所有其他建筑物的状态。

这是避免子类必须知道父类的一个选项。在每个建筑物上放置一个canIncrease observable,但让父视图模型处理实际的增加/减少,以便它可以循环遍历所有子节点并在位置发生更改时更新它们的observable。

var Building = function(location) {
  var self = this;
  self.nLocation = ko.observable(location);
  self.nBuilding = ko.observable("-Building Name Here-");
  
  self.canIncrease = ko.observable(); //set by parent
  self.canDecrease = ko.computed(function(){
    //Location number can't be decreased if the building is at location 1
    return self.nLocation() > 1;
  });
}

var Quote = function() {
  var self = this;
  var nQuoteID = ko.observable();

  self.buildings = ko.observableArray([new Building(1)]);

  self.addBuilding = function() {
    // Build new building with next loc/building number
    self.buildings.push(new Building(self.highestLocation() + 1));
    self.enableChildren();
  }
  
  self.highestLocation = ko.computed(function(){
    var highest=0;
    $.each(self.buildings(), function(key,value){ if(value.nLocation() > highest) highest = value.nLocation(); });
    return highest;
  });
  
  self.increaseLocNum = function(building) {
    building.nLocation(building.nLocation() + 1);
    self.enableChildren();
  };
  self.decreaseLocNum = function(building) {
    building.nLocation(building.nLocation() - 1);
    self.enableChildren();
  };
  
  self.enableChildren = function(){
    //Location number can't be increased if the building is the only building on the highest location
    //Location number can't be increased if there is only one building
    $.each(self.buildings(), function(key, building){
        if(building.nLocation() === self.highestLocation() || self.buildings().length === 1){
          building.canIncrease(false);
        }else{
          building.canIncrease(true);
        }
    });
  }
}

ko.applyBindings(new Quote());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<input type="button" data-bind="click: addBuilding" value="Add Building" />
<span style="margin-left: 8px;">Total Buildings: <label data-bind="text: buildings().length" /></span>
<span style="margin-left: 8px;">Highest Location: <label data-bind="text: highestLocation" /></span>
<br/>
<table>
  <thead>
    <tr>
      <th></th>
      <th>Location</th>
      <th>Building Name</th>
    </tr>
  </thead>
  <tbody data-bind="foreach: buildings">
    <tr style="border: 1px solid blue;">
      <td>
        <input type="button" data-bind="enable: canDecrease, click: $parent.decreaseLocNum" value="-" />
        <input type="button" data-bind="enable: canIncrease, click: $parent.increaseLocNum" value="+" />
      </td>
      <td>
        <span data-bind="text: nLocation"></span>
      </td>
      <td>
        <span data-bind="text: nBuilding"></span>
      </td>
    </tr>
  </tbody>
</table>