KO範例21 - 指定顯示格式
5 |
來談一個MVVM實務上超級常見的問題: 透過Binding宣告可以輕易將ViewModel屬性繫結到視覺元素上顯示,但數字、日期等內容常需依指定格式呈現才容易閱讀,因此在繫結時多半需要指定格式,例如: XAML在Binding時就可以透過StringFormat指定格式。但Knockout預設的繫結功能並不支援格式指定,所幸憑藉著KO優異的擴充性,這倒不算頭痛的問題。
我慣用的解法是借用Kendo UI程式庫的kendo.toString()工具函數,它能使用類似.NET string.Format()的語法指定日期與數字的格式,省去自行發明格式語法及撰寫轉換邏輯的工夫,省時又方便。
程式的寫法是利用範例12所介紹的自訂繫結技巧,自訂一個"formatText"繫結來取代"text"繫結。在其中使用kendo.toString()將屬性內容轉換成format(data-bind時可額外宣告)所指定的格式字串,再透過$(element).text()修改元素文字內容,只需要短短幾行就搞定囉~
完整程式範例如下: (因為只用到kendo.toString(),所需的Kendo UI程式庫直接取用CDN上kendo.core.min.js即可)
<!DOCTYPE html>
<html>
<head>
<title>Lab 21 - 格式化顯示</title>
<script src="../Scripts/jquery-1.7.2.js"></script>
<script src="../Scripts/knockout-2.1.0.debug.js"></script>
<script src="http://cdn.kendostatic.com/2012.2.913/js/kendo.core.min.js"></script>
<script>
ko.bindingHandlers["formatText"] = {
update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
$(element).text(kendo.toString(
ko.utils.unwrapObservable(valueAccessor()),
allBindingsAccessor().format));
}
};
</script>
<script>
function MyViewModel() {
var self = this;
self.dateTime = ko.observable(new Date());
self.date = ko.observable(new Date(2012, 11, 21));
self.num = ko.observable(1234.567);
self.perc = ko.observable(0.1234);
}
$(function () {
ko.applyBindings(new MyViewModel());
});
</script>
<style>
.hi
{
color: blue;
background-color: #f8c705;
width: 320px;
}
</style>
</head>
<body>
<dl>
<dt>DateTime (raw)</dt>
<dd data-bind="text: dateTime"></dd>
<dt>DateTime HH:mm:ss</dt>
<dd class="hi"
data-bind="formatText: dateTime, format: 'HH:mm:ss'"></dd>
<dt>Date (raw)</dt>
<dd data-bind="text: date"></dd>
<dt>Date yyyy/MM/dd</dt>
<dd class="hi"
data-bind="formatText: date, format: 'yyyy/MM/dd'"></dd>
<dt>Number (raw)</dt>
<dd data-bind="text: num"></dd>
<dt>Number N1</dt>
<dd class="hi"
data-bind="formatText: num, format: 'n1'"></dd>
<dt>Percentage (raw)</dt>
<dd data-bind="text: perc"></dd>
<dt>Percentage p1</dt>
<dd class="hi"
data-bind="formatText: perc, format: 'p1'"></dd>
</dl>
</body>
</html>
[KO系列]
http://www.darkthread.net/kolab/labs/default.aspx?m=post
Comments
# by Mj
請教,為何不用extend做?
# by Jeffrey
to Mj, extend是指用jQuery.extend()在bindingHandlers加入formatText,還是其他方面的應用?
# by mj
透過ko.extenders加載的方式做,感覺比較直覺,也不會跟其他binding互斥。 ko.extenders.formatText = function(target, format){.....}
# by Jeffrey
to mj, extenders的應用主要是透過訂閱target變更事件去觸發特定邏輯,在這個案例中,我想到的做法是增加一個observable()用來儲存格式化後的文字內容,當作需要格式化文字的binding對象(或許還有其他更好做法,請指教)。 但如此設計將會增加額外屬性,在序列化時形成多餘資料。在我的應用中,格式化後的文字多用於靜態文字的呈現(如span, div...),日期、數字等型別需要輸入時會另外binding到Kendo UI的DatePicker等,較無binding相衝的疑慮。而如此規劃,算是依UI需求使用不同binding,ViewModel屬性維持單純的資料型態,因UI而變化的部分盡量放進binding邏輯中,感覺更傾向SoC(關注點分離)。 以上個人淺見。
# by mj
哈,感謝黑暗大大的建議,format確實是view所關心的事情,不應該用extenders去做(= =實做之後發現真個要弄有點複雜,要先把model的值隔離,僅在bind view的時候吐格式化的字串....這樣才不會影響到model取值.....)