專案需求一枚,用於匯率換算。來源幣別及目標幣別以下拉選單方式顯示,想當然爾,目標幣別跟來源幣別相同還轉換個屁,因此規格提到: 目標幣別的下拉選項應包含所有幣別,但排除來源幣別當下的選取幣別,特殊的下拉選單連動需求應運而生。

要用KO實現此一連動並不困難: 為兩個<SELECT>各宣告一個observableArray作為options繫結對象,也各宣告一個observable作為value的繫結對象以對應下拉選單選取值;接著宣告一個computed函式建立來源幣別選取值與目標幣別observableArray的關聯,一旦來源幣別變動,複製來源幣別的observableArray,剔除當下來源幣別選取值後將陣列設定成目標幣別observableArray的內容,大功告成。

進一步分析,前述的computed只有單一訂閱對象及單一更新對象,可再簡化,將目標幣別options直接繫結到一個computed(訂閱來源幣別選取值,傳回剔除選取值後的幣別陣列),便可以computed取代observableArray + computed。

最後提一下jQuery.map這個好東西,在JavaScript中處理陣列,許多初學者直覺的做法會宣告新的空陣列,跑迴圈逐一處理陣列元素再放入新陣列。例如: 需求為1-10的數字陣列只留單數並+10,變成11, 13, 15..,通常會寫成:

var orig = [1,2,3,4,5,6,7,8,9,10]; 
  var res = []; 
  for (var i = 0; i < orig.length; i++) { 
    var v = orig[i]; 
    if (v % 2 == 0) continue; 
    res.push(v + 10); 
  }

而jQuery.map可簡化上述程式,變成:

var orig = [1,2,3,4,5,6,7,8,9,10]; 
var res = $.map(orig, function(v, i) { 
  if (v % 2 == 0) return null; //表示剔除 
  return v + 10; 
});

很精省吧?

完整程式碼如下: 線上展示

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>KO範例28 - 轉換對象(排除自己)之下拉選單連動</title>
</head>
<body>
  <div>
    From: 
    <select data-bind="options: ListA, value: PropA, optionsText: 't', optionsValue: 'v'"></select>
    (<span data-bind="text: PropA"></span>)
    &nbsp;&nbsp;&nbsp;To:
    <select data-bind="options: ListB, value: PropB, optionsText: 't', optionsValue: 'v'"></select>
    (<span data-bind="text: PropB"></span>)
  </div>
  <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.js"></script>
 <script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>
  <script>
    function myViewModel() {
      var self = this;
      self.PropA = ko.observable();
      self.ListA = ko.observableArray([
        { v:"TWD", t:"台幣" }, 
        { v:"USD", t:"美金" },
        { v:"EUR", t:"歐元" },
        { v:"JPY", t:"日幣" }, 
        { v:"HKD", t:"港幣" }
      ]);
      self.PropB = ko.observable();
      self.ListB = ko.computed(function() {
        var a = self.PropA();
        return $.map(self.ListA(), function(item) {
          if (item.v == a) return null;
          return item;
        });
      });
    }
    var vm = new myViewModel();
    ko.applyBindings(vm);
  </script>
</body>
</html>

[KO系列]

http://www.darkthread.net/kolab/labs/default.aspx?m=post

Comments

Be the first to post a comment

Post a comment