Knockout JS - ViewModel抽象

时间:2012-05-04 12:29:03

标签: mvvm knockout.js viewmodel abstraction

*更新* (见下文)

我理解KnockoutJS的基础知识。创建表视图模型时,可以使用<tr data-bind="foreach: rows">

现在我正在尝试抽象表viewmodel,这样我就可以创建具有相同行为的多个表(排序,编辑,分页等)。所以我的目标是这样的:

HTML

<div class="table a" data-bind="myTableBinding: aTableViewModel"></div>
<div class="table b" data-bind="myTableBinding: anotherTableViewmodel"></div>

主要ViewModel

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绑定](或类似的东西)。

我的第二次尝试是实现抽象,因为它应该实现:表属性(列等)在另一个“抽象级别”而不是表数据:

  1. 使用“抽象”模板在实例化新的特定表视图模型时创建基本的<tr data-bind="foreach: rows"> html - 我只是使用了Underscore的_.template。
  2. 让这个特定的视图模型像往常一样使用上面的html。
  3. 在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告诉我绑定都是在我的特定视图模型的html中混乱(插入到<div>。如果我插入行[A][B],那么它适用于初始数据([D]),但之后没有响应。

    总而言之:我对抽象视图模型这样简单的事情感到很困惑。在KnockoutJS中没有一个标准的解决方案吗? (我用Google搜索但却找不到任何东西......)或者我只是把自己弄得一团糟(很可能)? ;)

    * UPDATE *

    我解决了这个问题(但也许它不是最好/最好的 - 你的意见是什么?),为了完整起见:(一个浓缩版本 - 当然你可能也想观察行个别等..)

    HTML (是的,这是故意传递给绑定处理程序的字符串)

    <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 [...]
    

1 个答案:

答案 0 :(得分:0)

为什么重新发明轮子? :P

https://github.com/CogShift/Knockout.Extensions