【问题标题】:KnockoutJS - ViewModel Abstracion淘汰赛 JS - ViewModel 抽象
【发布时间】:2012-05-04 12:29:03
【问题描述】:

*更新*(见下文)

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

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

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 类包含到 &lt;th&gt; 元素中时:&lt;th class="col col-id"&gt;、&lt;th class="col col-name"&gt; 等,我发现使用 data-bind 属性并不容易(不可能?)。

data-bind 属性可能不应该用于这些东西,因为这些类不会改变——它们是更高抽象级别的一部分:我们实际上应该使用 jQuery.tmpl 或 Underscore 的模板插入这些类系统。但后来我收到一条错误消息,说[此模板系统不支持使用foreach 绑定](或类似的东西)。

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

  1. 在新的特定表视图模型的实例化时创建基本的&lt;tr data-bind="foreach: rows"&gt; html,使用“抽象”模板——我只是使用 Underscore 的 _.template 完成的。
  2. 让这个特定的视图模型像往常一样使用上面的 html。

在 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 中都搞砸了(插入到 &lt;div&gt; 中。如果我插入行 [A] 和 [B],那么它确实适用于初始数据([D]),但之后没有回应。

Alltogether:我对抽象视图模型这样简单的事情感到很困惑。在 KnockoutJS 中没有标准的解决方案吗? (我用谷歌搜索但找不到任何东西......)还是我自己搞砸了(很可能)? ;)

*更新*

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

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

【问题讨论】:

  • “之后没有响应”是什么意思?你在做var vm = new ViewModel() 和vm.groupTable.data(newData); 吗?
  • 其实(!)我在做vm.groupTable.data().push...但现在我明白那是多么愚蠢;)
  • 是的,但你实际上可以做到vm.groupTable.data.push。没有() 应该可以按预期工作。 :)
  • 您对 simplegrid 实施的具体问题是什么?您提到了抽象,但您的实现似乎与简单网格一样“抽象”。不知道为什么你将视图模型作为字符串传递,你真的不需要。另外,我建议下次不要在 CS 中显示代码,因为它减轻了社区的负担,必须了解一种中间语言才能帮助你。

标签: mvvm knockout.js viewmodel abstraction


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 2018-08-13
    相关资源
    最近更新 更多