Quantcast
Channel: 黑暗執行緒
Viewing all articles
Browse latest Browse all 2311

KO範例23 – 單選或多選兩用Checkbox清單

$
0
0

利用Checkbox模擬Radio清單的互斥選項是我常用的UI風格,之前曾用jQuery實作過,現在網頁都搬到Knockout的場子,少不了也要重現相同功能,順便考驗KO的能耐。(為何不直接用下拉選單就好? 這裡有一個好理由)

廢話不多說,直覺用以下Demo定義規則! (PS: 寫得太順手,不小心連多選的版本都寫進去 XD)

我最開始的想法是開發一個自訂繫結,將ko.observableArray轉成選項,並將勾選結果反應給ko.observable,而選項繫結時還需要像下拉選單一樣指定Text及Value…  想來想去,幾乎就是重寫一組跟<select>的options、optionsText、optionsValue、value一樣的繫組,那那那,何不直接寄生在<select>上? 把<option>轉成<input type="checkbox">,再把<select>本體藏起來,出乎順利地便完成了上述展示的效果。

使用方法很簡單,在一般的<select> data-bind後方再多加一個xorChkValue參數指向繫結對象就OK了:
(被選取項目的文字預設會變成藍色,如需修改可透過xorChkColor指定)

<select data-bind="options: categories, optionsText: 't', optionsValue: 'v', value: category, xorChkValue: category, xorChkColor: 'brown'"></select>

多選時一樣是加xorChkValue,但繫結對象要是ko.observableArray,記得<select>要加上multiple並改用selectedOptions取代value:

<select data-bind="options: categories, optionsText: 't', optionsValue: 'v', selectedOptions: selCatgs, xorChkValue: selCatgs" multiple>
</select>

完整程式碼如下,線上展示這回我放在JS Bin,有興趣的朋友可以試玩看看,發現問題請再回饋給我。

<!DOCTYPEhtml>
<html>
<head>
<scriptsrc="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script>
<script>
//互斥點選的checkbox
        ko.bindingHandlers.xorChkValue = {
            update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var $elem = $(element); //應為select
var val = valueAccessor();
var settings = allBindingsAccessor();
//檢查是否為多選
var multiple = "push"in val;
//支援自訂顏色
var color = settings.xorChkColor || "blue";
//取得<select>後方的元素
var $next = $elem.next();
var $container;
//取後方已有容器元素,清空即可
if ($next.hasClass("xor-checks")) {
                    $container = $next;
                    $container.empty();
                }
else { //否則建立容器
                    $container = $("<span class='xor-checks'></span>");
//加入對label及checkbox的點擊行為
                    $container.on("click", "input,label", function () {
//點擊label時透過prev()找到checkbox
var inp = this;
if (this.tagName.toLowerCase() === "label") {
                            inp = $(this).prev()[0];
                            inp.checked = !inp.checked; //切換選取
                        }
                        console.log(inp.checked);
if (multiple) { //多選時, 視狀態決定新增或移除
if (inp.checked) {
if ($.inArray(inp.value, val()) == -1)
                                    val.push(inp.value);
                            }
else {
                                val.remove(inp.value);
                            }
                        }
else { //單選
                            inp.checked = true;
                            val(inp.value);
                        }
                    });
                }
                $elem.find("option").each(function () {
var $cbx = $("<span><input type='checkbox' /><label /></span>");
varchecked =
                        multiple ? $.inArray(this.value, val()) != -1 :
                        val() == this.value;
                    $cbx.find("input").val(this.value).prop("checked", checked);
                    $cbx.find("label").text(this.text).css("color", checked ? color : "");
                    $container.append($cbx);
                });
                $elem.after($container);
                $elem.hide();
            },
        }
 
var c = 1;
function myViewModel() {
var self = this;
            self.categories = ko.observableArray();
            self.category = ko.observable("D");
            self.selCatgs = ko.observableArray(["D", "T"]);
            self.selCatgsText = ko.computed(function () {
return JSON.stringify(self.selCatgs());
            });
            self.addOption = function () {
                self.categories.push({ t: "Extra-" + c, v: c });
                c++;
            };
        }
var vm = new myViewModel();
        vm.categories.push({ t: "Desktop", v: "D" });
        vm.categories.push({ t: "Phone", v: "P" });
        vm.categories.push({ t: "Tablet", v: "T" });
        vm.categories.push({ t: "TV", v: "V" });
        $(function () {
            ko.applyBindings(vm);
        });
</script>
<metacharset="utf-8"/>
<title>KO範例23 – 單選或多選兩用Checkbox清單</title>
</head>
<bodystyle="padding: 24px">
<inputtype='button'data-bind="click: addOption"value="Add Option"/>
<br/>
單選: 
<selectdata-bind="options: categories, optionsText: 't', optionsValue: 'v', value: category, xorChkValue: category, xorChkColor: 'brown'"></select>
<br/>
<spandata-bind="text: category"></span>
<br/>
多選:
<selectdata-bind="options: categories, optionsText: 't', optionsValue: 'v', selectedOptions: selCatgs, xorChkValue: selCatgs"multiple>
</select>
<br/>
<spandata-bind="text: selCatgsText"></span>
</body>
</html>

[KO系列]

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

Viewing all articles
Browse latest Browse all 2311

Trending Articles