*更新* (见下文)
我了解 KnockoutJS 的基础知识。创建 TableView 模型时,可以使用 <tr data-bind="foreach: rows">
现在我正在尝试抽象 TableView 模型,以便我可以创建具有相同行为(排序、编辑、分页等)的多个表。所以我的目标是这样的:
HTML
<div class="table a" data-bind="myTableBinding: aTableViewModel"></div>
<div class="table b" data-bind="myTableBinding: anotherTableViewmodel"></div>
主视图模型
var MainViewModel = function () {
this.aTableViewModel = new AbstractTableViewModel({
columns: [...]
initialSort: [...]
});
this.anotherTableViewModel = new AbstractTableViewModel({
columns: [...]
initialSort: [...]
});
};
我的第一次尝试是模仿 KnockoutJS 文档用于 [Paged grid] 示例的示例 [simpleGrid] 插件 (@ http://knockoutjs.com/examples/resources/knockout.simpleGrid.1.3.js )。
我不太确定,但我认为抽象的基本概念在这个插件中没有得到很好的体现。当我试图将 css 类包含到
<th>
中时像这样的元素:<th class="col col-id">
, <th class="col col-name">
等,我发现使用 data-bind
这并不容易(不可能?)属性。data-bind
属性可能不应该用于这些东西,因为这些类不会改变——它们是更高抽象级别的一部分:我们实际上应该使用 jQuery.tmpl 或 Underscore 的模板系统插入这些类。但后来我收到一条错误消息,说 [此模板系统不支持使用 foreach
绑定(bind)](或类似的东西)。因此,我的第二次尝试是实现抽象,因为它应该被实现:表属性(列等)在另一个“抽象级别”而不是表数据:
<tr data-bind="foreach: rows">
html 在新的特定 TableView 模型的实例化中,使用“抽象”模板——我只是用 Underscore 的 _.template 做的。 在 CoffeeScript 中:
do ->
ko.dataTable =
ViewModel: (config) ->
@id = config.id
@columns = config.columns
@pageSize = config.pageSize ? 9999
@sortColumn = ko.observable (config.sortColumn ? @columns[0].col)
@sortOrder = ko.observable (config.sortOrder ? "asc")
@data = ko.observableArray (config.data ? [])
null
ko.bindingHandlers.dataTable =
init: (el, acc) ->
viewModel = acc()
$(el).find("div:first").html dataTableTemplateMaker viewModel
# ??? [A] ko.applyBindings viewModel, $(el).find("table")[0]
# ??? [B] controlsDescendantBindings: yes
null
update: (el, acc) ->
viewModel = acc()
# ??? [C]
null
进而:
<div data-bind="dataTable: groupTable">
和:
class ViewModel
constructor: ->
@groupTable = new ko.dataTable.ViewModel
id: "grouptable"
columns: [
{ col: "num", title: "Groep", editable: yes }
{ col: "subject", title: "Vak" }
{ col: "year", title: "Jaar" }
{ col: "level", title: "Niveau" }
{ col: "day", title: "Dag" }
{ col: "hour", title: "Uur" }
{ col: "place", title: "Lokaal", editable: yes }
]
pageSize: 10
sortColumn: "num"
sortOrder: "asc"
data: [] # [D]
...其中
???
标记我的困惑所在的位置。假设我不插入行
[A]
和 [B]
.然后当然 KnockoutJS 告诉我绑定(bind)在我的特定 View 模型的 html 中都搞砸了(插入到 <div>
中。如果我插入行 [A]
和 [B]
,那么它确实适用于初始数据(在 [D]
),但之后没有响应。总而言之:我对抽象 View 模型这样简单的事情感到很困惑。在 KnockoutJS 中没有标准的解决方案吗? (我用谷歌搜索但找不到任何东西......)还是我自己搞砸了(很可能)? ;)
*更新*
我解决了这个问题(但也许它根本不是最好的/很好 - 你的意见是什么?),为了完整起见:(一个浓缩版本 - 当然你可能还想单独观察行等。 .)
HTML(是的,这是故意传递给绑定(bind)处理程序的字符串)
<div data-bind="myTableBinding: 'viewModelPropertyHoldingTableViewModel'"></div>
CoffeeScript
class MainViewModel
constructor: ->
@viewModelPropertyHoldingTableViewModel = new TableViewModel <options>
null
class TableViewModel
constructor: (options) ->
@columns = options.columns
@rows = ko.observableArray (options.rows ? [])
[...]
null
tableTemplateMaker = _.template '
<table>
<thead>
<tr>
[% _.map(tableViewModel.columns, function (column) { %]
<th>[%= column.title %]</th>
[% } %]
</tr>
</thead>
<tbody data-bind="foreach: rows">
<tr>
[% _.map(tableViewModel.columns, function (column) { %]
<td data-bind="text: [%= column.id %]"></td>
[% } %]
</tr>
</tbody>
</table>
'
ko.bindingHandlers.myTableBinding =
init: (element, viewModelPropertyNameAccessor, _, mainViewModel) ->
tableViewModelProperty = viewModelPropertyNameAccessor()
tableViewModel = mainViewModel[tableViewModelProperty]
$(element).html tableTemplateMaker
tableViewModelProperty: tableViewModelProperty
tableViewModel: tableViewModel
null
m = new MainViewModel
ko.applyBindings m
m.viewModelPropertyHoldingTableViewModel.data.push [...]
最佳答案
为什么要重新发明轮子? :P
https://github.com/CogShift/Knockout.Extensions
关于mvvm - knockout JS - ViewModel 抽象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10448807/