June 23, 2013

KnockoutJS - drop-down list應用(2)

KnockoutJS - drop-down list應用(1)範例中,繫結至drop-down list的資料皆是單純的字串陣列,如
self.currencies = ko.observableArray(["USD", "GBP", "EUR", "JPY"]);
以上述方式在drop-down list不管是選項文字或是選項值都是相同的,可由Chrome的開發人員工具得證。


自訂drop-down list選項文字及選項值
在實務上,很常遇到的情況是選項文字與選項值是不同的,例如選項文字是讓使用者能理解的資料,而選項值則是實際送至後端儲存至資料庫的資料,這時繫結至drop-down list就不再是單純的字串陣列,而是Javascript物件陣列了。如
<select data-bind="options: CreditCards, optionsText: 'CardNumber',
    optionsValue: 'CardId', value: SelectedCard, optionsCaption: '請選擇'"></select>
<span data-bind="text: SelectedCard"></span> selected.
function ViewModel() {
    var self = this;
    self.CreditCards = ko.observableArray([{
        "CardId": 1,
            "CardNumber": "1234-5678-1234-0001",
            "CardHolder": "Pete"
    }, {
        "CardId": 2,
            "CardNumber": "1234-5678-1234-0002",
            "CardHolder": "Claire"
    }, {
        "CardId": 3,
            "CardNumber": "1234-5678-1234-0003",
            "CardHolder": "Pudding"
    }]);

    self.SelectedCard = ko.observable();
}

ko.applyBindings(new ViewModel());

上面的範例中,CreditCards是一個observableArray,裡面有3張信用卡資料,分別有CardId、CardNumber及CardHolder 3個屬性。在View中,options binding的optionsText參數指定了CardNumber,表示以CardNumber做為drop-down list的選項文字,而optionsValue參數指定了CardId,表示以CardId做為drop-down list的選項值,要注意的是CardId及CardNumer需有單引號包起來。另外,SelectedCard之值即為選項值(CardId之值)。執行以上範例可以看到選項文字及選項值被正確地設定。



利用選項值取得選項文字
對後端來說,有意義的資料大多是選項值,也就是範例中的CardId,但如果要顯示給使用者知道哪個選項被選取了,當然是要顯示對使用者有意義的選項文字,如範例中的卡號。要知道被選取的選項文字,可以透過jQuery的選取器(selector)來取得。如果不使用jQuery,則需透過Knockout的utils函式庫來搜尋CreditCards陣列來取得選項文字。
<select data-bind="options: CreditCards, optionsText: 'CardNumber',
    optionsValue: 'CardId', value: SelectedCard, optionsCaption: '請選擇'"></select>
<span data-bind="text: SelectedCardText"></span> selected.

self.SelectedCardText = ko.computed(function () {

    var search = self.SelectedCard();

    if (!search) {

        return null;

    } else {

        var matchedItem = ko.utils.arrayFirst(self.CreditCards(), function (item) {
            return item.CardId == search;
        });

        return matchedItem.CardNumber;
    }
});


在原本的ViewModel中,我們新增了一個computed屬性SelectedCardText來顯示卡號。執行結果如下



事實上,還有另一個方式可以直接取得選項文字。在前面的範例中我們指定了optionsValue為CardId,如果不指定optionsValue,取得的SelectedCard不會是純量值(CardId)而會是一個含有CardId、CardNumber及CardHolder的Javascript物件。如此便可透過這個Javascript物件取得CardNumber,也就是選項文字。
<select data-bind="options: CreditCards, optionsText: 'CardNumber',
    value: SelectedCard, optionsCaption: '請選擇'"></select>
<span data-bind="text: SelectedCard() ? SelectedCard().CardNumber : 'none'"></span> selected.

function ViewModel() {
    var self = this;
    self.CreditCards = ko.observableArray([{
        "CardId": 1,
            "CardNumber": "1234-5678-1234-0001",
            "CardHolder": "Pete"
    }, {
        "CardId": 2,
            "CardNumber": "1234-5678-1234-0002",
            "CardHolder": "Claire"
    }, {
        "CardId": 3,
            "CardNumber": "1234-5678-1234-0003",
            "CardHolder": "Pudding"
    }]);

    self.SelectedCard = ko.observable();
}

ko.applyBindings(new ViewModel());

不過這個方式有個潛在的問題會導致jQuery Validation驗証失敗

自訂選項文字
在選項文字的顯示上,除了可以直接指定Javascript物件中的某個屬性,也可以在data binding時,動態地組合出顯示文字,例如顯示卡號再加上持卡人名稱。
<select data-bind="options: CreditCards,
    optionsText: function(item){return item.CardNumber + '(' + item.CardHolder + ')'},
    value: SelectedCard, optionsCaption: '請選擇'"></select>
<span data-bind="text: SelectedCard() ? SelectedCard().CardNumber : 'none'"></span> selected.

No comments: