Mvvm KnockoutJS-ViewModel抽象
*更新*(见下文) 我了解KnockoutJS的基本知识。创建表视图模型时,可以使用Mvvm KnockoutJS-ViewModel抽象,mvvm,knockout.js,viewmodel,abstraction,Mvvm,Knockout.js,Viewmodel,Abstraction,*更新*(见下文) 我了解KnockoutJS的基本知识。创建表视图模型时,可以使用 现在,我试图抽象表视图模型,以便可以创建具有相同行为(排序、编辑、分页等)的多个表。所以我的目标是这样的: HTML 我的第一次尝试是模仿KnockoutJS文档用于[Paged grid]示例的[simpleGrid]插件(@) 我不是很确定,但我认为抽象的基本概念在这个插件中没有得到很好的体现。当我试图将css类包含到元素中时,比如:,,等等,我发现使用数据绑定属性并不容易(不可能?) 数据绑定属性可能不应
现在,我试图抽象表视图模型,以便可以创建具有相同行为(排序、编辑、分页等)的多个表。所以我的目标是这样的:
HTML
我的第一次尝试是模仿KnockoutJS文档用于[Paged grid]示例的[simpleGrid]插件(@)
我不是很确定,但我认为抽象的基本概念在这个插件中没有得到很好的体现。当我试图将css类包含到
元素中时,比如:
,
,等等,我发现使用数据绑定
属性并不容易(不可能?)
数据绑定
属性可能不应该用于这些东西,因为这些类不会改变——它们是更高抽象级别的一部分:我们应该使用jQuery.tmpl或下划线的模板系统插入这些类。但后来我得到一个错误,说[这个模板系统不支持使用foreach
绑定](或者类似的东西)
因此,我的第二次尝试是按照应该实现的方式实现抽象:表属性(列等)位于表数据之外的另一个“抽象级别”:
html——我只是用下划线的.template做了这个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">
。。。其中?
标记了我的困惑所在
假设我不插入行[A]
和[B]
。当然,KnockoutJS告诉我,我的特定viewmodel(插入到
中)的html中的绑定都是乱七八糟的。如果我插入行[A]
和[B]
,那么它对初始数据有效(在[D]
),但之后就没有响应
总而言之:我对抽象viewmodel这样简单的事情很困惑。在KnockoutJS中是否有一个标准的解决方案?(我在谷歌上搜索过,但找不到任何东西…)或者我只是把它搞砸了(很可能)?;)
*更新*
我解决了这个问题(但可能根本不是最好的/好的-你的意见是什么?),为了完整性:(一个浓缩版本-当然你可能还想单独观察行等等)
HTML(是的,这是特意传递给绑定处理程序的字符串)
咖啡脚本
class主视图模型
构造函数:->
@viewModelPropertyHoldingTableViewModel=新的TableViewModel
无效的
类TableViewModel
构造函数:(选项)->
@columns=options.columns
@rows=ko.observearray(options.rows?[]))
[...]
无效的
tableTemplateMaker=\u0.template'
[%\.map(tableViewModel.columns,函数(列){%]
[%=column.title%]
[% } %]
[%\.map(tableViewModel.columns,函数(列){%]
[% } %]
'
ko.bindingHandlers.myTableBinding=
init:(元素,viewModelPropertyNameAccessor,\ uMainViewModel)->
tableViewModelProperty=viewModelPropertyNameAccessor()
tableViewModel=mainViewModel[tableViewModelProperty]
$(元素).html tableTemplateMaker
tableViewModelProperty:tableViewModelProperty
tableViewModel:tableViewModel
无效的
m=新的主视图模型
ko.applyBindings m
m、 viewModelPropertyHoldingTableViewModel.data.push[…]
为什么要重新发明轮子?:p
为什么要重新发明轮子?:p
你说“之后没有响应”是什么意思?你是在做
var vm=new ViewModel()
和vm.groupTable.data(newData);
?实际上(!)我是在做vm.groupTable.data().push
…但现在我明白这有多愚蠢;)是的,但你实际上可以做vm.groupTable.data.push
。没有()
应该按预期工作。:)simplegrid实现的具体问题是什么?您提到了抽象,但您的实现似乎完全是“抽象的”作为简单的网格。不知道为什么要将viewmodel作为字符串传递,你真的不需要。另外,我建议下次不要在CS中显示代码,因为这会减轻社区的负担,让他们知道一种中间语言来帮助你。你说的“之后不响应”是什么意思你在做var vm=new ViewModel()
和vm.groupTable.data(newData);
?实际上(!)我在做vm.groupTable.data().push
…但现在我明白这有多愚蠢;)是的,但你实际上可以做vm.groupTable.data.push
。如果没有(),
应按预期工作。:)您对simplegrid实现的具体问题是什么?您提到了抽象,但您的实现似乎与简单网格一样“抽象”。不确定为什么要将viewmodel作为字符串传递,实际上不需要这样做。另外,我建议下次不要在CS中显示代码,因为这样可以减轻社区为帮助您而必须了解中间语言的负担。
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]
<div data-bind="myTableBinding: 'viewModelPropertyHoldingTableViewModel'"></div>
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 [...]